抱脸社区:Transformers,启动
Transformers,启动
Huggingface 在 2023 年大放异彩,成为 AI 领域最活跃的开源网站,前途不可限量。
书写前言
工欲善其事,必先利其器。
现如今,Transformers 已经被封装成一个独立的包,由 Huggingface 以社区的形式维护。
学习 Transformers 十分重要!作为在各个领域霸榜的存在,任何与 AI 打交道的人都不可能绕开它。
被封装好的 Transformers 十分便利!三行训练一个模型!随时随地导出!在多个框架间共享!
Hugginface 覆盖了绝大多数的 Transformers 的衍生模型,并维护了一个良好的开发生态 Hub。
最重要的是,Hugginface 提供了一个简明易懂的官方文档。
安装方法
一切神话,始于安装。像安装普通的包那样安装 Transformer 即可。
通常来说,需要搭配某个深度学习框架,比如 Pytorch。
当然,良好的包管理方式是先创建一个虚拟环境。
通常我们把它放在项目目录下的 .env 隐藏文件,并用 .gitignore 将其忽略。
1 |
|
之后在该虚拟环境中根据我们的需求安装。
1 |
|
本地设置
从远程实时下载模型是一个很美妙的想法,但因为诸如 GFW 等的原因,它并不总能实现。
更常见的情况下,我们需要缓存设置和离线模式。
缓存设置
预训练模型下载后通常被放到了 ~/.cache/huggingface/hub 下。
这个文件夹是默认的,除非环境变量 TRANSFORMERS_CACHE 被指定。
自然地,我们想到需要修改 shell 的环境变量:
- HUGGINGFACE_HUB or TRANSFORMERS_CACHE
- HF_HOME
- XDG_CACHE_HOME + /huggingface
Transformers 会按照优先级选择将模型下载到什么地方。
由于我们使用虚拟环境下安装,推荐的做法是将环境变量的指定添加到 activate 文件中。
1 |
|
以上命令需要在虚拟环境下执行。
离线模式
作为 GFW 内的子民,我们更多的想要使用离线模式。
其实离线模式就是将模型下载到本地缓存起来,然后调用。
需要指定环境变量 TRANSFORMERS_OFFLINE = 1 以开启。
1 |
|
这样一来它将不会试图从 Hub 下载文件,相应的,你需要在本地准备模型文件。
所有文件都可以从 Hub 下载,它们是有人维护的。
下载文件
要从 Hub 上逐一下载模型文件是愚蠢的。
优雅的方式是借助第三方工具 git 来下载。
但模型文件一般很大,而 git 保存 diff 的方式会使得仓库动辄几百 G。
因此,我们需要先安装 LFS 工具,它是与 git 集成的。
关于 git-lfs 的安装与配置,请查看 GitHub 的官方文档。
不过部分 Linux 发行版具有更加简单、安全的安装方式。
1 |
|
使用 git-lfs 的好处就是可以不用把所有大模型文件都下载下来,而只需要根据需要 pull 即可。
这里以 BERT 为例,首先可以把所有的小文件都下载下来。
1 |
|
我们会发现所有标有 LFS 的大文件都被存储成了指针文件。
快速开始
Pipeline 函数
流程函数 Pipeline() 是官方提供的一个懒人函数,可以使用最简单、最便利的方法迅速调用一个模型到指定任务。
比如,我想进行一次简单的情感分析任务。
1 |
|
1 |
|
当然,Pipeline() 还可以指定模型、数据集和 Tokenizer,具体可以查看官方文档。
AutoClasss 类
事实上,Pipeline() 是对 AutoClass 中各个组件即部分功能的集成。
而 AutoClass 是 transformers 的基本类,包括 Tokenizer 类, Model 类和 Configuration 类。
所有相关的类都衍生自这 3 个类,它们都有 save_pretrained() 和 from_pretrained() 方法。
Tokenizer 类
分词器 Tokenizer 用于将文本处理成一列数字作为模型输入。
Tokenization 的过程须遵循一定规则,具体参见官方总结。
Tokenizer 须保持和模型一致。譬如,BERT 就需要使用 BERT 的 Tokenzier。
1 |
|
1 |
|
按照约定,Tokenizer 返回一个包含如下字段的字典:
- input_ids: token 的数字表示。
- token_type_ids: token 属于句子 A 还是句子 B
- attention_mask: 表示哪一个 token 需要被注意。
Tokenzier 能够接受一个 list 并返回一个 batch,只需指定是否填充和截断。
1 |
|
Model 类
下载 AutoModel 和下载 Tokenizer 一样简单,只是你需要根据任务需求选择合适的模型。
譬如,对于文本分类任务,你需要下载 AutoModelForSequenceClassification。
1 |
|
你可以将 batch 直接输入模型,只需为 dictionary 加上 ** 的修饰符。
1 |
|
模型输出了最后的激活值,只需再套一个 softmax 就能做分类。
1 |
|
1 |
|
Configuration 类
模型的设置是可以被修改的,包括一些超参数。
这是因为当你从一个 Config 类初始化模型时,它是从头开始的。
你只需引入 AutoConfig 类并调用 from_pretrained() 函数。
1 |
|
然后将其通过 from_config() 函数调用。
1 |
|
Save/From 函数
模型训练完后,通过调用 tokenizer 的 save_pretrained() 函数即可保存。
1 |
|
如需复用模型,通过 from_pretrained() 函数即可。这也是从远程下载模型的函数。
1 |
|
项目实例
在这里以语义相似度分析为例,做一个简单的模型搭建与训练案例,预训练模型选用 BERT。
加载数据
数据集选用的是 STSBenchmark,是经典的语义相似度数据集,可以在此处获取。
STSBenchmark 以 CSV 个格式存储。其中,第 4 列是两个语句的相似度,为从 0 到 5 的浮点数。第 5 列和第 6 列是两个英文语句。
1 |
|
Dataset
Pytorch 通过 Dataset 类和 DataLoader 类处理数据集和加载样本。同样地,这里我们首先继承 Dataset 类构造自定义数据集,以组织样本和标签。
1 |
|
1 |
|
可以看到,我们编写的 STS 类成功读取了数据集。
每个样本以字典的形式保存,分别以 score, sent1, sent2 为键存储相似度和句子对。
DataLoader
我们需要 DataLoader 按 batch 加载数据,并将样本转换为模型可以接受的输入格式。
对于 NLP 任务,这个环节就是将每个 batch 中的文本按照预训练模型的格式进行编码,并进行填充和截断操作。
1 |
|
1 |
|
DataLoader 按照我们设置的 batch size 每次对 4 个样本进行编码。
并且通过填充和截断的操作使得每个样本的长度相同,填充位置 0 并且相应的 attention_mask 置 0。
这里我们选择的是 BERT 的编码器,因此每个样本都被处理成了”[CLS] sent1 [SEP] sent2 [SEP]” 的形式。
[CLS] 对应的 input_ids 是 101, 而 [SEP] 对应的 input_ids 是 102。
构建模型
这里实现了一个极其简单的模型,他只在预训练的 BRET 上添加了一个全连接层。
1 |
|
BERT 首先会将输入编码为 768 维的向量,之后利用一层全连接将 768 维映射成一个实数来进行回归。
注意,此时我们的模型是 Transformers 预训练模型的子类,因此需要通过预置的 from_pretrained 函数来加载模型参数。
这种方式使得我们可以更灵活地操作模型细节,例如这里 Dropout 层就可以直接加载 BERT 模型自带的参数值。
为了确保模型的输出符合我们的预期,我们尝试将一个 Batch 的数据送入模型。
1 |
|
1 |
|
模型输出了 4X1 的向量,其中 4 是 batch 的大小,1 是输出的维度,符合我们的预期。
训练模型
训练组件
总的来说,训练模型需要 loss_fn(损失函数)、optimizer(优化器)、lr_scheduler(学习率调整器)。
其中,损失函数用于计算梯度,优化器用于平滑梯度,学习率调整器用于在训练过程中调整学习率。
1 |
|
在这里,损失函数使用了 torch.nn 提供的均方误差 MSE。
优化器选用了 AdamW 并指定了学习率为 learning_rate(取 1e-5)。
lr_scheduler 制定了学习率分 epoch_num * len(train_loader) 步进行下降。
训练循环
之后定义训练循环,通过调用上述的 3 个组件来优化模型的参数。
同时借助 tqdm 做了一个进度条来实现训练过程的可视化。
1 |
|
在训练模型时,我们将每一轮 Epoch 分为训练循环和验证/测试循环。
在训练循环中计算损失、优化模型的参数,在验证/测试循环中评估模型的性能
最后,将”训练循环”和”验证/测试循环”组合成 Epoch,就可以进行模型的训练和验证了。
1 |
|
完整的训练过程应当如下。
1 |
|
大功告成!你已经成功构建并训练了一个语言模型。