使用 PyTorch 2.0 构建 Transformer 模型——Hugging Face生态系统

157 阅读15分钟

介绍
在本章中,我们将深入探讨Hugging Face生态系统的世界,这一平台是机器学习领域的先锋,为最先进的ML模型提供支持。Hugging Face已经成为实践者和研究人员的首选资源,提供了易于使用的库、前沿的ML模型、便捷的模型分享平台以及强大的社区支持。重要的是,Hugging Face提供了多个框架(如TensorFlow、PyTorch等)的库支持。然而,几乎所有的功能都优先支持PyTorch。本章通过全面的分析,旨在帮助读者深入理解Hugging Face生态系统及其各个组成部分,并展示如何利用其功能构建基于PyTorch的Transformer模型。

章节结构

本章包含以下内容:

  • 系统资源
  • Hugging Face概述及其组成
  • 数据集
  • 模型
  • 在Hugging Face上分享你的模型
  • 空间(Spaces)

目标

本章的目标是深入理解Hugging Face生态系统的核心功能和特性,特别是聚焦于transformers、datasets和tokenizers库。你将通过实际的示例学习这些库的使用。本章还将引导你完成开源模型的训练和微调过程,帮助你了解如何在Hugging Face平台上分享你的微调模型。此外,本章将详细介绍如何微调基于stable-diffusion的Dreambooth模型,并通过实际操作展示如何有效地在Hugging Face上分享该模型。通过这一学习过程,你将掌握利用这些先进工具进行项目开发的技能和知识。

系统资源

有关环境设置的详细说明,请参考以下链接:
环境设置说明

激活虚拟环境:

conda activate transformer_learn

为了继续进行本章中的编程任务,请安装以下必要的包:

pip3 install transformers  
pip3 install datasets  
pip3 install git+https://github.com/huggingface/diffusers  
pip3 install accelerate  
pip3 install ftfy  
pip3 install tensorboard  
pip3 install Jinja2

Hugging Face概述

Hugging Face生态系统(huggingface.co/)是一个全面的资源和工具套件,支持最先进深度学习模型的开发、实现和部署。它成立于2016年,旨在通过提供易于使用的工具,帮助更广泛的社区实现人工智能的民主化。具体来说,Hugging Face以其开源的transformer库而闻名,该库已经成为BERT、GPT等基于Transformer的模型的事实标准包。此外,HuggingFace.co还是一个充满活力的社区,社区已经上传了超过15万个模型。

图2.1展示了Hugging Face的用户界面。该界面提供了适用于广泛机器学习任务的数据集和模型,包括多模态、计算机视觉、音频、表格数据和强化学习等领域。此外,界面还允许用户更深入地探索特定子领域。

image.png

Hugging Face的关键组件

Hugging Face生态系统由六个主要组件组成,共同构建了一个全面的机器学习平台。表2.1展示了Hugging Face生态系统的关键元素:

序号名称描述
1Transformer库一个开源库,提供广泛的预训练模型(超过190个)。
2数据集库拥有超过24,000个可直接使用的机器学习数据集。
3Tokenizer库灵活的库,处理NLP文本数据的预处理和分词。
4ML集成支持与多个框架的集成(如PyTorch、TensorFlow和JAX/Flax)。所有模型都支持PyTorch,其他框架则有限支持。
5推理API使用户可以通过几行代码从Hugging Face部署模型。总体而言,支持小到大规模项目的生产就绪模型部署。
6Hugging Face Spaces用户可以在一个用户友好的环境中构建Web应用程序、托管演示并与社区协作。

表2.1:Hugging Face的关键组件

接下来,让我们深入了解这些主要组件。


Tokenizers(分词器)

分词器将原始文本转换为小单位(字符、单词、子词),这些单位是NLP处理的基本单元。表2.2展示了分词的主要示例。Hugging Face Tokenizer提供了多个预训练的分词算法,并提供了训练自定义分词器算法的机制。

分词示例

分词级别示例
字符级别['T', 'h', 'e', ' ', 't', 'o', 'k', 'e', 'n', 'i', 'z', 'e', 'r', 's']
单词级别['The', 'Tokenizers']
子词级别['the', 'token', '##izer', '##s']

表2.2:分词过程

创建自定义分词器

在某些情况下,如在处理医疗等特定领域的专业术语时,您可能需要开发一个自定义分词器。本节将指导您如何创建一个量身定制的分词器,以满足您的特定需求。

训练

以下代码演示了如何:

  1. 使用您的数据集训练一个分词器;
  2. 将训练好的分词器保存为JSON文件;
  3. 使用训练好的分词器进行推理。

请根据您的文件路径修改第4行,提供您计算机上文本文件的路径。附带的文档包含tokenizer_train.txt文件;不过,您也可以根据自己的使用案例,使用任何文本训练分词器。此外,修改第13行,提供您机器的路径:

from tokenizers import Tokenizer, models, pre_tokenizers, trainers

'''训练'''
# 从文件中读取数据集。txt文件可以在本书的GitHub仓库中找到
with open("/Users/premtimsina/Documents/bpbbook/chapter2_huggingFace/datasets/tokenizer_train.txt", "r") as file:
    dataset = [line.strip() for line in file.readlines()]

# 初始化BPE分词器。Byte Pair Encoding (BPE) 是一种子词分词技术。
tokenizer = Tokenizer(models.BPE())

# 设置预处理器以将输入拆分为单词
tokenizer.pre_tokenizer = pre_tokenizers.Whitespace()

# 在数据集上训练BPE分词器
trainer = trainers.BpeTrainer(special_tokens=["[UNK]", "[CLS]", "[SEP]", "[PAD]", "[MASK]"])
tokenizer.train_from_iterator(dataset, trainer=trainer)

# 保存训练好的分词器
tokenizer.save("/Users/premtimsina/Documents/bpbbook/chapter2_huggingFace/model/tokenizer.json")

推理

现在,让我们使用我们定制的分词器来进行推理。在以下代码中,PreTrainedTokenizerFast 提供了加载预训练分词器的机制:

'''推理'''
from transformers import PreTrainedTokenizerFast

# 加载训练好的分词器
fast_tokenizer = PreTrainedTokenizerFast(tokenizer_file="/Users/premtimsina/Documents/bpbbook/chapter2_huggingFace/model/tokenizer.json")

# 输入文本
text = "The Tokenizers"

# 使用分词器对文本进行编码
encoded = tokenizer.encode(text)

# 打印分词后的文本
print(encoded.tokens)

输出:

['T', 'h', 'e', 'T', 'o', 'ken', 'iz', 'ers']

可视化:

from tokenizers.tools import EncodingVisualizer

# 可视化分词过程
visualizer = EncodingVisualizer(fast_tokenizer._tokenizer)
visualizer(text="The Tokenizers")

输出:
图2.2展示了短语 "The Tokenizers" 的分词输出。我们可以看到,分词过程将文本分为8个token,如下所示:

image.png

使用Hugging Face的预训练分词器

在以下代码中,我们使用了预训练的分词器 bert-base-uncased。对于一般的语言处理任务,预训练分词器通常比自定义分词器更有效:

from transformers import BertTokenizer

# 加载预训练的BERT分词器
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")

# 对文本进行分词
print(tokenizer.tokenize("The tokenizers"))

输出:

['the', 'token', '##izer', '##s']

当我们将自定义分词器的分词结果(['T', 'h', 'e', 'T', 'o', 'ken', 'iz', 'ers'])与预训练的 BertTokenizer 的分词结果(['the', 'token', '##izer', '##s'])进行比较时,可以明显看出,BertTokenizer 的效果要好得多。这是因为我们仅用几行代码训练了自定义分词器。要生产一个最佳的分词器,必须提供足够的训练数据。然而,当我们在需要大量领域特定词汇的专业领域工作时,创建自定义分词器仍然非常有用。

数据集 (Datasets)

Datasets 是一个强大的库,它简化了机器学习中数据集的下载、预处理和管理过程。以下是 Datasets 库的一些显著特点:

  • 预加载数据集:它提供了大量的数据集,覆盖多个机器学习任务领域,包括计算机视觉、音频处理、自然语言处理 (NLP)、强化学习等。
  • 高效的数据处理与易用性:该库底层使用了 Apache Arrow(一种列式内存数据格式),能够高效地处理和存储数据。此外,它还支持数据版本控制(有助于可复现性),并提供了一个用户界面,帮助快速查看数据集。
  • 与 Hugging Face Transformer 和 PyTorch 的集成Datasets 库与 Hugging Face 的 Transformer 库兼容,并且可以无缝集成到 PyTorch 框架中。

使用 Hugging Face 数据集

准备数据:在以下示例中,我们下载了 IMDb 数据集并打印了其中的一行数据。正如你在第3行看到的,只需要一行代码就能下载数据集:

from datasets import load_dataset

# 加载 IMDb 电影评论数据集
imdb_dataset = load_dataset("imdb")

# 加载预训练模型和分词器
# 从数据集中选择一条示例文本
sample_text = imdb_dataset["test"][0]["text"]
print(sample_text)

输出:

I love sci-fi and am willing to put up with a lot. Sci-fi movies/TV are usually underfunded…..

使用 IMDb 数据集进行情感分析,我们将使用 IMDb 数据集进行情感分析:

from transformers import AutoModelForSequenceClassification, pipeline
from transformers import AutoTokenizer

model_name = "distilbert-base-uncased-finetuned-sst-2-english"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name)

# 创建情感分析流水线
sentiment_analysis_pipeline = pipeline("sentiment-analysis", model=model, tokenizer=tokenizer)

# 从数据集中选择一条示例文本
sample_text = imdb_dataset["test"][0]["text"]

# 对示例文本进行情感分析
result = sentiment_analysis_pipeline(sample_text)

# 打印结果
print("Sample Text:", sample_text)
print("Sentiment Analysis Result:", result)

输出:

Sentiment Analysis Result: [{'label': 'NEGATIVE', 'score': 0.999616265296936}]

分析: 这是一个令人兴奋的发展!仅用不到20行代码,我们就能完成端到端的情感分析。你可以根据自己的具体需求定制上述代码。在这段代码中,我们使用了预训练模型 distilbert-base-uncased-finetuned-sst-2-english,该模型用于分词和推理。这个模型使用了不区分大小写的英语词汇,并且在斯坦福情感树库 (SST-2) 数据集上进行了情感分析任务的微调。需要特别注意的是,在进行推理时,建议使用与模型相同的模型进行分词。

在 PyTorch 中使用 Hugging Face 数据集

直接将 Hugging Face 数据集传递给 DataLoader:在以下代码中,我们使用 torch 格式加载数据集。这将把数据转换为 PyTorch 的 Tensor 格式:

from datasets import load_dataset
from torch.utils.data import DataLoader, Dataset
import torch

# 加载 Hugging Face 数据集(以 IMDb 电影评论数据集为例)
imdb_dataset = load_dataset("imdb").with_format("torch")

查看加载的数据集:我们可以使用 DatasetInfo 查看数据集的信息:

from datasets import DatasetInfo
print(DatasetInfo(imdb_dataset))

输出:

DatasetInfo(description=DatasetDict({
    train: Dataset({
        features: ['text', 'label'],
        num_rows: 25000
    })
    test: Dataset({
        features: ['text', 'label'],
        num_rows: 25000
    })
    unsupervised: Dataset({
        features: ['text', 'label'],
        num_rows: 50000
    })) 

分析imdb_dataset 包含 traintestunsupervised 三个部分。此外,每一行都包含 textlabel 两个部分。接下来,让我们创建 DataLoader

from torch.utils.data import DataLoader, Dataset

train_loader = DataLoader(imdb_dataset['train'], batch_size=8, shuffle=True)
test_loader = DataLoader(imdb_dataset['test'], batch_size=8, shuffle=False)

附带的 Notebook 文件中包含了我们创建 CustomDataset 类的实现方法。

模型

在 Hugging Face 上,有超过 150,000 个模型可用于各种机器学习任务。在之前的示例中,我们讨论了如何使用预训练的 Transformer 模型对 IMDb 数据集进行情感分析。

本节将重点讨论基于稳定扩散(stable diffusion)的 Dreambooth 实现的微调。Dreambooth 是一个文本到图像的扩散模型,它根据提供的文本输入生成图像。通常,文本到图像的模型可以根据提示生成图像,例如“一个人在攀登珠穆朗玛峰”。然而,如果你希望模型生成一幅你攀登珠穆朗玛峰的图像,可以使用 Dreambooth 微调模型,只需要几张你的图片。一旦模型微调完成,它就能够生成任何包含你进行某项活动的图像。这使得 Dreambooth 成为一种有效的以主题为驱动的图像生成工具。

环境设置

请激活你的 Conda 环境,并在终端中输入以下命令。根据提示输入必要的参数。

accelerate config

accelerate config 命令通常用于设置 Accelerate 库的默认参数,例如精度模式(例如混合精度或全精度)、梯度累积设置以及其他相关参数。在执行任何 PyTorch 脚本代码之前,必须先运行此命令,以确保 Accelerate 库正确配置。

训练

确保从 GitHub 下载 train_dreambooth.py 并将其保存在计算机上。你可以通过以下链接获取该文件:GitHub - Dreambooth Example

请在终端中运行以下命令,这将开始训练 Dreambooth 模型:

export MODEL_NAME="CompVis/stable-diffusion-v1-4"
export INSTANCE_DIR="/Users/premtimsina/Documents/bpbbook/chapter2_huggingFace/datasets/dreambooth/photo"
export OUTPUT_DIR="/Users/premtimsina/Documents/bpbbook/chapter2_huggingFace/datasets/dreambooth/model"

accelerate launch train_dreambooth.py \
  --pretrained_model_name_or_path=$MODEL_NAME  \
  --instance_data_dir=$INSTANCE_DIR \
  --output_dir=$OUTPUT_DIR \
  --instance_prompt="a photo of sks boy" \
  --resolution=512 \
  --train_batch_size=1 \
  --gradient_accumulation_steps=1 \
  --learning_rate=5e-6 \
  --lr_scheduler="constant" \
  --lr_warmup_steps=0 \
  --max_train_steps=1000

为了更好地理解上面提到的参数,我们将详细探讨它们的含义。

参数说明

  1. MODEL_NAME:指定基础模型的名称。在这个例子中,我们使用的是稳定扩散模型(stable-diffusion-v1-4)。
  2. INSTANCE_DIR:指定用于微调模型的照片位置。我们建议使用 5-10 张 PNG 格式的图片。我在微调中使用了这三张照片。你可以使用任何主题的照片,包括猫、花朵、你自己等。然而,带有清晰面部和透明背景的照片效果较好。

通过微调模型,我们可以使其生成符合我们需求的图像,尤其是在特定领域或自定义任务中。

image.png

第三个变量是 OUTPUT_DIR,它指定了微调模型将被保存的目录。在运行代码之前,请确保该目录为空。

instance_prompt 参数是一个关键标识符,在推理过程中是必需的。在提供的代码中,instance_prompt 被设置为“a photo of sks boy”。请确保为训练过程提供适当的标识符,因为在推理时它将用于准确的图像生成。

模型的总训练时间可能会根据你的计算机规格和加速配置有所不同。通常,整个训练过程需要 30 分钟到 1 小时。以我为例,我在配备 M2 Max 处理器和 32GB RAM 的 Mac 上进行训练,整个过程花费了 45 分钟。

推理

你已经成功创建了 Dreambooth 模型。接下来,让我们使用该模型,通过提供不同的提示词来生成图像:

from diffusers import StableDiffusionPipeline
import torch

model_id = "/Users/premtimsina/Documents/bpbbook/chapter2_huggingFace/datasets/dreambooth/model/"
pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16).to("mps")

prompt = "a photo of sks boy riding horse"
image = pipe(prompt, num_inference_steps=500, guidance_scale=7.5).images[0]
image.save("/Users/premtimsina/Documents/bpbbook/chapter2_huggingFace/datasets/dreambooth/photo/boy_ridding_horse.png")

解释

  • 在代码的第 4 行,我们将张量转换为 mps 格式,这是因为在 Mac 系统上运行代码时需要此格式。然而,如果你是在 GPU 上运行代码,应该将张量转换为 cuda 格式。
  • 确保张量的格式正确非常重要,否则在执行代码时可能会出现错误。如果遇到问题,请仔细检查张量的格式,并根据需要做出调整。
  • 此外,请注意,在第 6 行,提示词以“a photo of sks boy”开头。我们在训练过程中为此提供了这个标识符,在推理过程中,你的标识符应该始终以此为开头。

图 2.4 展示了由自定义 DreamBooth 模型生成的图像。我们的模型生成的图像看起来相当不错,面部特征似乎匹配。如果你想生成高质量的图像,可以通过实验和优化训练参数来实现。

以下是推理生成的一些图像示例:

image.png

这太棒了!只需几行代码,我们就能创建一个根据指定主题生成图像的文本到图像生成器。

在 Hugging Face 上分享你的模型

在这一部分,我们将介绍如何将你的模型分享到 Hugging Face,并通过 Gradle 创建一个空间。关于这一过程的详细说明可以在随附的笔记本中找到。模型成功共享后,它将在你的 Hugging Face 账户中显示如下。

模型

下图展示了 Huggingface.co 上的 dreambooth_boy 模型,您可以在其中输入一个提示词,并根据所给的提示词生成相应的图像,如图所示:

image.png

Spaces

以下截图展示了我们的 Dreambooth-boy 模型对应的 Space。Hugging Face Spaces 提供了一种简便的方法来开发基于您模型的应用程序。具体来说,您可以执行以下任务:

  • 部署您的模型
  • 托管 Jupyter notebooks
  • 使用 Gradio 设计用户友好的界面
  • 使用 Streamlit 创建交互式 Web 应用程序
  • 与协作者共享您的 Space,让多人共同开发同一个应用

image.png

总结

在本章中,我们详细探讨了 Hugging Face 生态系统,这一在机器学习领域具有重要地位的工具。我们重点介绍了其核心组件——Transformers、Datasets 和 Tokenizers 库,并展示了如何在实际场景中应用这些工具。我们还学习了如何为特定任务微调模型,并将其分享到 Hugging Face 平台,使其能够为他人所用。通过这段学习旅程,我们对如何在各种项目中使用这些先进技术有了实践性的理解,特别是如何将 Dreambooth 模型调整为个性化的用途。

Hugging Face 生态系统作为一个多功能、全面的资源,在 AI 领域,尤其是在 Transformer 基础模型方面,具有突出的优势。它提供了多种功能,从创建自定义 Tokenizer 到利用预训练模型。通过探索其能力,我们为您提供了知识和技能,使您能够充分利用 Hugging Face 的创新工具,拓展机器学习的广阔可能性。通过本章内容,您已经为深入 AI 世界做好了准备,并将 Hugging Face 生态系统作为未来项目的坚实基础。