- 什么是 XLNet
XLNet 是一个类似 BERT 的模型,而不是完全不同的模型。总之,XLNet 是一种通用的自回归预训练方法。它是 CMU 和 Google Brain 团队在 2019 年 6 月份发布的模型,最终,XLNet 在 20 个任务上超过了 BERT 的表现,并在 18 个任务上取得了当前最佳效果(state-of-the-art),包括机器问答、自然语言推断、情感分析和文档排序。
作者表示,BERT 这样基于去噪自编码器的预训练模型可以很好地建模双向语境信息,性能优于基于自回归语言模型的预训练方法。然而,由于需要 mask 一部分输入,BERT 忽略了被 mask 位置之间的依赖关系,因此出现预训练和微调效果的差异(pretrain-finetune discrepancy)。
基于这些优缺点,该研究提出了一种泛化的自回归预训练模型 XLNet。XLNet 可以:
- 通过最大化所有可能的因式分解顺序的对数似然,学习双向语境信息;
- 用自回归本身的特点克服 BERT 的缺点;
此外,XLNet 还融合了当前最优自回归模型 Transformer-XL 的思路。
自回归语言模型(Autoregressive LM)
在 ELMO/BERT 出来之前,大家通常讲的语言模型其实是根据上文内容预测下一个可能跟随的单词,就是常说的自左向右的语言模型任务,或者反过来也行,就是根据下文预测前面的单词,这种类型的 LM 被称为自回归语言模型。GPT 就是典型的自回归语言模型。ELMO 尽管看上去利用了上文,也利用了下文,但是本质上仍然是自回归 LM,这个跟模型具体怎么实现有关系。ELMO 是做了两个方向(从左到右以及从右到左两个方向的语言模型),但是是分别有两个方向的自回归 LM,然后把 LSTM 的两个方向的隐节点状态拼接到一起,来体现双向语言模型这个事情的。所以其实是两个自回归语言模型的拼接,本质上仍然是自回归语言模型。
自回归语言模型有优点有缺点:
缺点是只能利用上文或者下文的信息,不能同时利用上文和下文的信息,当然,貌似 ELMO 这种双向都做,然后拼接看上去能够解决这个问题,因为融合模式过于简单,所以效果其实并不是太好。
优点其实跟下游 NLP 任务有关,比如生成类 NLP 任务,比如文本摘要,机器翻译等,在实际生成内容的时候,就是从左向右的,自回归语言模型天然匹配这个过程。而 Bert 这种 DAE 模式,在生成类 NLP 任务中,就面临训练过程和应用过程不一致的问题,导致生成类的 NLP 任务到目前为止都做不太好。
- 自编码语言模型(Autoencoder LM)
自回归语言模型只能根据上文预测下一个单词,或者反过来,只能根据下文预测前面一个单词。相比而言,Bert 通过在输入 X 中随机 Mask 掉一部分单词,然后预训练过程的主要任务之一是根据上下文单词来预测这些被 Mask 掉的单词,如果你对 Denoising Autoencoder 比较熟悉的话,会看出,这确实是典型的 DAE 的思路。那些被 Mask 掉的单词就是在输入侧加入的所谓噪音。类似 Bert 这种预训练模式,被称为 DAE LM。
这种 DAE LM 的优缺点正好和自回归 LM 反过来,它能比较自然地融入双向语言模型,同时看到被预测单词的上文和下文,这是好处。缺点是啥呢?主要在输入侧引入 [Mask] 标记,导致预训练阶段和 Fine-tuning 阶段不一致的问题,因为 Fine-tuning 阶段是看不到 [Mask] 标记的。DAE 吗,就要引入噪音,[Mask] 标记就是引入噪音的手段,这个正常。
XLNet 的出发点就是:能否融合自回归 LM 和 DAE LM 两者的优点。就是说如果站在自回归 LM 的角度,如何引入和双向语言模型等价的效果;如果站在 DAE LM 的角度看,它本身是融入双向语言模型的,如何抛掉表面的那个 [Mask] 标记,让预训练和 Fine-tuning 保持一致。当然,XLNet 还讲到了一个 Bert 被 Mask 单词之间相互独立的问题。
- XLNet 模型
4.1 排列语言建模(Permutation Language Modeling)
Bert 的自编码语言模型也有对应的缺点,就是 XLNet 在文中指出的:
- 第一个预训练阶段因为采取引入 [Mask] 标记来 Mask 掉部分单词的训练模式,而 Fine-tuning 阶段是看不到这种被强行加入的 Mask 标记的,所以两个阶段存在使用模式不一致的情形,这可能会带来一定的性能损失;
- 另外一个是,Bert 在第一个预训练阶段,假设句子中多个单词被 Mask 掉,这些被 Mask 掉的单词之间没有任何关系,是条件独立的,而有时候这些单词之间是有关系的。
上面两点是 XLNet 在第一个预训练阶段,相对 Bert 来说要解决的两个问题。
其实思路也比较简洁,可以这么思考:XLNet 仍然遵循两阶段的过程,第一个阶段是语言模型预训练阶段;第二阶段是任务数据 Fine-tuning 阶段。它主要希望改动第一个阶段,就是说不像 Bert 那种带 Mask 符号的 Denoising-autoencoder 的模式,而是采用自回归 LM 的模式。就是说,看上去输入句子 X 仍然是自左向右的输入,看到 Ti 单词的上文 Context_before,来预测 Ti 这个单词。但是又希望在 Context_before 里,不仅仅看到上文单词,也能看到 Ti 单词后面的下文 Context_after 里的下文单词,这样的话,Bert 里面预训练阶段引入的 Mask 符号就不需要了,于是在预训练阶段,看上去是个标准的从左向右过程,Fine-tuning 当然也是这个过程,于是两个环节就统一起来。当然,这是目标。剩下是怎么做到这一点的问题。
首先,需要强调一点,尽管上面讲的是把句子 X 的单词排列组合后,再随机抽取例子作为输入,但是,实际上你是不能这么做的,因为 Fine-tuning 阶段你不可能也去排列组合原始输入。所以,就必须让预训练阶段的输入部分,看上去仍然是 x1,x2,x3,x4 这个输入顺序,但是可以在 Transformer 部分做些工作,来达成我们希望的目标。
具体而言,XLNet 采取了 Attention 掩码的机制,你可以理解为,当前的输入句子是 X,要预测的单词 Ti 是第 i 个单词,前面 1 到 i-1 个单词,在输入部分观察,并没发生变化,该是谁还是谁。但是在 Transformer 内部,通过 Attention 掩码,从 X 的输入单词里面,也就是 Ti 的上文和下文单词中,随机选择 i-1 个,放到 Ti 的上文位置中,把其它单词的输入通过 Attention 掩码隐藏掉,于是就能够达成我们期望的目标(当然这个所谓放到 Ti 的上文位置,只是一种形象的说法,其实在内部,就是通过 Attention Mask,把其它没有被选到的单词 Mask 掉,不让它们在预测单词 Ti 的时候发生作用,如此而已。看着就类似于把这些被选中的单词放到了上文 Context_before 的位置了)。
具体实现的时候,XLNet 是用 “双流自注意力模型” 实现的,细节可以参考论文,但是基本思想就如上所述,双流自注意力机制只是实现这个思想的具体方式,理论上,你可以想出其它具体实现方式来实现这个基本思想,也能达成让 Ti 看到下文单词的目标。
这里简单说下 “双流自注意力机制”,一个是内容流自注意力,其实就是标准的 Transformer 的计算过程;主要是引入了 Query 流自注意力,这个是干嘛的呢?其实就是用来代替 Bert 的那个 [Mask] 标记的,因为 XLNet 希望抛掉 [Mask] 标记符号,但是比如知道上文单词 x1,x2,要预测单词 x3,此时在 x3 对应位置的 Transformer 最高层去预测这个单词,但是输入侧不能看到要预测的单词 x3,Bert 其实是直接引入 [Mask] 标记来覆盖掉单词 x3 的内容的,等于说 [Mask] 是个通用的占位符号。而 XLNet 因为要抛掉 [Mask] 标记,但是又不能看到 x3 的输入,于是 Query 流,就直接忽略掉 x3 输入了,只保留这个位置信息,用参数 w 来代表位置的 embedding 编码。其实 XLNet 只是扔了表面的 [Mask] 占位符号,内部还是引入 Query 流来忽略掉被 Mask 的这个单词。和 Bert 比,只是实现方式不同而已。
上面讲的 Permutation Language Model 是 XLNet 的主要理论创新,所以介绍的比较多,从模型角度讲,这个创新还是挺有意思的,因为它开启了自回归语言模型如何引入下文的一个思路,相信对于后续工作会有启发。当然,XLNet 不仅仅做了这些,它还引入了其它的因素,也算是一个当前有效技术的集成体。感觉 XLNet 就是 Bert、GPT 2.0 和 Transformer XL 的综合体变身:
- 首先,它通过 PLM(Permutation Language Model) 预训练目标,吸收了 Bert 的双向语言模型;
- 然后,GPT2.0 的核心其实是更多更高质量的预训练数据,这个明显也被 XLNet 吸收进来了;
- 再然后,Transformer XL 的主要思想也被吸收进来,它的主要目标是解决 Transformer 对于长文档 NLP 应用不够友好的问题。
4.2 Transformer XL
目前在 NLP 领域中,处理语言建模问题有两种最先进的架构:RNN 和 Transformer。RNN 按照序列顺序逐个学习输入的单词或字符之间的关系,而 Transformer 则接收一整段序列,然后使用 self-attention 机制来学习它们之间的依赖关系。这两种架构目前来看都取得了令人瞩目的成就,但它们都局限在捕捉长期依赖性上。
为了解决这一问题,CMU 联合 Google Brain 在 2019 年 1 月推出的一篇新论文《Transformer-XL:Attentive Language Models beyond a Fixed-Length Context》同时结合了 RNN 序列建模和 Transformer 自注意力机制的优点,在输入数据的每个段上使用 Transformer 的注意力模块,并使用循环机制来学习连续段之间的依赖关系。
4.2.1 vanilla Transformer
为何要提这个模型?因为 Transformer-XL 是基于这个模型进行的改进。
Al-Rfou 等人基于 Transformer 提出了一种训练语言模型的方法,来根据之前的字符预测片段中的下一个字符。例如,它使用 预测字符 ,而在 之后的序列则被 mask 掉。论文中使用 64 层模型,并仅限于处理 512 个字符这种相对较短的输入,因此它将输入分成段,并分别从每个段中进行学习,如下图所示。 在测试阶段如需处理较长的输入,该模型会在每一步中将输入向右移动一个字符,以此实现对单个字符的预测。
该模型在常用的数据集如 enwik8 和 text8 上的表现比 RNN 模型要好,但它仍有以下缺点:
- 上下文长度受限:字符之间的最大依赖距离受输入长度的限制,模型看不到出现在几个句子之前的单词。
- 上下文碎片:对于长度超过 512 个字符的文本,都是从头开始单独训练的。段与段之间没有上下文依赖性,会让训练效率低下,也会影响模型的性能。
- 推理速度慢:在测试阶段,每次预测下一个单词,都需要重新构建一遍上下文,并从头开始计算,这样的计算速度非常慢。
4.2.2 Transformer XL
Transformer-XL 架构在 vanilla Transformer 的基础上引入了两点创新:循环机制(Recurrence Mechanism)和相对位置编码(Relative Positional Encoding),以克服 vanilla Transformer 的缺点。与 vanilla Transformer 相比,Transformer-XL 的另一个优势是它可以被用于单词级和字符级的语言建模。
引入循环机制
与 vanilla Transformer 的基本思路一样,Transformer-XL 仍然是使用分段的方式进行建模,但其与 vanilla Transformer 的本质不同是在于引入了段与段之间的循环机制,使得当前段在建模的时候能够利用之前段的信息来实现长期依赖性。如下图所示:
在训练阶段,处理后面的段时,每个隐藏层都会接收两个输入:
- 该段的前面隐藏层的输出,与 vanilla Transformer 相同(上图的灰色线)。
- 前面段的隐藏层的输出(上图的绿色线),可以使模型创建长期依赖关系。
这两个输入会被拼接,然后用于计算当前段的 Key 和 Value 矩阵。
该方法可以利用前面更多段的信息,测试阶段也可以获得更长的依赖。在测试阶段,与 vanilla Transformer 相比,其速度也会更快。在 vanilla Transformer 中,一次只能前进一个 step,并且需要重新构建段,并全部从头开始计算;而在 Transformer-XL 中,每次可以前进一整个段,并利用之前段的数据来预测当前段的输出。
相对位置编码
在 Transformer 中,一个重要的地方在于其考虑了序列的位置信息。在分段的情况下,如果仅仅对于每个段仍直接使用 Transformer 中的位置编码,即每个不同段在同一个位置上的表示使用相同的位置编码,就会出现问题。比如,第 i−2i-2i−2 段和第 i−1i-1i−1 段的第一个位置将具有相同的位置编码,但它们对于第 iii 段的建模重要性显然并不相同(例如第 i−2i-2i−2 段中的第一个位置重要性可能要低一些)。因此,需要对这种位置进行区分。
论文对于这个问题,提出了一种新的位置编码的方式,即会根据词之间的相对距离而非像 Transformer 中的绝对位置进行编码。从另一个角度来解读公式的话,可以将 attention 的计算分为如下四个部分:
- 基于内容的 “寻址”,即没有添加原始位置编码的原始分数。
- 基于内容的位置偏置,即相对于当前内容的位置偏差。
- 全局的内容偏置,用于衡量 key 的重要性。
- 全局的位置偏置,根据 query 和 key 之间的距离调整重要性。
5) XLNet 与 BERT 比较
尽管看上去,XLNet 在预训练机制引入的 Permutation Language Model 这种新的预训练目标,和 Bert 采用 Mask 标记这种方式,有很大不同。其实你深入思考一下,会发现,两者本质是类似的。
区别主要在于:
- Bert 是直接在输入端显示地通过引入 Mask 标记,在输入侧隐藏掉一部分单词,让这些单词在预测的时候不发挥作用,要求利用上下文中其它单词去预测某个被 Mask 掉的单词;
- 而 XLNet 则抛弃掉输入侧的 Mask 标记,通过 Attention Mask 机制,在 Transformer 内部随机 Mask 掉一部分单词(这个被 Mask 掉的单词比例跟当前单词在句子中的位置有关系,位置越靠前,被 Mask 掉的比例越高,位置越靠后,被 Mask 掉的比例越低),让这些被 Mask 掉的单词在预测某个单词的时候不发生作用。
所以,本质上两者并没什么太大的不同,只是 Mask 的位置,Bert 更表面化一些,XLNet 则把这个过程隐藏在了 Transformer 内部而已。这样,就可以抛掉表面的 [Mask] 标记,解决它所说的预训练里带有 [Mask] 标记导致的和 Fine-tuning 过程不一致的问题。至于说 XLNet 说的,Bert 里面被 Mask 掉单词的相互独立问题,也就是说,在预测某个被 Mask 单词的时候,其它被 Mask 单词不起作用,这个问题,你深入思考一下,其实是不重要的,因为 XLNet 在内部 Attention Mask 的时候,也会 Mask 掉一定比例的上下文单词,只要有一部分被 Mask 掉的单词,其实就面临这个问题。而如果训练数据足够大,其实不靠当前这个例子,靠其它例子,也能弥补被 Mask 单词直接的相互关系问题,因为总有其它例子能够学会这些单词的相互依赖关系。
当然,XLNet 这种改造,维持了表面看上去的自回归语言模型的从左向右的模式,这个 Bert 做不到,这个有明显的好处,就是对于生成类的任务,能够在维持表面从左向右的生成过程前提下,模型里隐含了上下文的信息。所以看上去,XLNet 貌似应该对于生成类型的 NLP 任务,会比 Bert 有明显优势。另外,因为 XLNet 还引入了 Transformer XL 的机制,所以对于长文档输入类型的 NLP 任务,也会比 Bert 有明显优势。
- 代码实现
- 参考文献
作者:@mantchs
GitHub:github.com/NLP-LOVE/ML…