学习如何在自定义数据集上从头开始微调BERT
在这篇文章中,我们将使用PyTorch处理用于情感分类的BERT的微调问题。BERT是一个大型的语言模型,在流行和模型大小之间提供了一个很好的平衡,可以使用一个简单的GPU进行微调。我们可以从Hugging Face(HF)下载一个预训练的BERT,所以不需要从头开始训练它。特别是,我们将使用BERT的提炼(小型)版本,称为Distil-BERT。
Distil-BERT在生产中被广泛使用,因为它的参数比BERT的无外壳少40%。它的运行速度快60%,在GLUE语言理解基准中保持了95%的性能。
我们首先安装所有必要的库。第一行是捕捉安装的输出,保持你的笔记本干净。
我将使用Deepnote来运行本文中的代码,但如果你愿意,你也可以使用谷歌Colab。
你也可以用下面这行代码来检查你所使用的库的版本。
现在你需要指定一些一般的设置,包括历时的数量和设备硬件。我们设置了一个固定的随机种子,这有助于实验的可重复性。
加载IMDb电影评论数据集
让我们看看如何准备和标记IMDb电影评论数据集并微调Distilled BERT。获取压缩的数据并解压。
像往常一样,我们需要将数据分成训练、验证和测试集。
对数据集进行标记
让我们使用从预训练模型类继承的标记器实现将文本标记为单个单词标记。
标记化在自然语言处理中被用来将段落和句子分割成更小的单元,可以更容易地分配意义。
使用Hugging Face,您将始终发现一个与每个模型相关的标记器。如果你不是在做标记器的研究或实验,最好总是使用标准的标记器。
填充是一种策略,通过向较短的句子添加一个特殊的填充标记来确保张力器是矩形的。另一方面,有时一个序列可能太长,模型无法处理。在这种情况下,你需要把序列截断成一个较短的长度。
让我们把一切都打包到一个Python类中,我们将其命名为IMDbDataset。我们还将使用这个自定义数据集来创建相应的数据转换器。
encodings变量存储了很多关于标记化文本的信息。我们可以通过字典的理解只提取最相关的信息。字典中包含:
- input_ids:是句子中每个标记所对应的索引。
- labels:类标签
- attention_mask:表示一个标记是否应该被关注(例如,填充的标记不会被关注)。
让我们来构建数据集和相应的数据加载器。
加载和微调BERT
最后,我们完成了数据预处理,我们可以开始微调我们的模型。让我们定义一个模型和一个优化算法,在这种情况下,亚当。
DistilbertForSequenceCLassification指定了我们要对模型进行微调的下游任务,在本例中就是序列分类。注意,"无大小写 "意味着模型不区分大写和小写字母。
在训练模型之前,我们需要定义一些指标来比较模型的改进。在这个简单的案例中,我们可以使用传统的分类准确率。请注意,这个函数相当长,因为我们正在逐批加载数据集,以解决RAM和GPU的限制。通常,在对巨大的数据集进行微调时,这些资源是永远不够的。
在compute_accuracy函数中,我们加载一个给定的批次,然后从输出中获取预测的标签。在这样做的时候,我们通过变量num_examples来跟踪例子的总数。以同样的方式,我们通过correct_pred变量跟踪正确预测的数量。在我们对完整的数据加载器进行迭代之后,我们可以通过最后的除法来计算准确性。
你也可以注意到如何在compute_accuracy函数中使用该模型。我们给模型输入输入值以及表示一个标记是实际文本标记还是填充物的attention_mask信息。该模型返回一个SequenceClassificatierOutput对象,我们从中获得对数,并使用argmax函数将其转换成一个类别。
训练(微调)循环
如果你知道如何在PyTorch中对训练循环进行编码,那么你对这个微调循环的理解就不会有任何问题。就像任何神经网络一样,我们给网络提供输入,计算输出,计算损失,并根据这个损失进行参数更新。
每隔几个 epochs,我们就会打印训练进度以获得反馈。
最后的思考
在这篇文章中,我们已经看到了如何通过完全使用PyTorch对大型语言模型(如BERT)进行微调。实际上,还有一种更快、更聪明的方法,那就是使用Hugging Face公司的Transformers库来做这件事。这个库允许我们创建一个用于微调的Trainer对象,在那里我们只需几行代码就可以指定参数,如历时的数量等。如果你想在下一篇文章中看到如何做到这一点,请关注我!😉