《Attention is All You Need》浅读(简介+代码)

https://kexue.fm/archives/4765

2017年中,有两篇类似同时也是笔者非常欣赏的论文,分别是FaceBook的《Convolutional Sequence to Sequence Learning》和Google的《Attention is All You Need》,它们都算是Seq2Seq上的创新,本质上来说,都是抛弃了RNN结构来做Seq2Seq任务。

这篇博文中,笔者对《Attention is All You Need》做一点简单的分析。当然,这两篇论文本身就比较火,因此网上已经有很多解读了(不过很多解读都是直接翻译论文的,鲜有自己的理解),因此这里尽可能多自己的文字,尽量不重复网上各位大佬已经说过的内容。

序列编码 ↺

深度学习做NLP的方法,基本上都是先将句子分词,然后每个词转化为对应的词向量序列。这样一来,每个句子都对应的是一个矩阵X=(x1,x2,…,xt)Xx1x2xt,其中xixi都代表着第ii个词的词向量(行向量),维度为dd维,故X∈ℝn×dXRnd。这样的话,问题就变成了编码这些序列了。

第一个基本的思路是RNN层,RNN的方案很简单,递归式进行:

yt=f(yt−1,xt)ytfyt1xt


不管是已经被广泛使用的LSTM、GRU还是最近的SRU,都并未脱离这个递归框架。RNN结构本身比较简单,也很适合序列建模,但RNN的明显缺点之一就是无法并行,因此速度较慢,这是递归的天然缺陷。另外我个人觉得RNN无法很好地学习到全局的结构信息,因为它本质是一个马尔科夫决策过程。

 

第二个思路是CNN层,其实CNN的方案也是很自然的,窗口式遍历,比如尺寸为3的卷积,就是

yt=f(xt−1,xt,xt+1)ytfxt1xtxt1


在FaceBook的论文中,纯粹使用卷积也完成了Seq2Seq的学习,是卷积的一个精致且极致的使用案例,热衷卷积的读者必须得好好读读这篇文论。CNN方便并行,而且容易捕捉到一些全局的结构信息,笔者本身是比较偏爱CNN的,在目前的工作或竞赛模型中,我都已经尽量用CNN来代替已有的RNN模型了,并形成了自己的一套使用经验,这部分我们以后再谈。

 

Google的大作提供了第三个思路纯Attention!单靠注意力就可以!RNN要逐步递归才能获得全局信息,因此一般要双向RNN才比较好;CNN事实上只能获取局部信息,是通过层叠来增大感受野;Attention的思路最为粗暴,它一步到位获取了全局信息!它的解决方案是:

yt=f(xt,A,B)ytfxtAB


其中A,BAB是另外一个序列(矩阵)。如果都取A=B=XABX,那么就称为Self Attention,它的意思是直接将xtxt与原来的每个词进行比较,最后算出ytyt!

 

Attention层 ↺

Attention定义 ↺

 

Attention

Attention

 

Google的一般化Attention思路也是一个编码序列的方案,因此我们也可以认为它跟RNN、CNN一样,都是一个序列编码的层。

前面给出的是一般化的框架形式的描述,事实上Google给出的方案是很具体的。首先,它先把Attention的定义给了出来:

Attention(Q,K,V)=softmax(QK⊤dk‾‾√)VAttentionQKVsoftmaxQK⊤dkV


这里用的是跟Google的论文一致的符号,其中Q∈ℝn×dk,K∈ℝm×dk,V∈ℝm×dvQRndkKRmdkVRmdv。如果忽略激活函数softmaxsoftmax的话,那么事实上它就是三个n×dk,dk×m,m×dvndkdkmmdv的矩阵相乘,最后的结果就是一个n×dvndv的矩阵。于是我们可以认为:这是一个Attention层,将n×dkndk的序列QQ编码成了一个新的n×dvndv的序列

 

那怎么理解这种结构呢?我们不妨逐个向量来看。

Attention(qt,K,V)=∑s=1m1Zexp(〈qt,ks〉dk‾‾√)vsAttentionqtKVs1m1Zexpqtksdkvs


其中ZZ是归一化因子。事实上q,k,vqkv分别是query,key,valuequerykeyvalue的简写,K,VKV是一一对应的,它们就像是key-value的关系,那么上式的意思就是通过qtqt这个query,通过与各个ksks内积的并softmax的方式,来得到qtqt与各个vsvs的相似度,然后加权求和,得到一个dvdv维的向量。其中因子dk‾‾√dk起到调节作用,使得内积不至于太大(太大的话softmax后就非0即1了,不够“soft”了)。

 

事实上这种Attention的定义并不新鲜,但由于Google的影响力,我们可以认为现在是更加正式地提出了这个定义,并将其视为一个层地看待;此外这个定义只是注意力的一种形式,还有一些其他选择,比如queryquery跟keykey的运算方式不一定是点乘(还可以是拼接后再内积一个参数向量),甚至权重都不一定要归一化,等等。

Multi-Head Attention ↺

 

Multi-Head Attention

Multi-Head Attention

 

这个是Google提出的新概念,是Attention机制的完善。不过从形式上看,它其实就再简单不过了,就是把Q,K,VQKV通过参数矩阵映射一下,然后再做Attention,把这个过程重复做hh次,结果拼接起来就行了,可谓“大道至简”了。具体来说

headi=Attention(QWQi,KWKi,VWVi)headiAttentionQWiQKWiKVWiV


这里WQi∈ℝdk×d̃ k,WKi∈ℝdk×d̃ k,WVi∈ℝdv×d̃ vWiQRdkdkWiKRdkdkWiVRdvdv,然后

MultiHead(Q,K,V)=Concat(head1,...,headh)MultiHeadQKVConcathead1headh


最后得到一个n×(hd̃ v)nhdv的序列。所谓“多头”(Multi-Head),就是只多做几次同样的事情(参数不共享),然后把结果拼接

 

Self Attention ↺

到目前为止,对Attention层的描述都是一般化的,我们可以落实一些应用。比如,如果做阅读理解的话,QQ可以是篇章的词向量序列,取K=VKV为问题的词向量序列,那么输出就是所谓的Aligned Question Embedding

而在Google的论文中,大部分的Attention都是Self Attention,即“自注意力”,或者叫内部注意力。

所谓Self Attention,其实就是Attention(X,X,X)AttentionXXX,XX就是前面说的输入序列。也就是说,在序列内部做Attention,寻找序列内部的联系。Google论文的主要贡献之一是它表明了内部注意力在机器翻译(甚至是一般的Seq2Seq任务)的序列编码上是相当重要的,而之前关于Seq2Seq的研究基本都只是把注意力机制用在解码端。类似的事情是,目前SQUAD阅读理解的榜首模型R-Net也加入了自注意力机制,这也使得它的模型有所提升。

当然,更准确来说,Google所用的是Self Multi-Head Attention:

Y=MultiHead(X,X,X)YMultiHeadXXX

 

Position Embedding ↺

然而,只要稍微思考一下就会发现,这样的模型并不能捕捉序列的顺序!换句话说,如果将K,VKV按行打乱顺序(相当于句子中的词序打乱),那么Attention的结果还是一样的。这就表明了,到目前为止,Attention模型顶多是一个非常精妙的“词袋模型”而已。

这问题就比较严重了,大家知道,对于时间序列来说,尤其是对于NLP中的任务来说,顺序是很重要的信息,它代表着局部甚至是全局的结构,学习不到顺序信息,那么效果将会大打折扣(比如机器翻译中,有可能只把每个词都翻译出来了,但是不能组织成合理的句子)。

于是Google再祭出了一招——Position Embedding,也就是“位置向量”,将每个位置编号,然后每个编号对应一个向量,通过结合位置向量和词向量,就给每个词都引入了一定的位置信息,这样Attention就可以分辨出不同位置的词了。

Position Embedding并不算新鲜的玩意,在FaceBook的《Convolutional Sequence to Sequence Learning》也用到了这个东西。但在Google的这个作品中,它的Position Embedding有几点区别:

1、以前在RNN、CNN模型中其实都出现过Position Embedding,但在那些模型中,Position Embedding是锦上添花的辅助手段,也就是“有它会更好、没它也就差一点点”的情况,因为RNN、CNN本身就能捕捉到位置信息。但是在这个纯Attention模型中,Position Embedding是位置信息的唯一来源,因此它是模型的核心成分之一,并非仅仅是简单的辅助手段。

2、在以往的Position Embedding中,基本都是根据任务训练出来的向量。而Google直接给出了一个构造Position Embedding的公式:

⎧⎩⎨⎪⎪PE2i(p)=sin(p/100002i/dpos)PE2i+1(p)=cos(p/100002i/dpos)PE2ipsinp100002idposPE2i1pcosp100002idpos


这里的意思是将id为pp的位置映射为一个dposdpos维的位置向量,这个向量的第ii个元素的数值就是PEi(p)PEip。Google在论文中说到他们比较过直接训练出来的位置向量和上述公式计算出来的位置向量,效果是接近的。因此显然我们更乐意使用公式构造的Position Embedding了。

 

3、Position Embedding本身是一个绝对位置的信息,但在语言中,相对位置也很重要,Google选择前述的位置向量公式的一个重要原因是:由于我们有sin(α+β)=sinαcosβ+cosαsinβsinαβsinαcosβcosαsinβ以及cos(α+β)=cosαcosβ−sinαsinβcosαβcosαcosβsinαsinβ,这表明位置p+kpk的向量可以表示成位置pp的向量的线性变换,这提供了表达相对位置信息的可能性。

结合位置向量和词向量有几个可选方案,可以把它们拼接起来作为一个新向量,也可以把位置向量定义为跟词向量一样大小,然后两者加起来。FaceBook的论文和Google论文中用的都是后者。直觉上相加会导致信息损失,似乎不可取,但Google的成果说明相加也是很好的方案。看来我理解还不够深刻。

一些不足之处 ↺

到这里,Attention机制已经基本介绍完了。Attention层的好处是能够一步到位捕捉到全局的联系,因为它直接把序列两两比较(代价是计算量变为

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值