type
status
password
date
slug
summary
category
URL
tags
icon
本文来讲述BERT应用的一个例子,采用预训练好的BERT模型来进行演示。BERT的库来源于Transformers,这是一个由PyTorch编写的库,其集成了多个NLP领域SOTA的模型,比如bert、gpt-2、transformer xl等,并且可以自由选择已经预训练好的模型参数,我们可以基于这些参数进行进一步的训练调试。
安装
在开始之前,我们需要先安装
transformers
,直接在pip上安装即可:bert基础模型
BertTokenizer
在英文模型中,添加自定义词的作用不仅是增加新词或者专业领域的词汇,而且可以防止词语被自动拆成词根词缀
方法1
- 找到pytorch版本的bert-base-cased的文件夹中的vocab.txt文件。
- 最前面的100行都是[unused],直接用需要添加的词替换进去。
方法2
重构词汇矩阵。可以通过重构BERT初始权重矩阵的方式将他们加入词表。
输出
查看
BertModel(BertPreTrainedModel)
的官方文档,里面对返回值outputs
的解释如下:- last_hidden_state:
(batch_size, sequence_length, hidden_size)
,序列最后一层的隐藏状态
- pooler_output:
(batch_size, hidden_size)
,序列的第一个token(classification token)的最后一层的隐藏状态
- hidden_states:可选项,如果指定config.output_hidden_states=True,则会输出。它是一个元组,第一个元素是embedding,其余元素是各层的输出,每个元素的形状是(batch_size, sequence_length, hidden_size)。
- attentions:这也是输出的一个可选项,如果指定config.output_attentions=True,则会输出。它是一个元组,它的元素是每一层的注意力权重,用于计算self-attention heads的加权平均值。
情感分类任务
本文采用的任务是文本分类任务中的情感分类,即给出一个句子,判断出它所表达的情感是积极的(用1表示)还是消极的(用0表示)。这里所使用的数据集是斯坦福大学所发布的一个情感分析数据集SST,其组成成分来自于电影的评论。模型大致结构如下图所示,这里就用的是上述所说的feature extract特征抽取方法,使用BERT的生成的句子向量。
依赖库
加载数据集
利用BERT进行特征抽取,之后使用逻辑回归进行分类
获取预训练model、tokenizer
在这里,我们利用BERT对数据集进行特征抽取,即把输入数据经过BERT模型,来获取输入数据的特征,这些特征包含了整个句子的信息,是语境层面的。这种做法类似于EMLo的特征抽取。需要注意的是,这里并没有使用到BERT的微调,因为BERT并不参与后面的训练,仅仅进行特征抽取操作。我们使用预训练好的"bert-base-uncased"模型参数进行处理,采用的模型是
BertModel
,采用的分词器是BertTokenizer
。tokenizer原理(wordpiece
)
由于我们的输入句子是英文句子,所以需要先分词;然后把单词映射成词汇表的索引,再喂给模型。实际上Bert的分词操作,不是以传统的单词为单位的,而是以
wordpiece
为单位,这是比单词更细粒度的单位。同时为了提升训练速度,我们需要把句子都处理成同一个长度,即常见的pad
操作,我们在短的句子末尾添加一系列的[PAD]符号:Bert模型
我们来看以下Bert模型给我们的输出是什么样的:
第一维的是样本数量,第二维的是序列长度,第三维是特征数量。也就是说,Bert对于我们的每一个位置的输入,都会输出一个对应的特征向量。
使用逻辑回归进行训练
在这一部分,我们使用sklearn的逻辑回归模块对我们的训练集进行拟合
请注意:我们使用[:,0,:]来提取序列第一个位置的输出向量,因为第一个位置是[CLS],比起其他位置,该向量应该更具有代表性,蕴含了整个句子的信息。
完整代码
基于原生PyTorch微调BERT模型
在上一部分,我们利用了Bert抽取特征的能力进行建模,提取了Bert的输出特征,再输入给一个线性层以预测。但Bert本身的不参与模型的训练。现在我们采取另一种方式,即fine-tuned,Bert与线性层一起参与训练,反向传播会更新二者的参数,使得Bert模型更加适合这个分类任务。
将训练数据输入模型,得到预测结果→计算损失函数→计算梯度→更新参数→重新将训练数据输入模型,得到预测结果
建立模型
模型很简单,关键代码都在上面注释了。其主要构成是在bert模型的[CLS]输出位置接上一个线性层,用以预测句子的分类。
训练模型
得到以下输出: