Google提出的BERT(Bidirectional Encoder Representations from Transformers)是现在自然语言处理领域里当之无愧的王者,但是在阅读这篇文献的时候,总有一种和传统自然语言技术断层的感觉。通过研究OpenAI GPT后才恍然大悟,原来这才是其中的桥梁:BERT的思想启发自OpenAI GPT,并应用了transformer的强大处理能力,结合了更多的训练数据、更巧妙的训练手段,才取得了现在这样好的效果。这里就对OpenAI GPT和BERT共同依赖的无监督自然语言模型技术进行全面总结,同时对他们各自的特点进行阐述。
对于训练大型的深度学习网络来说,有标注的训练数据是最大的限制瓶颈。因此在NLP领域可以通过学习大量的无监督数据来减少对监督数据的依赖。同时即使监督数据充足,使用更大量级的无监督预训练可以让模型获得更好的特征表示,从而在提升下游fine-tuning任务的效果(例如word embeddings)。但是想要在字粒度学习好的无监督特征表示并不容易,主要是因为
针对上述问题,OpenAI GPT开创性的提出了统一的模型架构,使用通用的特征表示和最少的模型修改,即可无缝支持无监督预训练和有监督微调:
1)将多样的输入数据结构组合在一起,构成统一的连续token序列输入;
2)预训练和微调的模型统一采用transformer,并在最后一层特征输出之前都保持一致,区别仅在于后面的线性层和优化目标。
BERT也完全采用了上述方法。
OpenAI GPT最大的特点是在无监督预训练过程中选择了经典的LM(Language Modeling)作为优化目标,也就是说通过最大化由前面一段语句去预测后面一个词的似然概率来实现模型的学习,也就是对一条语料 U = { u 1 , u 2 , ⋯ , u n } \mathcal{U}=\{u_1,u_2,\cdots,u_n\} U={u1,u2,⋯,un}的似然概率用公式表示为
L 1 ( U ) = ∑ i l o g P ( u i ∣ u i − k , ⋯ , u i − 1 ) L_1(\mathcal{U}) = \sum_i logP(u_i|u_{i-k},\cdots,u_{i-1}) L1(U)=i∑logP(ui∣ui−k,⋯,ui−1)
其中 k k k表示上下文窗口大小,由此可见OpenAI GPT只能由左向右的执行训练,也因此是一个单向的预训练模型,这也限制着它的网络架构只能使用transformer的decoder部分。而在有监督微调过程中,一条语料包含token序列 X = { x 1 , x 2 , ⋯ , x m } \mathcal{X}=\{x_1,x_2,\cdots,x_m\} X={x1,x2,⋯,xm}和对应的标签 y y y,将 X \mathcal{X} X输入到相同的预训练网络中得到transformer的特征表示,并将输出层替换为任务相关的输出层来微调整个网络。目标用公式表示为
L 2 ( X , y ) = ∑ x , y l o g P ( y ∣ x 1 , ⋯ , x m ) L_2(\mathcal{X},y) = \sum_{x,y} logP(y|x_1,\cdots,x_m) L2(X,y)=x,y∑logP(y∣x1,⋯,xm)
同时论文表示在微调的 L 2 L_2 L2目标中辅助以 L 1 L_1 L1目标能够增强模型的泛化性并加快收敛,因此最后的目标为
L ( X , y ) = L 2 ( X , y ) + λ L 1 ( X ) L(\mathcal{X},y) = L_2(\mathcal{X},y) + \lambda L_1(\mathcal{X}) L(X,y)=L2(X,y)+λL1(X)
这里还有一个重要的细节,在微调之前需要将多样的输入token序列合并为统一有序的token序列,这其中引入了一些在预训练过程中不存在的分隔token(start、delim、extract),而它们的特征表示只能在微调过程中进行学习。对于多样输入的转化如下图所示,需要注意的是
1)transformer的输出特征表示只取extract对应的即可,因为它已经attend到序列中的每个token表示了;
2)在相似度任务中,由于text1和text2没有先后顺序,因此将二者不同先后顺序的token序列输入同一个transformer,并将特征表示逐元素相加后接入输出层;
3)对于问答系统任务,将多个回答分别与context合并构成多条token序列,再输入同一个transformer和输出层,最后使用softmax归一化得到概率分布。
我们再回头看见BERT的核心工作也就一目了然了,这里总结为以下5个方面:
max_position_embeddings=512
,最大segment分段数token_type_vocab_size=16
|
|
不深入了解BERT的预训练则不知道它的强大。BERT的预训练需要MLM和NSP结合,这里分别对二者进行介绍。
传统的LM(Language Modeling)只适合例如RNN/LSTM这样单向的模型架构,而transformer天然就是一种双向架构,像OpenAI GPT这样强制transformer学习单向信息的模型,势必会影响模型最终的效果。BERT最大的贡献便是用MLM代替了LM从而使得预训练双向transformer成为了可能。
具体来说,BERT将输入token序列中的15%随机替换为[mask]token,利用这些[mask]在最后输出的特征表示,来预测其原本是哪些词来训练网络,图示如下。但是这样做会在预训练中引入[mask]而微调和最终推理过程中却不会出现,造成了上下游不一致的情况。同时,MLM训练出来的网络只会利用“上下文”来得到当前token的特征表示,即便在微调和推理过程中当前token是知道的,但当前token也不会对其自身的特征表示有任何贡献,这又是另一种上下游不一致。
综上所述,为了消除上述两种上下游不一致情况,BERT在实现过程中又使用了一种trick,在选中的15%的被加上mask的token中,采取如下处理:
最后这15%的token依然全部被预测来完成模型的学习。不难看出来上述的2、3步骤是相互制衡的关系,因而二者的比例保持相等,既让当前token有所贡献,又通过设置了一些噪声来抑制它贡献太多。MLM仅在一个batch中预测15%的token,而传统的LM会预测全部token,这就导致了MLM需要更多的训练步数(1,000,000步),但这种巧妙的方法经过实验后超越了LM达到了最佳效果。
假设一条语料中被mask的token下标集合为 M \mathcal{M} M,transformer最后一层第 i i i个token的特征表示为 h i ∈ R d h_i\in \mathbb{R}^d hi∈Rd,其对应的真实词表onehot向量为 y i ∈ R l y_i\in \mathbb{R}^l yi∈Rl,输出线性层的权重为 W m ∈ R d × l W_m\in \mathbb{R}^{d\times l} Wm∈Rd×l, l l l为词表大小。那么MLM的交叉熵损失用公式表示为
L M L M = ∑ i ∈ M y i log ( s o f t m a x ( h i W m ) ) L_{MLM}=\sum_{i\in\mathcal{M}}y_i\log(softmax(h_iW_m)) LMLM=i∈M∑yilog(softmax(hiWm))
MLM的训练是在字粒度上的,而为了更好的适用于问答系统和语言推理等需要预测句粒度的关系,BERT添加了NSP目标,从而和MLM构成了多任务学习(Multi-Task Learing)。具体来说,NSP就是一个简单的二分类任务,其训练语料可以通过任何语料集通过下述处理获取:
需要注意的是这里的”语句“不一定是自然的语句,而是有可能包含多个自然语句的token序列。将抽取的语句以[CLS,A,SEP,B,SEP]的token序列输入模型中,最终取[CLS]的特征表示连接输出层。假设一条语料在transformer最后一层中[CLS]token的特征表示为 h C ∈ R d h_C\in \mathbb{R}^d hC∈Rd,label向量为 y ∈ R 2 y\in \mathbb{R}^2 y∈R2,输出线性层的权重为 W n ∈ R d × 2 W_n\in \mathbb{R}^{d\times 2} Wn∈Rd×2。那么NSP的交叉熵损失用公式表示为
L N S P = ∑ y log ( s o f t m a x ( h C W n ) ) L_{NSP}=\sum y\log(softmax(h_CW_n)) LNSP=∑ylog(softmax(hCWn))
后续研究对NSP实际效果还有深入研究,我们下一节再展开。最终BERT的预训练过程可以参考下图:输入格式[CLS,A,SEP,B,SEP],其中A和B按上述方式随机mask,特殊[CLS]和[SEP]token不参与mask。最终损失函数表示为 L = L M L M + L N S P L=L_{MLM}+L_{NSP} L=LMLM+LNSP
BERT和OpenAI GPT一样,都可以对多样的输入进行简单的合并,就可以完成端到端的微调了。关于多种目标任务的处理方式如下:
深度学习本就是半理论半实践的科学,经过大量的实验还是能发现BERT的一些问题的,这里总结为如下几个方面
这篇论文发现BERT预训练里有一些方案选择和细节处理的不太好,导致模型没有被充分的训练,而当充分训练后,RoBERTa可以达到比BERT更优异的效果,甚至超过了BERT的后续改进版本,具体有
越大的模型在语言模型中效果越好,即便BERT-base已经有110M参数,而BERT-large达到了340M参数,但仍然没有看到有饱和的迹象,唯一的限制就是GPU/TPU的内存限制和训练时长。那么能不能控制模型的规模而达到BERT一样好的性能?ALBERT就是一种很好的选择,它通过embedding矩阵分解和跨层参数共享,在略微牺牲效果的前提下,极大程度的减少了模型规模;重新探讨了NSP的不足,并提出使用SOP(sentence-order prediction)任务来进一步提升效果并超越了BERT。
和BERT一样,ALBERT同样使用了transformer的encoder部分,并使用了GELU激活,设置隐层维度为 H H H,那么feed-forward的中间层维度也为 4 H 4H 4H,attention的head数量为 H / 64 H/64 H/64,这里仅额外多了一个词表的embedding大小 E E E。ALBERT的3点主要贡献如下
|
|
除了上述贡献外,ALBERT的训练过程还包括了很多后BERT模型的很多trick:
1)输入序列90%长度为512,10%小于512,这是根据RoBERTa的实验,越长的输入序列上下文信息越完整,模型学习效果越好
2)词表大小和BERT同为30K
3)在MLM任务中使用n-gram masking,即添加mask的方式不再互相独立了,而是选取n-gram后一起添加mask,语义信息更完整
4)优化器使用 L A M B L_{AMB} LAMB
5)batch size为4096,训练125000步。
另外,模型使用更大的训练集还会有提升;由于ALBERT共享权重具有天然的正则化效果,在大型数据集上仍然未过拟合,去掉transformer中的dropout效果会略微提升。通过实验还发现,增加ALBERT的嵌套层数并不能一直提升效果,例如ALBERT-large到达24层效果最好,而ALBERT-xxlarge到达12层效果最好。