Bert原理
BERT是2018年谷歌提出来的在自然语言处理领域的一个模型,比GPT1晚了大概四个月,在NLP领域产生了深远的影响,本文接下来对BERT进行详细介绍。
1、什么是BERT
BERT全称为Bidirectional Encoder Representations from Transformers,即一种基于Transformer编码器的双向语言表征模型,首先会用BERT在大规模的文本数据集上进行自监督学习,使模型学习到语言的表征能力 ,接着可以在不改变模型结构的基础上在各种NLP下游任务上做微调。(因为之前的基于RNN结构的预训练模型,在应用到不同的下游任务时,需要稍微改变模型结构)
2、BERT的原理
在之前的预训练语言表征模型架构都不是双向的,例如GPT(用的transformer解码器)在预训练时由于掩码的存在当前单词只能看到前面的信息,而不能看到当前单词后面的信息,相当于是根据当前时刻去预测未来。而在应用到下游任务时,例如知识问答这种句子层面的任务是很不好的,因为我们需要从整体语境,结合左右两边的信息去得出答案,而不仅仅只是根据前面的信息。
Transformer的编码器由于自注意力的存在天生就是双向的,对于输入的完整的句子,他会使句子中的每个单词之间都产生联系,也就是左右都可以看到,因此BERT选择使用Transformer的编码器。也就是说,BERT的模型结构就是堆叠Transformer的编码器,当然还包括前面的Embedding层和最后的全连接层。
BERT模型最初设计时主要是为了理解语言和句子特征提取,因为只有Transformer的编码器,可以看到全部的输入,所以单独的BERT很难做机器翻译这种生成式任务。
BERT有两个版本,分别是
和
。
- 其中,L指的是Transformer编码器层的个数,H是编码器中隐藏层的大小,A为多头注意力中分了几个头。
的参数量和GPT1差不多。
- 其中,L指的是Transformer编码器层的个数,H是编码器中隐藏层的大小,A为多头注意力中分了几个头。
3、BERT预训练
3.1 输入
在预训练的过程中,为了使BERT能够更好的适应下游的任务,理解句子之间的关系,输入是两个句子(句子对),这两个句子可能是上下文的,也可能不是上下文的。具体的输入形式如下:
[cls] ‘我’ ‘爱’ ‘吃’ ‘梨’ [SEP] ‘香‘ ‘焦’ ‘熟’ ‘了’ (不是上下文 NotNext)
[cls] ‘我’ ‘爱’ ‘吃’ ‘梨’ [SEP] ‘因‘ ’为‘ ’梨‘ ’又‘ ’甜‘ ’又‘ ’脆‘ (是上下文 IsNext)
在上面的两对句子,每队句子的开头都有一个[cls]符号,同时中间使用[sep]符号分割两个句子。[cls]符号被看作是一个特殊的符号,在进行自注意力计算的时候[cls]融合了所有输入的信息,因此在作分类任务的时候可以将[cls]作为整个输入提取特征后的代表,把[cls]通过全连接层再做softmax操作得到最终的分类结果。
那么最终送进transformer编码器的输入是什么呢?
当我们构造好输入后,和tranformer的输入embedding一样,会先将句子根据词表变成一串数字,接着进行tokens embedding,将数字映射成向量,然后将tokens embedding和位置编码(position embeddings)进行相加,注意这里的位置编码是可以进行学习的,这是和transformer的位置编码不同的一点。同时,由于我们的输入是两个句子,我们还会进行加入Segment embeddings,这个的作用是告诉模型哪个token是一个句子的,哪个token是第二个句子的。如下图所示:
3.2 训练任务1:Masked LM
在进行预训练时,由两个训练任务,第一个训练目标是Masked LM。由于双向的模型训练结果可能比单向的模型更好,因此为了训练一个双向的表征模型,使模型更好的理解整体特征,BERT会对输入中的15%的句子随机打上Mask,然后让模型根据上下文信息预测被Mask的单词一开始是什么,相当于让模型去完型填空。这种策略被称为” masked language model(MLM)”。例如:
输入: [cls] ‘我’ ‘爱’ ‘吃’ ‘梨’ [SEP] ’梨‘ ’又‘ ’甜‘ ’又‘ ’脆‘
Masked LM:[cls] ‘我’ ‘爱’ ‘吃’ ‘梨’ [SEP] [mask] ’又‘ ’甜‘ ’又‘ ’脆‘接着将embedding后的输入送进模型,得到最终的输出,如下图所示:
其中,[mask]符号编码后得到
, 经过编码得到
, 然后将R$_{mask}经过全连接层得到最终预测的被mask的词,然后与被mask之前的词算Loss,通过此方式实现自监督。
尽管这样可以训练得到一个双向的模型,但是在进行下游任务的微调时,输入里不会有[mask]这个符号,这样就会使预训练和微调的时候输入产生不一样。为了解决这个问题,如果有一个词被选中进行mask,那么这个词有80%的概率会用[mask]符号代替,有10%的概率会用其他的单词代替,还有10%的概率什么也不做。如下所示:
80%概率 my dog is hairy ——>my dog is [MASK]
10%概率 my dog is hairy ——>my dog is apple
10%概率 my dog is hairy ——>my dog is hairy通过这样的方式,使得预训练和微调的时候输入可以产生匹配。如果输入中没有[mask]符号,模型不会知道到底哪一个词是mask的,促使模型去对每一个词进行语境上的双向理解猜测,同时又因为只有很少的比例没有[mask]标识,因而在预训练的时候不会影响模型的收敛。
3.3 训练任务2:Next Sentence Prediction
由于很多下游任务例如问答是基于理解两个句子之间的关系,而不是直接让模型去猜测,因此BERT中还设计了第二个训练任务:预测两个句子在文中是否是属于上下文的关系。通过增加Next Sentence Prediction任务,可以使模型在问答和自然语言推理等下游任务上的能力提高。输入的两个句子中有50%的概率是属于上下文关系,50%的概率不是属于上下文关系,因此这个任务又是一个二分类任务。例如:
- 输入中的[CLS]符号在经过编码后得到C,C可以看作是汇集了整个句子的所有信息,因此将C经过MLP后得到最终二分类的输出,然后去算Loss。
因此,在预训练时,BERT相当于是有两个优化目标,一个是预测被MASK的词原来是什么,还有是预测输入的两个句子是否属于上下文关系。
4、BERT微调
4.1 分类任务
分类任务有很多种,如果输入是很多个句子的话,那么就按照预训练的时候那样进行处理,输入的第一个token是[CLS],句子中间使用[SEP]进行分割;如果输入是一个句子的话,那么只需要在输入的开头加上[CLS]字符就可以。无论输入是一个句子还是很多句子,最终都是将[CLS]字符经过编码后,然后将其通过一个MLP层得到最终的输出,然后与标签去算Loss。
4.2 问答任务
问答任务的输入是一个问题和一段话,问题的答案就在这段话里,因此在对问答任务进行微调的时候,我们只需要计算每一个输入的token是答案开头的概率和结尾的概率,然后与标签去算Loss。
4.3 句子实体识别任务
在句子实体识别任务中,就是对句子中的每个词,判断他是属于什么标签,相当于是对句子中的每个单词进行多分类任务。这时,会将每一个编码后tokens(除去[cls]这种特殊字符)分别经过全连接层,去计算每一个tokens的属性类别,然后通过标签计算Loss。
5、总结
- 总的来说,BERT在预训练时相当于是完型填空,根据上下文语境去猜单词,而GPT则是根据当前时刻去预测未来信息,因此GPT的训练任务相比于BERT来说更难一些,BERT更加好收敛一些。但是GPT由于是预测未来,所有在拥有大规模数据集和模型参数的情况下,GPT的上限可能更高一些。不过一般人估计也没有设备能够训练GPT3那种规模的模型,相比较起来,BERT在学术研究方面可能更加友好一些,毕竟咬一咬牙凑几张显卡还是能跑起来BERT的,而且在同规模大小的情况下,BERT比GPT能取得的效果更好。