语言模型串烧(BERT后)

语言模型的发展实在是太快了,怎么才赶上NLP快车呢?此文包含在BERT之后提出的一些语言模型。

Transformer-XL(2019年1月)

为了方便陈述,用Trm-XL代表Transformer-XL。

Trm模型最大的缺点就是只能处理非常短的文本。而作为Trm的升级版,Trm-XL(XL是指extra long)在长距离依赖上表现十分好,并且在速度方面比Trm快1800多倍。

早在Trm-XL之前,就已经有一款称作Vanilla Trm的模型,将长文本分成一段段的chunk,然后再独立运行Trm,试图弥补Trm的近视。但是这样的措施实际上没有并没有太大的性能提升,首先在chunk与chunk之间,信息并不能交互,一旦有两个token之间的距离超过了Trm的边界,那么就是不相关的。其次在评估阶段,每过一个step就要运行一次Trm,时间消耗是很大的。

Trm-XL在Vanilla Trm的基础上引入了两个创新点:

  • 循环机制
  • 相对位置编码

以修复Vanilla Trm的短板。

Trm-XL虽然和Vanilla Trm一样也会对文本分段建模,但是引入了段与段之间的循环机制,上一个chunk的隐含层信息被缓存起来,使得当前chunk在计算时能利用之前的信息。这样一来,Trm的边界被拓宽了,就以下面这张图为例,x12的信息能追溯至x3。另外,有了之前chunk的部分信息,下一个chunk就不需要重复计算这些联系,所以每次向前都是迭代一个chunk的大小,不再是龟速的每次一个step了。

Trm-XL的另一个改进是使用了相对位置编码的position embedding。对于同一个chunk中的询问q_i 和键k_j,他们之间的注意力分数可以分解为:

其中$E_{x_i}$和$E_{x_j}$分别是词i和词j的embedding,$U_i$和$U_j$是位置向量,这个式子实际上是

$$\left(W_q (E_{x_i} + U_i )\right)^T \left(W_k (E_{x_j} + U_j)\right)$$

的展开式。而引入了相对位置编码后,原先所有的U将被替换,不过可以看到这种替换不是对称的,$A_{i,j}^rel$中所有的$U_j$被替换为$R_{i−j}$,而$U_i$则被替换为了u和v。另外,权重矩阵也有些许变化。

为什么这样做呢?实际上作者的意思是将位置i看作相对位置坐标系的原点,一旦i固定,j和i的关系就可以通过距离差确定了,上式中的R就是一个正弦信号嵌入矩阵。另外只要距离相同,不论i和j的实际数值是多少,都可以分享参数u和v,这应该是学习坐标原点的含义吧。

GPT-2(2019年2月)

OpenAI的GPT-2在写作上可谓是和人类难分真假,甚至有人想用GPT-2续写小说。那么这么强大的网络是怎么构造的呢?

一般来说,双向语言模型能比单向的提取更多的上下文信息,但是双向语言模型不太适合做生成任务,因在看不到后文的情况下,双向语言模型的性能会大打折扣。但是只用单向语言模型的GPT-2怎么吸引大众的眼球呢?在模型“先天不足”的情况下,作者只好选择用数据量来弥补。作者为了训练该网络,爬取了800w网页得到一份巨大的WebText数据集,然后堆叠了48层Trm(完全形态),形成一个拥有15亿参数的GPT-2。之前提到的Trm是会对一个chunk中所有的token对做self-attention的,但是为了保证单向的特性,作者只让token与之前已经出现的token做attention,也就是下图展示的结构了。

光有数据和模型还不够,还缺训练方法。在“_Improving Language Understanding by Generative Pre-Training_”中,也就是GPT1.0的训练分为无监督预训练(pre-training)和有监督微调(fine-tuning)两个阶段。无监督阶段就是很常规的给定上文预测下文的任务:

$$
L_1 (U) = \sum_i{\log⁡ P(u_i |u_{i−k}, \dots, u_{i−1},\Theta)}
$$

其中U表示语料库。

而有监督阶段实际上是为了训练模型,使其适合其他任务。假设有一个已经标注的语料库C,假设每个文本由多个token序列$x_1,…,x_m$组成,target是y,该阶段的目标函数可以抽象地用下面的式子表示

$$
L_2(C) = \sum_{x,y}{log⁡P(y|x_1,…,x_m )}
= \sum_{x,y}{\log⁡ softmax(h_l^m W_y)}
$$

上式W是加在最后一层Trm后的全连接层,是该阶段的训练参数。

一图胜千言,论文中给出了一张图,左边表示模型的结构,右边表示各种任务。

可以看到模型结构部分的输出有两部分,分别对应上面说到的无监督和有监督训练。而为了更好的训练效果,在有监督训练阶段还会使用无监督的目标函数,让模型“不忘初心”。

$$ L_3 (C) = \lambda \times L_1(C) + L_2(C) $$

GPT-2结构貌似和GPT相比没有太大的区别,就增加了Layer Normalization和权重初始化方式。

ERNIE

XLNet(2019年6月)

在提出XLNet的论文中,作者分析了BERT成功的原因:自编码模型(AE)能更好地利用上下文信息。但同时,作者也指出了BERT的缺陷:pre-training阶段引入的[mask]在fine-tuning阶段没有用到,这实际上会影响BERT的性能。基于这一点,作者提出了XLNet,其核心思想可以概括为:__一个用类似AE的方式做预训练的AR模型__。

Permutation Language Model

为了让AR模型同时看到上下文,作者提出了permutation LM。假设有一个句子序列(a,b,c,d,e),并且d是待预测词,那么做法就是将d固定但将其他词打乱,假设现在得到了(b,e,a,d,c),那么使用AR模型预测d这个词的时候就有一定几率看到下文了。这么做确实弥补了AR模型偏袒上文的缺点,但是却引入了另一个问题——句子序列退化成了词袋模型。在BERT中是用position embedding解决这个问题的,XLNet却用了另一种解决方案。作为对比,传统AR模型,比如Trm等,预测当前位置的概率采用的是简单直接的Softmax
$$
p_{\theta}(X_{z_t} = x | x_{z_{<t}}) = \frac{\exp⁡(e(x)^T h_{\theta}(x_{z<t}))}
{\sum_{x^′}{\exp⁡(e(x^′)^T h_{\theta}(x_{z<t}))}}
$$

而XLNet采用的则是下面的概率:
$$
p_{\theta}(X_{z_t} = x | x_{z_{<t}}) = \frac{\exp⁡(e(x)^T g_{\theta}(x_{z<t},z_t))}
{\sum_{x^′}{\exp⁡(e(x^′)^T g_{\theta}(x_{z<t},z_t))}}
$$

也就是提出了一种新的位置表示方式,这样即使经过重排列,原位置信息还是能被包含在内。这样,XLNet就能在同时看到上下文的时候不受重排列的影响了。顺便说一下,虽然直接对原句子排列省时省力,但是XLNet吃的数据中,句子序列还是原来的顺序,只不过在用Trm提取信息前用一层mask将数据处理了一下,使其在Trm眼中就像经过了排列那样。以排列(3,2,4,1)为例,这个mask可以长这样,有颜色的表示“可以看到”,空白表示“看不到”。

然后将模型展开后,不同位置能看到的信息就像下面这张图一样

Two-stream Self-Attention

但是这里还存在一个问题,以上图为例,当模型要预测x3这个位置的词时,x3自身不应该作为模型的上下文信息被输入,否则输入啥输出啥的模式训练出来的模型不work。如果不将x3输入,那么x3的第1层隐含层信息$h_3^{(1)}$中就不包括x3了,可是x3作为序列(3,2,4,1)中的第一个token,后面的token都等着吃x3的信息呢,如果$h_3^{(1)}$中不包含x3的信息,那么之后的位置就无法提取有效的上下文信息!

这样一方面不能让看到“自身”,又要让模型target-aware,矛盾双方牵扯出一种解决思路——two-stream,即其中一条路包含“自身”,另一条路不包含“自身”。其实上图中h那条路包含自身信息,这条stream被称为content-stream,这条路实际上就是最基础的attention;而g那条路不包含自身信息,被称为query-stream。

$$
g_{z_t}^{(m)} = Attention\left( Q=g_{z_t}^{(m-1)},KV=h_{Z_{<t}}^{(m-1)} \right)
$$

$$
h_{z_t}^{(m)} = Attention\left( Q=h_{z_t}^{(m-1)},KV=h_{Z_{\le t}}^{(m-1)} \right)
$$

上面两个式子中,query stream中包含位置信息$z_t$但不包含$x_{z_t}$;而content stream同时包含位置信息$z_t$和$x_{z_t}$。

其实个人感觉permutation LM会因为token的顺序多变导致训练困难,而作者也在论文中提到了训练的技巧,那就是只预测句子后后半部分,这样做可以减小训练难度,也可以节约时间空间。

RoBERTa(2019年7月)

CTRL(2019年9月)

ALBERT(2019年9月)

ALBERT是谷歌发布的轻量级BERT模型,比BERT模型参数小18倍,性能还超越了它,在SQuAD和RACE测试上创造了新的SOTA。ALBERT主要是三个方面的工作:

分解矩阵

说得专业一些就是 __Factorized embedding parameterization__。在BERT中,词向量维度E和隐含层维度H是相等的,而作者认为预训练模型的重点是在训练模型提取上下文的能力上,而不需要花太多空间在“上下文无关”的词向量上,因此ALBERT中E<<H,但为了保证之后计算过程中维度的一致性,必须添加一个隐含层,将E维词向量映射回H维。更直白一些就是将原本VH的矩阵分解为VE和E*H两个矩阵,并且只要E足够小,这个空间就被省下来了。(⊙ˍ⊙)真是朴素……

那么这个操作能省下多少空间呢?假设词典大小是3万,BERT-large中E和H都是1024维,那么参数量大概是30000*1024=30720000。而ALBERT-large的E是128维,H保持不变,那么参数量为30000*128+128*1024=3971072。两者相差26748928,大概是27M,并没有达到18倍的参数量减小。就算加上position embedding,所节省的空间也大致如此,光靠分解矩阵节省的空间是很有限的,作者一定用了其他节省空间的方法。

参数共享

有一种针对Transformer的改进方式是使用单独一个Trm单元,然后让其在时间尺度上展开,使其具有和RNN一样的结构,这种改进后的模型称为Universal Transformer。ALBERT也用了类似的思想,但是并不是在时间尺度上,而是在模型深度上共享单元。具体分为三种模式:all-shared、shared-attention、shared-FFN。

如果分享模式是all-shared,那么模型相当于由12个完全相同的层堆叠而成,显而易见这样做能节省大量的空间。但问题是这样的模型能work吗?上面给出的实验结果已经给出了答案,all-shared模型相比于原先的模型在各种测试下会有轻微的性能下滑,但是相比于节省的空间,这种下滑还是值得的。另外注意到shared-attention模型不仅减小了参数量,甚至在不少任务下还有性能的提升。

句间连贯性损失

BERT预训练使用NSP(next-sentence prediction)损失函数,其用于判断一个句子对中的两个句子是否是语义连续的。具体来说,NSP是一个二分类任务,其中每个正例是由两句连续的句子组成,而每个负例由来自不同文章的两个句子构成。BERT使用这样的损失函数是希望帮助可以其在自然语言推理任务上获得更好的性能。但是ALBERT的作者认为NSP太过简单,因为预测主题比预测连贯性更容易,所以模型更可能是通过判断两个句子的主题间接地预测了连贯性。ALBERT采用的SOP(sentence-order prediction)就是再NSP基础上对负例的构造做了小改进,既然模型会偷懒选择预测主题,那么只要是来自相同主题的两个句子,按照错误的顺序排列就可以构成一个负例。又是朴素的思想ㄟ( ▔, ▔ )ㄏ

作者最后给出了BERT和ALBERT在各种任务上的表现

可以看到ALBERT-base因为参数量小,因此和BERT最好的模型——BERT-large有比较大的性能差距,但是ALBERT-large的表现和BERT-large相似,考虑到ALBERT-large将近18倍的“瘦身”以及6.5倍的加速,可以认为ALBERT模型还是很成功的。或许是选用了更合适下游任务的损失函数,ALBERT在阅读理解任务RACE上的表现有较大的提升,或者反过来说明BERT的损失函数选的不好?此外,比较BERT和ALBERT在参数量增加后性能提升的趋势可以看出,ALBERT至少还是存在提升的潜力的。

Reformer(2020)

AdaBERT(2020)

参考

Transformer-XL

XLNet

RoBERTa

  • Liu, Y., Ott, M., Goyal, N., Du, J., Joshi, M., Chen, D., … Stoyanov, V. (2019). RoBERTa: A Robustly Optimized BERT Pretraining Approach. (1). Retrieved from http://arxiv.org/abs/1907.11692

ALBERT

Reformer

AdaBERT

其他