NLP预训练模型:从transformer到albert
XLNet:运行机制及和Bert的异同比较
从语言模型到Seq2Seq:Transformer如戏,全靠Mask
Transformer和Bert相关知识解答
Transformer-XL: Attentive Language Models Beyonds a Fixed-Length Context
transformer是这些模型的基础,具体的原理+代码的介绍可以看我的博客:Transformer 代码+原理。
在上一篇博客中详细介绍了transformer的原理和pytorch版本的代码,这里将一些问题拎出来,再强调一下。
- padding mask:解决方式就是在填充的位置赋予一个很小的负值/负无穷(-np.inf)的值,经过softmax后的得分为0,即没有注意力分配到这个上面。
- mask self-attention: 产生一个对角线为0的上三角矩阵。这样就掩盖掉后面的信息了。
为什么要使用multi-head attention?
论文上的说法是使用multi-head可以得到不同的子空间,从而得到不同的信息。但是也有很多paper对此说法保持怀疑态度,并做了很多研究,这里参考了为什么Transformer 需要进行 Multi-head Attention?的解答。
有大量的paper表明,transformer或者bert等的特定层是有特定的功能的,比如说,底层更偏向于关注语法,顶层更偏向于关注语义。这样看来,在同一层transformer关注的点是相同的,说明每个head关注点是相同的,但是也有研究表明,在每层总有一两个head关注点独一无二。这可能是因为初始化的不同所导致的(因为如果相同的初始化,经过同样的计算,其参数会是相同的)。
众多研究表明Multi-Head其实不是必须的,去掉一些头效果依然有不错的效果(而且效果下降可能是因为参数量下降),这是因为在头足够的情况下,这些头已经能够有关注位置信息、关注语法信息、关注罕见词的能力了,再多一些头,无非是一种enhance或noise而已。
为什么使用LN对其进行归一化?
关于BN和LN我之前写过一篇博客来介绍:聊聊深度学习中的BN和LN。
在这篇博客中我有介绍过说BN更适合做CV,因为BN是对mini-batch中的某一个维度进行归一化,但这不适合NLP任务,LN是对一个样本中的所有维度进行归一,比较适合NLP任务。
选择什么样的归一化方式,取决于关注数据的哪部分信息,如果某个维度的差异度很重要,需要被拟合,那么就别在那个维度归一化。
为什么multi-head attention后面要加一个ffn?
我之前的博客文本分类算法中就提到过,增加全连接层,能够学习特征之间的关联与权重(也就是对特征进行加权以及合并),能够提升整个block的非线性变换的能力。
对于长文本,经典的transformer会按照固定的长度(512字符),直接将文本划分为若干个segment。很有可能一句话就会被分到两个segment之中,导致上下文碎片化。
而且在模型训练时,如下图(a),两个segment之间并不产生联系,他们被单独训练,而且这显然不符合现实。
在模型评估之时,如下图(b),每次只计算最后一个位置的token,计算完后,整个序列向后移动一个位置。
Transformer-XL通过引入Segment-Level recurrence mechanism来建模更长序列,它通过融合前后两个Segment的信息来到这个目的。
这里采用了相对位置编码,Vanilla Transformer中的绝对位置编码不适合transformer-XL,因为这会造成位置信息的混乱——我们不知道某个相同的位置编码到底是来自于哪个segment。
并且transformer-XL改变了self-attention的计算方式,首先我们来看看Vanilla Transformer的计算过程:
通过上述分析,transformer-xl从n-1层到第n层的完整计算为:
bert是在transformer encoder的基础之上进行改进的,因此在整个流程上与transformer encoder没有大的差别,只是在embedding,multi-head attention,loss上有所差别。关于bert的细节,网络上有很多相关资料,这里就列出一些关于bert的问题。
- transformer的输入是 token embedding 和 position embedding(绝对位置编码);bert的输入是 token embedding ,position embedding(学习得到)和segment embedding。
- bert在token序列之前加了一个特定的token“[cls]”,这个token对应的向量后续会用在分类任务上;如果是句子对的任务,那么两个句子间使用特定的token“[seq]”来分割
- transformer 在embedding之后跟了一个dropout,但是bert在embedding之后先跟了一个layer normalization,再跟了一个dropout。
- transformer的loss是在decoder阶段计算的。bert预训练的loss由2部分构成,分别是NSP和MLM任务,这两个任务的loss相加得到总loss。 bert fine-tune任务的loss会根据任务性质来设计。
- bert在encoder之后,在计算NSP和MLM的loss之前,分别对NSP和MLM的输入加了一个Dense操作,这部分参数只对预训练有用,对fine-tune没用。而transformer在decoder之后就直接计算loss了,中间没有Dense操作。
XLNet: Generalized Autoregressive Pretraining for Language
XLNet:Generalized Autoregressive Pretraining for Language Understanding
XLNet:运行机制及和Bert的异同比较
在介绍XLNET之前,需要介绍一下AR和AE。
BERT的成功有一部分取决于它充分利用了上下文的信息,但是BERT这种学习模式,不太适合自然语言生成的任务,因此其自然语言生成任务的效果较差。而且上文也说过,因为这种mask的方式会造成fine-tune阶段与训练阶段的脱节,所以bert就出了三种情况的这种操作。
XLNET的想法就是,在AR的想法中尽可能地利用双向的语言的信息。在fine-tune的阶段,不像Bert那种带Mask符号的Denoising-autoencoder的模式,而是采用自回归LM的模式。
就是说,看上去输入句子X仍然是自左向右的输入,看到Ti单词的上文Context_before,来预测Ti这个单词。但是又希望在Context_before里,不仅仅看到上文单词,也能看到Ti单词后面的下文Context_after里的下文单词,这样的话,Bert里面预训练阶段引入的Mask符号就不需要了,于是在预训练阶段,看上去是个标准的从左向右过程,Fine-tuning当然也是这个过程,于是两个环节就统一起来。
那么XLNET是怎么做的呢?它的思想是对token进行全排列,比如说有token [x1,x2,x3]某个排列后就有[x1,x3,x2],那么我们在读到x2的时候自然就有x1,x3的信息(上下文信息)。假设token的长度是n,那么进行全排列的话就有n!种可能,这样计算量也太大了,因此xlnet采用采样的方式逼近目标函数的期望:
假设给定一串序列 x = [ x 1 , x 2 , x 3 , . . . , x n ] x=[x_1,x_2,x_3,...,x_n] x=[x1,x2,x3,...,xn],它将有n!个不同的排列组合 Z = [ z 1 , z 2 , . . . , z n ! ] Z=[z_1,z_2,...,z_{n!}] Z=[z1,z2,...,zn!],令 z ∈ Z z∈Z z∈Z表示某一排列方式, z t z_t zt表示为z这个排列的第t个位置, z < t z
我们解决了目标函数的问题,但是这并不代表问题解决,我们还有两个问题:
因此引入了“双流自注意力”(two stream self attention)机制来帮助建模:
xlnet打败了bert,但是在xlnet发布之后不久,bert的改进版roberta使用了160G的数据进行预训练,又打败了xlnet。
RoBERTa: A Robustly Optimized BERT Pretraining Approach
Dynamic Masking:
BERT中有个Masking Language Model(MLM) 预训练任务,在准备训练数据的时候,需要Mask掉一些token,训练过程中让模型去预测这些token,这里将数据Mask后,训练数据将不再变化,将使用这些数据一直训练直到结束,这种Mask方式被称为Static Masking。
如果在训练过程中,期望每轮的训练数据中,Mask的位置也相应地发生变化,这就是Dynamic Masking,RoBERTa使用的就是Dynamic Masking。
在RoBERTa中,它具体是这么实现的,将原始的训练数据复制多份,然后进行Masking。这样相同的数据被随机Masking的位置也就发生了变化,相当于实现了Dynamic Masking的目的。例如原始数据共计复制了10份数据,共计需要训练40轮,则每种mask的方式在训练中会被使用4次。
Full-Sentences without NSP:
通过实验发现,去掉NSP任务能够提升一些down-stream任务的指标。FULL-SENTENCES表示从一篇文章或者多篇文章中连续抽取句子,填充到模型输入序列中。也就是说,一个输入序列有可能是跨越多个文章边界的。具体来讲,它会从一篇文章中连续地抽取句子填充输入序列,但是如果到了文章结尾,那么将会从下一个文章中继续抽取句子填充到该序列中,不同文章中的内容还是按照SEP分隔符进行分割。
Larger Batch Size:
RoBERTa通过增加训练过程中Batch Size的大小,来观看模型的在预训练任务和down-stream任务上的表现。发现增加Batch Size有利于降低保留的训练数据的Perplexity,提高down-stream的指标。
Byte-Level BPE:
Byte-Pair Encodeing(BPE)是一种表示单词,生成词表的方式。BERT中的BPE算法是基于字符的BPE算法,由它构造的”单词”往往位于字符和单词之间,常见的形式就是单词中的片段作为一个独立的”单词”,特别是对于那些比较长的单词。比如单词woderful有可能会被拆分成两个子单词”wonder”和”ful”。
不同于BERT,RoBERTa使用了基于Byte的BPE,词表中共计包含50K左右的单词,这种方式的不需要担心未登录词的出现,因为它会从Byte的层面去分解单词。
More Data and More Training Steps
ALBERT
我们知道bert模型很大,参数很多,占用的内存很大,在分布式计算中通信开销也大。因此Albert就是为了进行参数的削减但是又不对性能产生影响。
Albert有这些操作:
之所以可以这样做是因为每次反向传播时都只会更新一个 Token 相关参数,其他参数都不会变。而且在第一次投影的过程中,词与词之间是不会进行交互的,只有在后面的 Attention 过程中才会做交互,我们称为 Sparsely updated。如果词不做交互的话,完全没有必要用一个很高维度的向量去表示,所以就引入一个小的隐藏层。
作者推测,NSP效果不佳的原因是其难度较小。将主题预测和连贯性预测结合在了一起,但主题预测比连贯性预测简单得多,并且它与LM损失学到的内容是有重合的。SOP的正例选取方式与BERT一致(来自同一文档的两个连续段),而负例不同于BERT中的sample,同样是来自同一文档的两个连续段,但交换两段的顺序,从而避免了主题预测,只关注建模句子之间的连贯性。
关于位置编码的更多内容可以阅读让研究人员绞尽脑汁的Transformer位置编码