作者:Xu LIANG 编译:ronghuaiyang
导读
理解XLNet中的双流自注意力机制。
在我之前的文章什么是XLNet,它为什么比BERT效果好?中,我主要讨论了XLNet (AR语言模型)和BERT (AE语言模型)之间的区别以及重排列语言建模。
我相信对XLNet有一个直观的理解远比实现细节重要,所以我只解释了重排列语言建模,而没有提到另一个重要的部分,双流自注意力架构。但正如陈家明在评论中提到的,双流自注意力是XLNet论文的另一个亮点,所以我写这篇文章是为了尽可能清楚地解释双流自注意力。
内容结构如下。
- 重排列语言建模的快速回顾
- 重排列带来了什么问题?
- BERT有这样的问题吗?
- XLNet如何解决这个问题?
- 注意力mask:XLNet如何实现重排列?
重排列建模的快速回顾
特殊的术语:
- AR语言模型:自回归语言建模
- AE语言模型:自动编码器语言建模
为了使这篇文章更加独立,我在这里做一个简短的总结:什么是XLNet,为什么它的性能优于BERT。
XLNet提出使用重排列语言建模,使AR语言模型学习双向上下文。这样可以避免AE语言模型中MASK方法带来的弊端。
重排列方法是获取一个序列的重排列,并使用之前的t-1
个tokens作为上下文来预测第t个位置的token。例如,我们有一个句子[x1, x2, x3, x4]
,而x3
是我们要预测的第t个位置的token。首先,我们得到句子的排列。
[('x1', 'x2', 'x3', 'x4'),
('x1', 'x2', 'x4', 'x3'),
('x1', 'x3', 'x2', 'x4'),
('x1', 'x3', 'x4', 'x2'),
('x1', 'x4', 'x2', 'x3'),
('x1', 'x4', 'x3', 'x2'),
('x2', 'x1', 'x3', 'x4'),
('x2', 'x1', 'x4', 'x3'),
('x2', 'x3', 'x1', 'x4'),
('x2', 'x3', 'x4', 'x1'),
('x2', 'x4', 'x1', 'x3'),
('x2', 'x4', 'x3', 'x1'),
('x3', 'x1', 'x2', 'x4'),
('x3', 'x1', 'x4', 'x2'),
('x3', 'x2', 'x1', 'x4'),
('x3', 'x2', 'x4', 'x1'),
('x3', 'x4', 'x1', 'x2'),
('x3', 'x4', 'x2', 'x1'),
('x4', 'x1', 'x2', 'x3'),
('x4', 'x1', 'x3', 'x2'),
('x4', 'x2', 'x1', 'x3'),
('x4', 'x2', 'x3', 'x1'),
('x4', 'x3', 'x1', 'x2'),
('x4', 'x3', 'x2', 'x1')]
然后选取一些样本作为训练数据。(本文从排列中随机抽取样本)
代码语言:javascript复制('x1', 'x2', 'x4', 'x3'),
('x1', 'x4', 'x3', 'x2'),
('x2', 'x3', 'x4', 'x1'),
('x4', 'x2', 'x3', 'x1'),
('x3', 'x2', 'x4', 'x1'),
我们可以看到每个token都有机会出现在x3之前。因此,AR模型可以从这些上下文tokens中学习双向信息。如果你仍然不清楚重排列,你可以阅读前面的文章。
重排列带来了什么问题?
这种重排列可以使AR模型从两个方向看到上下文,但也带来了原transformer 无法解决的问题.
重排列语言建模目标:
- Z:一种分解顺序
- p_θ:似然函数
- x_zt:分解顺序中的第t个token
- x_z<t:第t个token之前的所有tokens
这是重排列语言建模的目标函数,即以t-1个tokens为上下文,预测第t个token。
有两个标准Transformer不能满足的要求:
- 为了预测token x_t,模型应该只看到x_t的位置,而不是x_t的content(我将在下一节解释什么是content)
- 为了预测token x_t,模型应该将x_t之前的所有token编码为content
特别是第一个要求,transformer将位置编码合并到token嵌入中。因此,它不能将位置信息与token嵌入分离开来。
BERT有这样的问题吗?
BERT是一个AE语言模型,它不像AR语言模型那样需要单独的位置信息。与XLNet需要位置信息来预测第t个token不同,BERT使用[MASK]来表示要预测哪个token(我们可以认为[MASK]只是一个占位符)。例如,如果BERT使用x2, x1, x4来预测x3,那么x2, x1, x4的嵌入包含了位置信息和其他与[MASK]相关的信息。因此,该模型很有可能预测[MASK]是x3。
在这里我将对信息做更详细的说明。BERT embedded (BERT所学的信息)包含两种信息:位置信息和内容信息(为简单起见,我将其分为两部分)。
位置信息很容易理解,因为它告诉模型当前token的位置。内容信息(语义和语法)包含当前标记的“意义”。一个直观的例子是kind — man woman = queen
。
XLNet怎么解决这个问题?
XLNet提出了双流自注意力来解决这个问题。
顾名思义,它包含两种自注意力。一个是content stream attention,它是Transformer中的标准自注意力。另一个是query stream attention。XLNet引入它来替换BERT中的[MASK] token。
例如,如果BERT想用上下文单词x1和x2的知识来预测x3,它可以使用[MASK]来表示x3 token。[MASK]只是一个占位符。x1和x2的嵌入包含位置信息,帮助模型“知道”[MASK]的是x3。
XLNet的情况有所不同。一个token x3将服务两种角色。当它被用作内容来预测其他标记时,我们可以使用内容表示(通过内容流注意力来学习)来表示x3。但是如果我们想要预测x3,我们应该只知道它的位置而不是它的内容。这就是为什么XLNet使用查询表示(通过查询流注意力来学习)来保留x3之前的上下文信息,只保存x3的位置信息。
为了直观地理解双流自注意力,我们可以认为XLNet用查询表示代替了BERT中的[MASK]。他们只是选择不同的方法做同一件事。
注意力mask:XLNet如何实现重排列?
当我第一次读到这篇文章的时候,我不禁对训练中重排列的实现细节产生了疑惑。如果你们感兴趣,我就简单讲一下。
在第一部分“重排排列语言建模的快速回顾”中,我给出了一个句子[x1, x2, x3, x4]
的排列示例,如下所示。
[('x1', 'x2', 'x3', 'x4'),
('x1', 'x2', 'x4', 'x3'),
('x1', 'x3', 'x2', 'x4'),
('x1', 'x3', 'x4', 'x2'),
('x1', 'x4', 'x2', 'x3'),
('x1', 'x4', 'x3', 'x2'),
('x2', 'x1', 'x3', 'x4'),
('x2', 'x1', 'x4', 'x3'),
('x2', 'x3', 'x1', 'x4'),
('x2', 'x3', 'x4', 'x1'),
('x2', 'x4', 'x1', 'x3'),
('x2', 'x4', 'x3', 'x1'),
('x3', 'x1', 'x2', 'x4'),
('x3', 'x1', 'x4', 'x2'),
('x3', 'x2', 'x1', 'x4'),
('x3', 'x2', 'x4', 'x1'),
('x3', 'x4', 'x1', 'x2'),
('x3', 'x4', 'x2', 'x1'),
('x4', 'x1', 'x2', 'x3'),
('x4', 'x1', 'x3', 'x2'),
('x4', 'x2', 'x1', 'x3'),
('x4', 'x2', 'x3', 'x1'),
('x4', 'x3', 'x1', 'x2'),
('x4', 'x3', 'x2', 'x1')]
我们很容易误解,我们需要获得一个句子的随机顺序并将其输入到模型中。但事实并非如此。输入语句的顺序是[x1, x2, x3, x4]
,XLNet使用注意力掩码来重排列分解因子的顺序。
这个句子的原始顺序是[x1, x2, x3, x4]
。我们随机得到一个分解的顺序为[x3, x2, x4, x1]
。
左上角是内容表示的计算。如果我们想要预测x1的内容表示,我们应该拥有所有4个token内容信息。KV = [h1, h2, h3, h4]
和Q = h1
。
左下角是查询表示的计算。如果我们想要预测x1的查询表示,我们不能看到x1本身的内容表示。KV = [h2, h3, h4]
,Q = g1
。
右下角是整个计算过程。我把它从头到尾解释了一遍。首先,h
和g
被初始化为e(xi)
和w
。在内容掩码和查询掩码之后,双流注意力将输出第一层输出h^(1)
和g^(1)
,然后计算第二层。
注意右边的内容掩码和查询掩码。它们都是矩阵。在内容mask中,第一行有4个红点。这意味着第一个token (x1)可以看到(注意到)所有其他tokens,包括它自己(x3->x2->x4->x1)。第二行有两个红点。这意味着第二个token (x2)可以看到(注意到)两个token(x3->x2)。等等。
内容掩码和查询掩码之间惟一的区别是,查询掩码中的对角元素为0,这意味着token不能看到它们自己。
让我们总结一下。输入的句子只有一个顺序。但是我们可以使用不同的注意力mask来实现不同的分解顺序。
总结
在这篇文章中,我主要解释了XLNet面临的问题是什么,以及如何使用双流自注意力来解决它。我还提到了有关排列注意里mask的一些实现细节。对于结果的比较,你可以从XLNet team中找到最新的发布,它比论文的比较更加公平。
—END—
英文原文:https://towardsdatascience.com/what-is-two-stream-self-attention-in-xlnet-ebfe013a0cf3