一、认识
BERT(Bidirectional Encoder Representation from Transformers)是2018年10月由Google AI研究院提出的一种预训练模型,该模型在机器阅读理解顶级水平测试SQuAD1.1中表现出惊人的成绩: 全部两个衡量指标上全面超越人类,并且在11种不同NLP测试中创出SOTA表现,包括将GLUE基准推高至80.4% (绝对改进7.6%),MultiNLI准确度达到86.7% (绝对改进5.6%),成为NLP发展史上的里程碑式的模型成就
BERT的网络架构使用的是多层Transformer Encoder结构。其最大的特点是抛弃了传统的RNN和CNN,通过Attention机制将任意位置的两个单词的距离转换成1,有效的解决了NLP中棘手的长期依赖问题
1.1 背景
预训练语言模型(Language model pre-training)对于下游很多自然语言处理任务都有着显著的改善。但是作者说到,现有预训练模型的网络结构限制了模型本身的表达能力,其中最主要的限制就是没有采用双向编码的方法来对输入进行编码
OPENAI GPT中使用了从左到右(left-to-right)的网络架构,使得模型在编码过程中只能看到之前的信息
如上图所示。对于这句样本来说,无论是采用left-to-right还是right-to-left的方法,模型在对"it"进行编码时都不能够很好的捕捉到其具体的指代信息。就像人在看这句话时一样,在没有看到"tired"这个词前无法判断"it"具体所指代的事物(如:把"tired"换成"wide",则"it"指代的就是"street")。若采用双向编码的方式则从理论上来说就能够很好的避免这个问题
橙色线条表示"it"应将注意力集中在哪些位置上,颜色越深表示注意力权重越大。通过上图可以发现,模型在对"it"进行编码时,将大部分注意力都集中在了"The animal"上,而这也符合实际预期
1.2 提出
BERT(Bidirectional Encoder Representations from Transformers)这一网络结构来实现模型的双向编码学习能力。同时,为了使得模型能够有效的学习到双向编码的能力,BERT在训练过程中使用了基于掩盖的语言模型(Masked Language Model,MLM),即随机对输入序列中的某些位置进行遮蔽,然后通过模型来对其进行预测
由于MLM预测任务能够使得模型编码得到的结果同时包含上下文的语境信息,有利于训练得到更深的BERT网络模型。除此之外,在训练BERT的过程中还加入了下句预测任务(Next Sentence Prediction, NSP),即同时输入两句话到模型中,然后预测第2句话是不是第1句话的下一句话
二、Bert网络结构
多个Transformer Encoder一层一层地堆叠起来,就组装成了BERT了,在论文中,作者分别用12层和24层Transformer Encoder组装了两套BERT模型,两套模型的参数总数分别为110M和340M
可以发现上半部分与之前的Transformer Encoder差不多,只不过在Input部分多了一个Segment Embedding
2.1 Input Embedding
在BERT中Input Embedding主要包含三个部分:Token Embedding、Positional Embedding和Segment Embedding。虽然前面两种Embedding在Transformer中已经介绍过,但是这里需要注意的是BERT中的Positional Embedding对于每个时刻的位置并不是采用公式计算出来的,其原理也是类似普通的词嵌入一样为每一个位置初始化了一个向量,然后随着网络一起训练
BERT开源的预训练模型最大只支持512个字符的长度,这是因为其在训练过程中(位置)词表的最大长度只有512
由于BERT的主要目的是构建一个通用的预训练模型,因此难免需要兼顾到各种NLP任务场景下的输入。因此Segment Embedding的作用便是便是用来区分输入序列中的不同序列,其本质就是通过一个普通的词嵌入来区分每一个序列所处的位置。如在NSP任务中,那么对于任意一个序列的每一位置都将用同一个向量来进行表示,即此时Segment词表的长度为2
最后,再将这三部分Embedding后的结果相加(并进行标准化)便得到了最终的Input Embedding部分的输出
最上面的Input表示原始的输入序列,其中第一个字符"[CLS]"是一个特殊的分类标志,若下游任务是做文本分类的话,那么在BERT的输出结果中可以只取"[CLS]"对应的向量进行分类即可;而其中的"[SEP]"字符则是用来作为将两句话分开的标志。Segment Embedding层则同样是用来区分两句话所在的不同位置,对于每句话来说其内部各自的位置都是一样的,若原始输入就只有一句话,那么Segment Embedding层中对应的每个Token的位置向量都是一样的。Positional Embedding是用来标识句子中每个Token各自所在的位置,使得模型能够捕捉到文本"有序"这一特性
2.2 Bert Encoder
其整体由多个BertLayer(也就是论文中所指代的Transformer blocks)所构成
在Transformer中,模型的输入会被转换成512维的向量,然后分为8个head,每个head的维度是64维。但是BERT的维度是768维度,然后分成12个head,每个head的维度是64维
BERT模型分为24层和12层两种,其差别就是使用Transformer Encoder的层数的差异,BERT-base使用的是12层的Transformer Encoder结构,BERT-Large使用的是24层的Transformer Encoder结构
三、Bert预训练
BERT是一个多任务模型,其预训练(Pre-training)任务是由两个自监督任务组成,即MLM和NSP
3.1 MLM
MLM是指在训练的时候随即从输入语料上mask掉一些单词,然后通过的上下文预测该单词,该任务非常像在中学时期常做的完形填空
正如传统的语言模型算法和RNN匹配那样,MLM的这个性质和Transformer的结构是非常匹配的。在BERT的实验中,15%的WordPiece Token会被随机Mask掉。在训练模型时,一个句子会被多次喂到模型中用于参数学习,但是Google并没有在每次都mask掉这些单词,而是在确定要Mask掉的单词之后,做以下处理:
- 80%的时候会直接替换为[Mask],将句子 "my dog is cute" 转换为句子 "my dog is [Mask]"
- 10%的时候将其替换为其它任意单词,将单词 "cute" 替换成另一个随机词,例如 "apple"。将句子 "my dog is cute" 转换为句子 "my dog is apple"。
- 10%的时候会保留原始Token,例如保持句子为 "my dog is cute" 不变
这么做的原因是若句子中的某个Token 100%都会被mask掉,那么在fine-tuning时模型就会有一些没有见过的单词。加入随机Token的原因是因为Transformer要保持对每个输入token的分布式表征,否则模型就会记住这个[mask]是token"cute"。至于单词带来的负面影响,因为一个单词被随机替换掉的概率只有15%*10% =1.5%,这个负面影响其实是可以忽略不计的。 另外文章指出每次只预测15%的单词,因此模型收敛的比较慢
优点
- 被随机选择15%的词当中以10%的概率用任意词替换去预测正确的词,相当于文本纠错任务,为BERT模型赋予了一定的文本纠错能力
- 被随机选择15%的词中以10%的概率保持不变,缓解了微调时与预训练时输入不匹配的问题(预训练时候输入句子中有mask,而finetune时输入是完整无缺的句子,即输入不匹配问题)
缺点
针对有两个及两个以上连续字组成的词,随机mask字割裂了连续字之间的相关性,使模型不太容易学习到词的语义信息。主要针对这一短板,因此google此后发表了BERT-WWM,国内的哈工大联合讯飞发表了中文版的BERT-WWM
3.2 NSP
Next Sentence Prediction(NSP)的任务是判断句子B是否是句子A的下文。若是的话输出"IsNext",否则输出"NotNext"。训练数据的生成方式是从平行语料中随机抽取的连续两句话,其中50%保留抽取的两句话,符合IsNext关系;另外50%的第二句话是随机从预料中提取的,关系是NotNext的。这个关系保存在[CLS]符号中
输入 = [CLS] 我 喜欢 玩 [Mask] 联盟 [SEP] 我 最 擅长 的 [Mask] 是 亚索 [SEP]
类别 = IsNext
输入 = [CLS] 我 喜欢 玩 [Mask] 联盟 [SEP] 今天 天气 很 [Mask] [SEP]
类别 = NotNext
在此后的研究(论文《Crosslingual language model pretraining》等)中发现,NSP任务可能并不是必要的,消除NSP损失在下游任务的性能上能够与原始BERT持平或略有提高。这可能是由于BERT以单句子为单位输入,模型无法学习到词之间的远程依赖关系。针对这一点,后续的RoBERTa、ALBERT、spanBERT都移去了NSP任务
BERT预训练模型最多只能输入512个词,因为在BERT中,Token,Position,Segment Embeddings 都是通过学习来得到的。在直接使用Google 的BERT预训练模型时,输入最多512个词(还要除掉[CLS]和[SEP]),最多两个句子合成一句。这之外的词和句子会没有对应的embedding