友情提示:由于HuggingFace社区触犯了天朝的某些法律,有关HuggingFace系列的内容中,提到“冲浪板”就指科学上网,需要借助国外旅游工具。
任务简介
情感分类问题属于是自然语言处理中的”Hello World”,目的就是对一段话的情感进行分类。最简单的就是二分类,包含了积极和消极两种情感。
数据集
在本次任务中使用的数据集为ChnSentiCorp数据集。数据集包含了9600条训练集、1200条测试集、1200条验证集。每条数据包含了两个属性,分别是text和label。其中text是一段中文文本,代表一段评价,label是0或1的数字标签,分别代表了消极和积极。
那么,该怎样获取这个数据集呢?
正常来讲,我们只需要这样一段代码,就可以直接从HuggingFace上获取数据集。
1 | from datasets import load_dataset |
但是!这个数据集被放在了谷歌云上,我们没法直接获取,即便有冲浪板也不好用。不过不用担心,我们可以站在巨人的肩膀上看世界。
开始实战
加载编码工具
注意,第一次使用需要冲浪板。
1 | from transformers import BertTokenizer |
加载和观察数据集
1 | from datasets import load_from_disk |
1 | DatasetDict({ |
我们在后面要使用Pytorch的工具建立模型和训练,所以这里我们建立一个Pytorch可以直接使用的数据集。
1 | import torch |
数据整理函数
我们需要将文本数据编码后以张量的格式存储在GPU上。
1 | def collate_fn(data): |
接下来我们不着急进行下一步,可以先进行试算。随便弄一些文本和标签,将它们放入函数,看一看结果。
1 | demo = [ |
1 | tensor([[ 101, 872, 4991, ..., 0, 0, 0], |
注意,我们并不在意试算后的具体数值结果是多少。相比而言,我们更看重输出的数据格式,这一点非常重要!
数据加载器
现在的输出格式看上去没什么大问题,下一步就是构建加载器。
1 | train_load = torch.utils.data.DataLoader( |
1 | 600 |
预训练模型
此处加载的模型为bert-base-chinese模型,和编码工具的名字一致,因为模型和其编码工具往往配套使用。
1 | from transformers import BertModel |
1 | 10226.7648 |
顺便可以查看一下模型的参数数量,一共是约为一亿个参数。
由于这个模型较大,并且已经是训练好的模型,并且它只负责特征提取工作,所以在本次任务中可以不对其再次进行训练。为了节省计算,可以将其梯度冻结。
1 | for param in pretrained.parameters(): |
1 | torch.Size([4, 500, 768]) |
这个数据的格式表示,模型将之前的四段文本的编码结果也就是[4,500]张量,变成了[4,500,768]的张量,也就是说,最初的每段文本,都变成了[500,768]的张量,这就是属于这个文本的特征。
下游任务模型
在获取到特征以后,下游的模型只需要将特征转为0和1标签的概率。
1 | import torch.nn as nn |
在这段代码中,定义了下游任务模型,该模型只包括一个全连接的线性神经网络,权重矩阵为768×2,所以它能够把一个768维度的向量转换到二维空间中。
下游任务模型的计算过程为,获取了一批数据之后,使用backbone将这批数据抽取成特征矩阵,抽取的特征矩阵的形状应该是16×500×768,这在之前预训练模型的试算中已经看到。这3个维度分别代表了16句话、500个词、768维度的特征向量。之后下游任务模型丢弃了499个词的特征,只取得第1个词(索引为0)的特征向量,对应编码结果中的[CLS],把特征向量矩阵变成了16×768。相当于把每句话变成了一个768维度的向量。
注意:之所以只取了第0个词的特征做后续的判断计算,这和预训练模型BERT的训练方法有关系,这部分涉及到Bert的原理。
然后可以对下游模型进行试算。
1 | model = Model() |
1 | torch.Size([4, 2]) |
很好,输出的形状符合预期。
训练模型
所有东西都准备好了,可以开始训练了。
1 | #这里选用的是AdamW优化器,它是Adam的优化版,在自然语言处理处理领域一般比Adam更好用。 |
1 | steps: 0 loss: 0.9177090525627136 lr: 0.003333333333333333 accuracy: 0.3125 |
从训练过程来看,至少训练是有效的。
模型评价
现在要对模型进行评价,测试其在测试集上的准确率。
1 | test_set = Dataset('test') |
1 | 0 |
在测试集上有91.98%的准确率,这个正确率不算高,但起码证明训练效果是有的。我们只是训练的一轮,如果再多训练几轮,说不定可以提高一些。并且下游模型只有一层网络,只提取的第一个字符,如果模型更复杂一些,说不定也能提高准确率。