Transformer 知识点理解

BERT是Bidirectional Encoder Representations from Transformers的简称,该框架一出,引起了轩然大波,在11项NLP领域的任务中取得了state-of-the-art的结果。顾名思义,这其实是基于Transformer模型的Encoder表征。其实通俗一点来说,我们可以把它理解成某种功能强大又好用的词向量。既然BERT是一个基于transformer框架的预训练模型,我们不妨先来解构transformer。

Transformer模型在Google论文“Attention Is All You Need”中首次被提出。下图就是Transformer的整体框架图:



初看该模型架构,确实有点复杂,各种圈圈,框框加箭头让人有点懵。

其实细细看来,其并未脱离seq2seq的Encoder和Decoder大框架。左半部分的Nx方框是Encoder过程,右半部分的Nx方框为Decoder过程。而方框内的新内容就是Multi-Head Attention,再加上Input Embedding和Nx方框中间的Positional Encoding,其余并没有新知识点。

Decoder部分和Encoder部分的架构很相似,但也有两处细节有所不同,一是最下层的Multi-Head Attention部分被换成了Masked Multi-Head Attention,二是decoder多出一层的Multi-Head Attention底下的箭头来源不一样。

首先来看Encoder的细节部分。

上左图是Scaled Dot-Product Attention的过程,也就是self-attention的核心过程;右图是多头并行机制。先来看左图,Q,K通过矩阵相乘后,经过Scale(也就是除以 \sqrt{d_{k}} )过程后经softmax归一化处理后再与V进行矩阵相乘,结果就是self-attention的输出。公式如下:

1、Q,K,V是什么?

这里的Q,K,V是什么呢?(原文没有直接给出解释,具体可参考另一篇博文,文章有详细的解释:jalammar.github.io/illu 或者直接翻看transformer代码。) 其实很简单,Q,K,V都来自于句子词嵌入X(word embedding + position embedding)的矩阵变换。

既然Q,K,V都来自于原始句子的序列(这也就是为啥会叫self-attention了,就是自己跟自己做attention嘛--),不禁要问为什么经过这一番self-attention就能work呢?不妨先回忆一下基本的基于attention的seq2seq框架(不熟悉的童鞋可以参考之前的笔记:zhuanlan.zhihu.com/p/54)。

2、 attention与 Self-attention 比较

在Encoder过程,句子的token序列依次进入RNN模型并依次输出 h_{1}…h_{N} 隐状态序列。为方便描述,记隐状态序列为H。Decoder过程接收来自Encoder的最后一个隐状态 h_{N}

和句首信息<SOS>的embedding作为第一个输入并产生隐状态 s_{1} ,H与 s_{1} 矩阵相乘得到相似性向量,该向量经过Softmax归一化与H矩阵相乘就得到结果 c_{1} 。用Q,K,V的思路重新整理一下该过程如下:

Q代表Queries,K代表Keys,V就是Values。由于一般attention过程中Q是逐个与K,V进行矩阵变换的,所以这边记为小写q。

该过程的意思很简单,就是q和K中的各元素进行相似性比对得到Scores向量(上图e1,…,e5序列),经过softmax归一化得到权重向量(\alpha_{1},…,\alpha_{5} )。通过V和权重向量矩阵相乘就可以得到结果c1。

注意力机制的原理是根据所关心的问题(即q)的不同,对句子单词序列(即K)所分配的注意力也不一样。所以根据不同的q和K序列中各元素(k1,…,k5)的相似性,产生的c包含相应比例的V序列(v1,…,v5)的信息。此处的K和V是完全一致的,都来自Encoder的隐状态输出H。

那么对于Self-attention机制来说,Q,K,V均由词嵌入X的矩阵变换得到,本质上和一般的attention机制没有实质区别。简图如下:



如果我们把Q中序列单独拿出来看,q1和 K^{T} 矩阵相乘经scale和softmax过程,再和V矩阵相乘得到c1。这个过程是和attention过程一模一样的。经过这一番变换,输出c1不仅包含单词x1自身的信息,也包含了不同比例的其他单词的信息。而self-attention与一般attention很大的区别就是可以一次完成整个单词序列的attention工作,在效率上有大幅提升。除了可以并行处理输出,Self-attention另一个优点是可以克服长距离依赖的问题。

众所周知,LSTM虽然能在一定程度上解决长距离依赖的问题,但随着句子长度的增加,会给后续优化带来很多困难。而self-attention没有这个问题,因为self-attention模型中,任意两个单词的距离都为1。怎么理解呢,RNN模型中t时刻的输出包含不同比例t-1时刻的信息,该模型是顺序型的模型,自然带有位置信息。而self-attention模型是并行模型,句子序列中第一个单词和最后一个单词同时经过K,V矩阵变换,从而得到输出结果,是不具有位置概念的,所以任意两个单词的距离都一样。

但是这也带来了另一个问题,如果没有位置信息,我们任意颠倒一句话得到的输出都是一样的。先来体会一下没有位置概念的意思,我们把上图c1补充完整,根据公式:

现在,我们颠倒单词的顺序,我们让K序列为(k2,k1,k3,k5,k4),相应的V序列为(v2,v1,v3,v5,v4),K和V是键值对,所以它们是对应的。我们再来计算q1所对应的结果c1,可以得到:

整理一下,就会发现两个c1是完全一致的。这显然不是我们想要的结果。我们知道单词顺序对于理解一句话是非常重要的,比如:“我吃鸡” 和 “鸡吃我” 这能是一回事吗?

3、 位置编码

为了解决这个问题,谷歌采用加入位置编码的方式。这就是让人困惑不已的位置编码公式了:

pos表示该词的在句子序列中的实际位置,i表示词向量的第i个维度, d_{model} 是词向量的维度为512。位置的偶数维采用正弦公式,奇数维采用余弦公式。这样的编码方式既可以表示该词的绝对位置,也能表示相对位置。三角函数为什么能捕捉到相对位置信息依赖于以下两个公式:


对于单词序列的位置偏移k, PE_{(pos+k)} 可以表示成 PE_{(pos)}PE_{(k)} 的线性组合。

对于特定的偏移量k,PE_{(k)}的结果用实数a,b来表示。有了位置编码,self-attention机制就能表达词序信息啦。

4、 多头机制(Multi-Head Attention)

理解了单头机制,再来看多头机制就不复杂了。论文中采用8头并行机制。



上述公式表明所谓的多头机制,就是将高维的Q,K,V向量通过矩阵变换转换为一些低维的向量(q,k,v)。

对应其中一头 head_{i} = Attention(q, k, v),最后将各单头结果拼接。论文中采用8头并行,

模型的Encoder部分的知识点解释的差不多,再注意一点,Encoder中Q,K,V都来自一个地方,最开始来自于句子的 词嵌入+位置编码。


再来看Decoder部分。

上面我们也说过,Decoder在两处跟Encoder有区别,分别来看。

5、 Mask机制

Mask机制有两种,一种叫padding mask,作用是使每一批次的句子长度一致。Padding mask在所有的self-attention中都会用到,不管是Encoder还是Decoder中。另一种叫sequence mask,是Decoder的self-attention中特有的mask。

Sequence mask

Sequence mask的目的是使decoder过程不能看到未来信息。这很好理解,因为解码的时候我们是根据之前的信息逐个推导序列中的单词的。如果提前看到解码序列,我们还解啥码。

但是这儿也有个疑点,我们知道seq2seq框架中,单词是逐个逐个被解码出来的,在t时刻,我们只能拥有t时刻之前的信息,既然如此,为什么还会需要加一个mask操作呢?搜索了好多文章都没有关于这方面的解释,只能查代码看个究竟了。

原来transformer模型训练的时候,直接把ground truth整个序列作为decoder端的输入,这样当然需要掩码操作了,终于恍然大悟。训练时一次性解码,这也是与RNN架构的一大区别吧。当然在预测过程,还是像一般seq2seq的decoder过程一样是逐个解码的。

Sequence mask 具体操作:



作一个上三角为1,其余值全为0的矩阵。将该矩阵作用于self-attention矩阵,值为0的位置不作处理,仍然是self-attention的输出值;值为1的位置用-np.inf替换。这样经过softmax过程,-np.inf的值为0。

6、 Decoder 与 Encoder的attention

Decoder过程中,比Encoder多了一次attention操作:

相比于其他部分的Multi-Head attention方框下的箭头均来自同一处,这部分两个箭头来自Encoder过程,另一个箭头来自Decoder上一层输出。论文中说了,该部分的attention就是seq2seq框架中一般的attention过程。上文我们也解读过这一过程,所以这边就很好理解了,来自Encoder的两个箭头分别代表K、V,他们都来自于Encoder output的矩阵变换。另一个箭头代表Q,来自Decoder过程的self-attention

以上几点是个人的解读,如有不对的地方欢迎指正。谢谢!

发布于 2019-03-01