深度学习:前沿技术-XLNet
文章目录
欢迎转载,作者:Ling,注明出处:深度学习:前沿技术-XLNet
简介
XLNet通过改进深度学习在自然语言处理中典型的两阶段学习的预训练语言模型阶段(Pretrained),来提高深度学习在自然语言处理各项任务中的性能。它综合了自回归语言模型(Autoregressive LM)和自编码语言模型(Autoencoder LM)各自的优势,结合了Transformer-XL在长句子/篇章方面的优势,以及Permutation Language Model在双向语言模型的优势,在20项自然语言处理任务上都得到了显著的改进。
详解
在理解XLNet之前,我们需要引入两个概念:自回归语言模型(Autoregressive LM)和自编码语言模型(Autoencoder LM)。
自回归语言模型
定义:自回归语言模型是大家通常讲的语言模型,它根据上文内容预测下一个可能跟随的单词,即自左向右的语言模型任务,或者反过来,根据下文预测前面的单词。
典型技术:GPT, ELMO(本质上是两方向的自回归简单拼接结合)。
优点:和下游NLP任务有关,比如生成类NLP任务,文本摘要,机器翻译等,在实际生成内容的时候,都是从左向右,自回归语言模型天然匹配这个过程。而自编码语言模型和这个过程不匹配。
缺点:只能利用上文或者下文的信息,或者像ELMO简单两方向结合。
自编码语言模型
定义:自编码语言模型是通过在输入X中随机Mask掉一部分单词,然后在预训练过程中根据上下文单词来预测这些被Mask掉的单词。该做法类似Denoising Autoencoder(DAE)的思路。那些被Mask掉的单词即为在输入侧加入的噪音。
典型技术:BERT。
优点:同时利用利用上下文信息,双向语言模型。
缺点:
- 输入侧引入[Mask]标记,导致预训练阶段和Fine-tuning阶段不一致,因为Fine-tuning阶段看不到[Mask]标记。
- 独立假设问题:举个例子:比如”New York is a city”,假设我们Mask住”New”和”York”两个词,那么给定”is a city”的条件下”New”和”York”并不独立,因为”New York”是一个实体,看到”New”则后面出现”York”的概率要比看到”Old”后面出现”York”概率要大得多。所以同时Mask 15% 的词不是好的做法。
- 和生成类NLP任务从左到右的思路不匹配。
通过上面介绍,我们知道,自回归和自编码语言模型都有各自的优缺点,XLNet希望将两者结合,克服各自的缺点:
- 使用自回归语言模型,以更好匹配下游任务。
- 不在输入侧使用Mask,以使得预训练和Fine-tuning阶段一致,但是又可以使用上下文信息,实现双向语言模型。
XLNet如何做到以上两点:
排列语言建模(Permutation Language Modeling),其背后是通过双流自注意力机制(Two-Stream Self-Attention)和Attention Mask实现。
排列语言模型(Permutation Language Model)
举个例子:
我们有一个句子X,有四个单词构成,顺序是:x_{1}x_{2}x_{3}x_{4}
, 此时如果我们要预测单词是x_{3}
, 如果按照常规自回归做法,应该用x_{1}x_{2}
预测x_{3}
, 这样就只有上文信息,没有下文信息。如果我们用排列语言建模的方法,可以有4!种排列,其中一种排列为图中左下子图所示:1->4->2->3, 此时如果按照自回归预测x_{3}
,会用到x_{1},x_{2},x_{4}
的信息,即原始输入的上下文信息。如果我们训练的时候,各种排列都训练一遍,这样就能保证预测每个词,所有上下文信息都可以用到。
换一种说法,传统自回归语言模型只能按顺序猜词,比如先”猜”一个词,然后根据第一个词”猜”第二个词,根据前两个词”猜”第三个词,……。而排列语言模型会学习各种顺序的猜测方法,比如上面的最后一个式子对应的顺序3→1→2,它是先”猜”第三个词,然后根据第三个词猜测第一个词,最后根据第一个和第三个词猜测第二个词。
注意,对于一个长度为T的序列,我们可以遍历T!种路径,然后学习语言模型的参数,但是这个计算量非常大(10!=3628800,10个词的句子就有这么多种组合)。因此实际我们只能随机的采样T!里的部分排列。
形式化表示:
ZT表示长度为T的序列的所有排列组成的集合,则z∈ZT是一种排列方法。我们用zt表示排列的第t个元素,而z<t表示z的第1到第t-1个元素。
举个例子,假设T=3,那么ZT共有6个元素,我们假设其中之一z=[1,3,2],则z3=2,而z<3=[1,3]。
有了上面的记号,则排列语言模型的目标是调整模型参数使得下面的似然概率最大:
上面的公式看起来有点复杂,细读起来其实很简单:从所有的排列中采样一种,然后根据这个排列来分解联合概率成条件概率的乘积,然后加起来。
当然,在实现的时候,我们不会真正对输入的单词进行重新排列,而是通过在Transformer内部进行Attention Mask实现排列。比如p(x1|x3)p(x2|x1x3)p(x3),我们可以在用Transformer编码x1时候让它可以Attend to x3,而把x2Mask掉 (意思就是算Attention score的时候只算x3对x1的影响,而x2的attention score为0);编码x3的时候把x1,x2都Mask掉。
为了实现排列语言模型,论文采用了双流自注意力机制(Two-Stream Self-Attention)和Attention Mask。
双流自注意力机制(Two-Stream Self-Attention)
在介绍什么是双流自注意力机制前,我们先来看两个例子。
例子一:
输入句子:我 喜欢 自然 语言 处理,我们排列语言模型的一个排列是4->2->5->1->3,表示,我先预测第二个位置的单词,然后预测第五个位置单词,以此类推。
在预测位置2的内容(单词)时,输入为位置(“2”),不能含有内容信息(“喜欢”),和上一个单词的完全信息,包括内容(“语言”)和位置(“4”),
在预测位置5的内容时,输入为位置(“5”),不能含有内容信息(“处理”),和之前所有信息,(喜欢,2),(语言,4)。
从该例子可以看出,在预测当前位置的输出时,需要输入之前的所有信息,包括内容和位置,而当前位置只能提供位置信息,不能提供内容信息。作者原话为:「新任务希望在预测下一个词时只能提供位置信息,不能提供内容相关的信息。因此模型希望同时做两件事,首先它希望预测自己到底是哪个字符,其次还要能预测后面的字符是哪个。」
为能够实现该场景,我们需要双流自注意力机制。
例子二:
在理解论文中的图前,我们再看一个例子,假设整句话为 ["我 1", "今天 2", "很 3",「开心 4」],我们只采样出一个样本 (["今天 2", "很 3", "开心 4"] → "我 1" ),XLNet 的做法和 BERT 有同有异。
假设还没做排列:
我们目标是用234预测1。此时,将“我”替换成一个特殊字符 "MASK",用它对应的词向量,同时加上位置向量,得到G,作为Query,X2,X3,X4(包含词向量和位置向量信息)作为Key和Value,通过transformer的self attention(Key*Query然后softmax得到attention score,然后乘以Value得到相应输入贡献的值)得到G1(可以用它推测内容)。
注意:G包含了特殊单词[MASK]向量和位置向量,X包含了单词内容向量和位置向量。
我们再看完整的:
计算输出用到的输入如下(冒号前为输出,冒号后为输入):
G1: 我G,今天X2,很X3,开心X4
H1:我X1,今天X2,很X3,开心X4
G2: 我X1,今天G,很X3,开心X4
H2:我X1,今天X2,很X3,开心X4
其他同理。G1,G2是一类表征,走的是Query Stream,H1,H2是一类表征,走的是Content Stream,G用了当前节点的位置信息(内容信息用一个特殊字符的向量替代)和其他节点的位置和内容信息得到,H同时用了位置和内容信息得到。这里走了两个Stream,所以叫双流,用了self attention,所以叫双流自注意力机制。
形式化表示如下:
解释:
g_1^{l}
表示位置1,l层输出的G,由上一层的g_1^{l-1}
作为Query,除位置1以外的上一层的h_{j\neq1}^{l-1}
作为Key和Value,通过self attention计算得到。来自Query Stream。h_1^l
表示位置1,l层输出的H,由上一层的h_1^{l-1}
作为Query,所有位置的上一层的h_:^{l-1}
作为Key和Value,通过self attention计算得到。来自Content Stream。Content Stream即为传统Transformer的计算方法,包含了位置和内容向量。
以上计算存在一个问题:标签泄露。如上例子,X1的内容信息传递给H2,H3,H4,而H2,H3,H4又会参与下一层计算位置1的G(假设再加一层在上面),从而泄露了X1的信息给预测位置1的单词,这就是标签泄露。
形式化表示如下:
解决办法:通过注意力掩码(Attention Mask)实现排列。注意力掩码就是根据选定的排列将不合理的注意力权重置零。
形式化表示如下:
解释:
z_{t}
为排列中的第 t 位置(按排列后位置算)z_{1:t-1}
为排列中的第 1个到第t-1 个词g_{z_{t}}^{l}
表示第t位置在l层输出的G,由上一层第t位置的g_{z_{t}}^{l-1}
作为Query,上一层从第1到t-1位置的H,h_{z_{1:t-1}}^{l-1}
作为Key和Value,通过Self Attention计算得到。来自Query Stream。h_{z_t}^l
表示在第t位置在l层输出的H,由上一层第t位置的H,h_{z_t}^{l-1}
作为Query,上一层第1到第t位置的H,h_{z_{1:t}}^{l-1}
作为Key和Value,通过Self Attention计算得到。来自Content Stream。
我们通过三层来看看为什么这样做,可以避免标签泄露问题:
还是用这个例子,排列为2->3->4->1,我们预测1,计算输出用到的输入如下:
G1:我G,今天X2,很X3,开心X4
H1:我X1,今天X2,很X3,开心X4
G2: 今天G
H2:今天X2
G3:今天X2,很G
H3:今天X2,很X3
G4:今天X2,很X3,开心G
H3:今天X2,很X3,开心X4
注意:这一层结果的G2,H2,由于排列的存在和之前的完全不一样。
我们再往后传一层:
G11:G1, H2,H3,H4
H11:H1,H2,H3,H4
其中H2-H4都不含有X1的信息,这样就防止了标签泄露。
结合上面的解释知识,我们就可以分析论文中给出的图:
- 左下图(b)即为求G的Query Stream
- 左上图(a)即为求H的Content Stream
- 右边图(c)为多层叠加,最后一层预测结果,以及给定一个排列,Content Stream和Query Stream通过各自的Attention Mask达到符合给定排列的目的。
- 排列为:3->2->4->1
- e(x)表示相应的word和位置的embedding
- w表示位置和特殊字符Mask的embedding
- Query Stream的Attention Masks表示:第一行是计算
g_1^{(1)}
需要用到$$e(x_2)$,$e(x_3)$,$e(x_4)$$
,因为1前面有324,第二行是计算g_1^{(2)}
需要用到e(x_3)
,因为2前面只有3,以此类推。 - Content Stream的Attention Masks表示:第一行是计算
h_1^{(1)}
需要用到e(x_1)
,e(x_2)
,e(x_3)
,e(x_4)
,因为1前面有324,计算H可以用1234所有内容,其他以此类推。
部分预测
支持长句
同时为了更好的支持长句子或者篇章,XLNet还引入了Transformer-XL的思想:分段(Segment),循环机制和相对位置编码。具体可以参考:Transformer-XL
效果
RACE:阅读理解
SQuAD:阅读理解
GLUE:NLP综合任务
文本分类
信息检索
总结
优点
- 拥有自回归语言模型的优点,和下游任务匹配
- 拥有自编码语言模型优点,双向语言模型
- 克服可修改输入加[Mask]特殊字
缺点
- 需要更强的算力,训练比较慢,Fine-Tuning过程比BERT多5-10倍的时间
- 在我项目中,我用三万corpus训练类似QQP的模型,对比BERT和XLNet,反而是BERT效果更好,可能在QQP和小训练样本的情况下,BERT还是更好一些,另外我对无法遍历所有排列这个做法也存在一定疑问。
参考
- 需要更强的算力,训练比较慢,Fine-Tuning过程比BERT多5-10倍的时间
- 在我项目中,我用三万corpus训练类似QQP的模型,对比BERT和XLNet,反而是BERT效果更好,可能在QQP和小训练样本的情况下,BERT还是更好一些,另外我对无法遍历所有排列这个做法也存在一定疑问。
参考
XLNet: Generalized Autoregressive Pretraining for Language Understanding