本文参考的原始论文地址:https://arxiv.org/abs/1706.03762
谷歌昨天在arxiv发了一篇论文名字教Attention Is All You Need,提出了一个只基于attention的结构来处理序列模型相关的问题,比如机器翻译。传统的神经机器翻译大都是利用RNN或者CNN来作为encoder-decoder的模型基础,而谷歌最新的只基于Attention的Transformer模型摒弃了固有的定式,并没有用任何CNN或者RNN的结构。该模型可以高度并行地工作,所以在提升翻译性能的同时训练速度也特别快。
模型分为编码器和解码器两个部分,编码器由6个相同的层堆叠在一起,每一层又有两个支层。第一个支层是一个多头的自注意机制,第二个支层是一个简单的全连接前馈网络。在两个支层外面都添加了一个residual的连接,然后进行了layer nomalization的操作。模型所有的支层以及embedding层的输出维度都是 dmodel=512 . 模型的解码器也是堆叠了六个相同的层。不过每层除了编码器中那两个支层,解码器还加入了第三个支层,如图中所示同样也用了residual以及layer normalization。具体的细节后面再讲。
论文是从attention结构开始介绍Transformer的,这里为了方便,从模型的输入开始介绍。
模型输入。
编码器和解码器的输入就是利用学习好的embeddings将tokens(一般应该是词或者字符)转化为 dmodel 维向量。对解码器来说,利用线性变换以及softmax函数将解码的输出转化为一个预测下一个token的概率。
位置编码。
由于模型没有任何循环或者卷积,为了使用序列的顺序信息,需要将tokens的相对以及绝对位置信息注入到模型中去。论文在输入embeddings的基础上加了一个“位置编码”。位置编码和embeddings由同样的维度都是 dmodel 所以两者可以直接相加。有很多位置编码的选择,既有学习到的也有固定不变的。本文中用了正弦和余弦函数进行编码。
下面介绍我对本文最重要的一部分注意力模型的理解。
论文首先给attentioin进行了一个定义。attention函数可以看作将一个query和一系列key-value对映射为一个输出(output)的过程。这里的query,keys,values以及output都是向量。输出是由带权的values加起来得到的,而每个value的权重是根据query和相应的key通过一个函数计算出来的。
scaled 的点乘attention
论文中用的attention是基本的点乘的方式,就是多了一个所谓的scale。输入包括维度为 dk 的queries以及keys,还有维度为 dv 的values。计算query和所有keys的点乘,然后每个都除以 dk−−√ (这个操作就是所谓的Scaled)。之后利用一个softmax函数来获取values的权重。
实际操作中,attention函数是在一些列queries上同时进行的,将这些queries并在一起形成一个矩阵 Q 同时keys以及values也并在一起形成了矩阵 K 以及 V 。则attention的输出矩阵可以按照下述公式计算:
多头的attention (Multi-Head Attention)
这个应该是本文最核心的部分。本文结构中的Attention并不是简简单单将一个点乘的attention应用进去。作者发现先对queries,keys以及values进行 h 次不同的线性映射效果特别好。学习到的线性映射分别映射到 dk , dk 以及 dv 维。分别对每一个映射之后的得到的queries,keys以及values进行attention函数的并行操作,生成 dv 维的output值。具体操作细节如以下公式。
把这些attention头的output拼接起来作为最终值,就像下图中multihead attention结构示意图所描述的一样。
在本模型中如何使用attention
本文提出的模型Transformer以三种不同的方式使用了多头attention。
1. 在encoder-decoder的attention层,queries来自于之前的decoder层,而keys和values都来自于encoder的输出。这个类似于很多已经提出的seq-to-seq模型所使用的attention机制。
2. 在encoder含有self-attention层。在一个self-attention层中,所有的keys, values以及queries都来自于同一个地方,本例中即encoder之前一层的的输出。
3. 类似的,decoder中的self-attention层也是一样。不同的是在scaled点乘attention操作中加了一个mask的操作(设置为负无穷),这个操作是保证softmax操作之后不会将非法的values连到attention中(个人理解,比如你这一位置queryattention的values不能有这一位置之后的values的信息,只能有该位置前面的values,本人菜鸟欢迎拍砖)。
之前说模型由堆叠在一起的六个层组成,每层由两个支层,attention层就是其中一个,而attention之后的另一个支层就是一个前馈的网络。公式描述如下。
模型的整体框架基本介绍完了,其最重要的创新应该就是Self-Attention的使用级联的多头attention架构。
作者在文中深入讨论了为什么选择使用self attention这一结构。主要从三个方面来谈。第一是每层的总计算复杂性,其次是能并行计算的数量,这点论文用所要求的序列操作的最小值来量化。第三点是针对网络长距离依赖的路径长度。为了提升在长序列上的计算性能,self-attention应该改被限制(restrict)在一个size大小为 r 的邻域内,这样可以将最大路径长度增加到 O(n/r) ,至于具体如何去做作者说在未来工作中会研究。
上图为self attention结构与cnn以及rnn的性能比较,可以看出self attention还是具有优势的。
论文中的东西就说这么多了,下面说我的感想。
自我感觉谷歌这次放大招了,完全抛弃了CNN以及RNN这几年做神经机器翻译的固有思维,仅用了attention来对句子进行编码和解码。从论文后面的附图可以看出该模型已经在很大程度上“理解”了句子的意思。也许过一段时间,各种层叠attention及其变种的模型就会满天飞了,但谷歌无疑开了这样一个好头,就是我们不必对固有的模型抱有很深的执念,尝试各种可能也许会有意想不到的效果。不过话说回来,谁知道这个模型是失败了多少次之后才有的成功呢?