• Attention Is All You Need(Transformer)


    一  :self-Attention

    二:位置编码

    三:模型结构

    四:优缺点 

    这篇论文中只使用了self-Attenion和Encoder-Decoder方式,没有采用传统的CNN与RNN 。用一句比较流行的话就是大道至简。作者的实验是通过搭建编码器和解码器各6层,总共12层的Encoder-Decoder。

      

    作者采用Attention机制的原因是考虑到RNN(或者LSTM,GRU等)的计算限制为是顺序的,也就是说RNN相关算法只能从左向右依次计算或者从右向左依次计算,这种机制带来了两个问题:

    1. 时间片 [公式] 的计算依赖 [公式] 时刻的计算结果,这样限制了模型的并行能力;
    2. 顺序计算的过程中信息会丢失,尽管LSTM等门机制的结构一定程度上缓解了长期依赖的问题,但是对于特别长期的依赖现象,LSTM依旧无能为力。

    Transformer的提出解决了上面两个问题,首先它使用了Attention机制,将序列中的任意两个位置之间的距离是缩小为一个常量;其次它不是类似RNN的顺序结构,因此具有更好的并行性,符合现有的GPU框架。论文中给出Transformer的定义是:Transformer is the first transduction model relying entirely on self-attention to compute representations of its input and output without using sequence aligned RNNs or convolution。

       

    遗憾的是,作者的论文比较难懂,尤其是Transformer的结构细节和实现方式并没有解释清楚。尤其是论文中的 [公式] , [公式] , [公式] 究竟代表什么意思作者并没有说明。通过查阅资料,发现了一篇非常优秀的讲解Transformer的技术博客[4]。本文中的大量插图也会从该博客中截取。首先感谢Jay Alammer详细的讲解,其次推荐大家去阅读原汁原味的文章。

    1. Transformer 详解

    1.1 高层Transformer

    论文中的验证Transformer的实验室基于机器翻译的,下面我们就以机器翻译为例子详细剖析Transformer的结构,在机器翻译中,Transformer可概括为如图1:

    图1:Transformer用于机器翻译

     

    Transformer的本质上是一个Encoder-Decoder的结构,那么图1可以表示为图2的结构:

    图2:Transformer的Encoder-Decoder结构

     

    如论文中所设置的,编码器由6个编码block组成,同样解码器是6个解码block组成。与所有的生成模型相同的是,编码器的输出会作为解码器的输入,如图3所示:

    图3:Transformer的Encoder和Decoder均由6个block堆叠而成

    我们继续分析每个encoder的详细结构:在Transformer的encoder中,数据首先会经过一个叫做‘self-attention’的模块得到一个加权之后的特征向量 [公式] ,这个 [公式] 便是论文公式1中的 [公式] :

    [公式]

    第一次看到这个公式你可能会一头雾水,在后面的文章中我们会揭开这个公式背后的实际含义,在这一段暂时将其叫做 [公式] 。

    得到 [公式] 之后,它会被送到encoder的下一个模块,即Feed Forward Neural Network。这个全连接有两层,第一层的激活函数是ReLU,第二层是一个线性激活函数,可以表示为:

    [公式]

    Encoder的结构如图4所示:

    图4:Transformer由self-attention和Feed Forward neural network组成

     

    Decoder的结构如图5所示,它和encoder的不同之处在于Decoder多了一个Encoder-Decoder Attention,两个Attention分别用于计算输入和输出的权值:

    1. Self-Attention:当前翻译和已经翻译的前文之间的关系;
    2. Encoder-Decnoder Attention:当前翻译和编码的特征向量之间的关系。

    图5:Transformer的解码器由self-attention,encoder-decoder attention以及FFNN组成

     

    1.2 输入编码

    1.1节介绍的就是Transformer的主要框架,下面我们将介绍它的输入数据。如图6所示,首先通过Word2Vec等词嵌入方法将输入语料转化成特征向量,论文中使用的词嵌入的维度为 [公式] 。

     

    图6:单词的输入编码

    在最底层的block中, [公式] 将直接作为Transformer的输入,而在其他层中,输入则是上一个block的输出。为了画图更简单,我们使用更简单的例子来表示接下来的过程,如图7所示:

    图7:输入编码作为一个tensor输入到encoder中

    1.3 Self-Attention

    Self-Attention是Transformer最核心的内容,然而作者并没有详细讲解,下面我们来补充一下作者遗漏的地方。回想Bahdanau等人提出的用Attention[2],其核心内容是为输入向量的每个单词学习一个权重,例如在下面的例子中我们判断it代指的内容,

    The animal didn't cross the street because it was too tired

    通过加权之后可以得到类似图8的加权情况,在讲解self-attention的时候我们也会使用图8类似的表示方式

    图8:经典Attention可视化示例图

     

    在self-attention中,每个单词有3个不同的向量,它们分别是Query向量( [公式] ),Key向量( [公式] )和Value向量( [公式] ),长度均是64。它们是通过3个不同的权值矩阵由嵌入向量 [公式] 乘以三个不同的权值矩阵 [公式] , [公式] , [公式] 得到,其中三个矩阵的尺寸也是相同的。均是 [公式] 。

    图9:Q,K,V的计算示例图

    那么Query,Key,Value是什么意思呢?它们在Attention的计算中扮演着什么角色呢?我们先看一下Attention的计算方法,整个过程可以分成7步:

    1. 如上文,将输入单词转化成嵌入向量;
    2. 根据嵌入向量得到 [公式] , [公式] , [公式] 三个向量;
    3. 为每个向量计算一个score: [公式] ;
    4. 为了梯度的稳定,Transformer使用了score归一化,即除以 [公式] ;
    5. 对score施以softmax激活函数;
    6. softmax点乘Value值 [公式] ,得到加权的每个输入向量的评分 [公式] ;
    7. 相加之后得到最终的输出结果 [公式] : [公式] 。

    上面步骤的可以表示为图10的形式。

    图10:Self-Attention计算示例图

     

    实际计算过程中是采用基于矩阵的计算方式,那么论文中的 [公式] , [公式] , [公式] 的计算方式如图11:

    图11:Q,V,K的矩阵表示

     

    图10总结为如图12所示的矩阵形式:

    图12:Self-Attention的矩阵表示

    这里也就是公式1的计算方式。

    在self-attention需要强调的最后一点是其采用了残差网络 [5]中的short-cut结构,目的当然是解决深度学习中的退化问题,得到的最终结果如图13。

    图13:Self-Attention中的short-cut连接

     

    1.3 Multi-Head Attention

    Multi-Head Attention相当于 [公式] 个不同的self-attention的集成(ensemble),在这里我们以 [公式] 举例说明。Multi-Head Attention的输出分成3步:

    1. 将数据 [公式] 分别输入到图13所示的8个self-attention中,得到8个加权后的特征矩阵 [公式] 。
    2. 将8个 [公式] 按列拼成一个大的特征矩阵;
    3. 特征矩阵经过一层全连接后得到输出 [公式] 。

    整个过程如图14所示:

    图14:Multi-Head Attention

     

    同self-attention一样,multi-head attention也加入了short-cut机制。

    1.4 Encoder-Decoder Attention

    在解码器中,Transformer block比编码器中多了个encoder-cecoder attention。在encoder-decoder attention中, [公式] 来之与解码器的上一个输出, [公式] 和 [公式] 则来自于与编码器的输出。其计算方式完全和图10的过程相同。

    由于在机器翻译中,解码过程是一个顺序操作的过程,也就是当解码第 [公式] 个特征向量时,我们只能看到第 [公式] 及其之前的解码结果,论文中把这种情况下的multi-head attention叫做masked multi-head attention。

    1.5 损失层

    解码器解码之后,解码的特征向量经过一层激活函数为softmax的全连接层之后得到反映每个单词概率的输出向量。此时我们便可以通过CTC等损失函数训练模型了。

    而一个完整可训练的网络结构便是encoder和decoder的堆叠(各 [公式] 个, [公式] ),我们可以得到图15中的完整的Transformer的结构(即论文中的图1):

    图15:Transformer的完整结构图

     

    2. 位置编码

    截止目前为止,我们介绍的Transformer模型并没有捕捉顺序序列的能力,也就是说无论句子的结构怎么打乱,Transformer都会得到类似的结果。换句话说,Transformer只是一个功能更强大的词袋模型而已。

    为了解决这个问题,论文中在编码词向量时引入了位置编码(Position Embedding)的特征。具体地说,位置编码会在词向量中加入了单词的位置信息,这样Transformer就能区分不同位置的单词了。

    那么怎么编码这个位置信息呢?常见的模式有:a. 根据数据学习;b. 自己设计编码规则。在这里作者采用了第二种方式。那么这个位置编码该是什么样子呢?通常位置编码是一个长度为 [公式] 的特征向量,这样便于和词向量进行单位加的操作,如图16。

    图16:Position Embedding

     

    论文给出的编码公式如下:

    [公式]

    [公式]

    在上式中, [公式] 表示单词的位置, [公式] 表示单词的维度。关于位置编码的实现可在Google开源的算法中get_timing_signal_1d()函数找到对应的代码。

    作者这么设计的原因是考虑到在NLP任务重,除了单词的绝对位置,单词的相对位置也非常重要。根据公式 [公式] 以及[公式] ,这表明位置 [公式] 的位置向量可以表示为位置 [公式] 的特征向量的线性变化,这为模型捕捉单词之间的相对位置关系提供了非常大的便利。

    3. 总结

    优点:(1)虽然Transformer最终也没有逃脱传统学习的套路,Transformer也只是一个全连接(或者是一维卷积)加Attention的结合体。但是其设计已经足够有创新,因为其抛弃了在NLP中最根本的RNN或者CNN并且取得了非常不错的效果,算法的设计非常精彩,值得每个深度学习的相关人员仔细研究和品位。(2)Transformer的设计最大的带来性能提升的关键是将任意两个单词的距离是1,这对解决NLP中棘手的长期依赖问题是非常有效的。(3)Transformer不仅仅可以应用在NLP的机器翻译领域,甚至可以不局限于NLP领域,是非常有科研潜力的一个方向。(4)算法的并行性非常好,符合目前的硬件(主要指GPU)环境。

    缺点:(1)粗暴的抛弃RNN和CNN虽然非常炫技,但是它也使模型丧失了捕捉局部特征的能力,RNN + CNN + Transformer的结合可能会带来更好的效果。(2)Transformer失去的位置信息其实在NLP中非常重要,而论文中在特征向量中加入Position Embedding也只是一个权宜之计,并没有改变Transformer结构上的固有缺陷。

    参考:

    https://zhuanlan.zhihu.com/p/48508221

    http://jalammar.github.io/illustrated-transformer/

    一、Attention机制的一般形式及self-Attention

    • Attention的一般形式

    为了更统一的描述各个部分的Attention机制,我们首先对过去各种各样的Attention做一个形式上的抽象。回想之前提到过的seq2seq中的Attention机制是如何进行的呢?也就是对于待解码的词向量 [公式] ,需要考虑它上一时刻的隐状态 [公式] ,与Encoder部分的每一个隐状态 [公式] 进行比较,通过某个打分函数 [公式] 得到权重 [公式] ,再将这j个权重赋给j个Encoder的隐状态 [公式] 得到加权求和的向量 [公式] 。

    在上面这个过程中,不难发现实际上操作的有三类变量,第一类是需要与一个变量集合逐一比较的,我们称为query,简记为q。而那个集合里每一个变量作为第二类变量,是要与q进行比较的,称为key,简记为k。而最后一类变量是被权重 [公式] 对应j位置赋权的,称为value,简记为v(这样定义,很容易发现key和value是一一对应的,因为第j个需要和query比较的key,得到的权重要赋予给第j个value)。这样描述起来很抽象,与上述具体的过程对应起来,就是 [公式] , [公式] ,这样理解起来就形象多了。

    有了这种抽象的表述,将每一个q,k,v以矩阵形式表述,可以表示为:

    [公式] , [公式] , [公式]

    (m,n为序列的长度)

    那Attention的一般形式可以被表述为【注1】:

    [公式] (1)

    是不是巨乱,是不是蒙圈了,那是因为我把打分函数 [公式] 给抽象化了。下面就来说最常用的打分函数,在上一篇专栏文章里面的打分函数用的是加性函数( [公式] ),而在Transformer的论文中采用了乘性打分函数:

    [公式] ,也就是 对[公式] 和 [公式] 的内积计算softmax值。

    此时(1)式可改写为:

    [公式] (2)

    同时文中做了一个小的缩放操作,原因是单纯的做q与k的内积会导致 [公式] 内的元素方差较大,以至于将softmax送到梯度较小的区域之内(我将试图在【注2】中对这件事进行解释),不利于模型参数的更新,所以将(2)式进行缩放操作,及在 [公式] 的基础上除以 [公式] ,([公式]为q,k向量的维度 )。最终形成论文提及的Attention形式:

    [公式] (3)

    以下关于Attention的操作将根据(3)式来进行。

     

    • self-Attentiion

    Transformer的核心思想就是用Attention来替代原来Encoder和Decoder部分的RNN,先前RNN的主要作用就是将当前时刻输入的词向量信息与前一时刻隐状态进行整合,形成该时刻的隐状态信息,换句话说,就是将词向量信息抽象为可供模型使用的高层次信息。那么如何只利用Attention来完成这个过程呢?

    图1 self-Attention图示

    还拿上篇文章的“我”“很”“帅”为例,由图1所示,对于“我”这个词来说,将其词向量作为query向量q,将"我很帅"及句子的起始和终止符号每个词的词向量都作为待对比的key,value向量取与key相同。设通过Attention操作后的向量为h,那么根据(3)式:

    [公式]

    结合上式和图1可以看出,对“我”这个词整合成隐层信息的时候,是将“我”这个词与其所在句子中的每一个词进行比较,考查其在句子中的表达更注重哪些位置的信息,从而分配不同的权重给对应位置的词进行加权求和,这也符合Attention的基本思想。由于所有的词汇的Attention操作都是在其句子自身进行的,因此这种Attention机制被称为self-Attention(自注意力机制)。

    Transformer将Encoder和Decoder的主要部分都替换成了这样的self-Attention,优点很明显,所有待处理的向量在矩阵运算下可以很好的并行处理,加快了以前Encoder和Decoder的效率。但还有一个问题待解决,那就是在RNN当中可以很好的保留词与词之间的序列顺序,现在通过self-Attention并行化以后,这个信息难以被描述出来,在Transformer论文原文中,引入了位置向量来标记每个词所在的位置信息。

    二、位置向量和多头注意力机制

    • 位置向量

    在论文原文中,作者引入了位置向量PE(pos),并与输入的词向量进行求和,之后输入对应的下一层,这就要求位置向量应该与词向量具有相同的维度 [公式] ,并在奇偶性不同的分量位置上设计了不同的取值,如下:

    在偶数位分量,有 [公式]

    在奇数位分量,有 [公式]

    其中,pos为当前词语在句子中的位置(1,2,3,4....),i为位置向量的分量位置

    可能这看起来有点匪夷所思,但如果从位置的偏移角度来看,解释起来就相对合理了。假设我们要计算pos位置移动k位置的位置向量,也就是 [公式] ,以偶数位分量为例,有:

    [公式]

    [公式]

    [公式]

    可见,在pos位置偏移k个位置以后的位置向量可以表示为pos位置向量的线性组合,使得位置的相对信息有了一定体现。

    • 多头注意力机制

    在引入了位置向量PE(pos)以后,我们将位置向量与词向量进行求和,输入到self-Attention中进行抽象信息的整合。多数情况下,单一的self-Attention难以捕获序列信息的多样性。因此考虑多个相同操作的self-Attention平行的提取每个词语的信息,然后再将多个Attention的结果拼接起来,用于后续层次的操作。这点类似于卷积神经网络中多个卷积核同时作用一个矩阵对象的想法,都是试图取实现信息不同角度的多样化采集。

    三、其余模型细节

    在介绍完Transformer的主要模型构件以后,就可以祭出各种博客里粘了多少次的图,由图2所示。

    图2 Transformer示意

    图2中除了我们熟悉的全连接层和softmax层以外,红色箭头指出的部分我们都已经有了相对详细的介绍。而蓝色箭头的部分则是模型的一些细节处理,使得模型加速收敛及保持序列的有序性。

    • 残差边与Layer-Normalization

    残差边(short-cut)在图像的resnet中已经被广泛应用了,它的出现是为了防止网络层数的加深导致网络内的参数退化。其想法是将低层的特征跃过一些网络层直接送进高层网络,这就保证了网络的最差情况也能学到那个低层特征本身。原因是过去的网络是计算 [公式] 层输入 [公式] 的线性与非线性的变换 [公式] ,而残差边的思想是将低层的(比如 [公式] 层 [公式] ))特征直接送入 [公式] 层参与运算[公式] ,这样一来,即使参数w,b都退化为0,也还能留下低层特征的信息送到高层,不至于让信息在深层网络传递的过程中丢失过多。

    另一个操作Layer-Normalization(LN)则是起到与Batch-Normalization(BN)类似的作用,BN是指在批次这个维度来标准化数据,使得其落在梯度适中的区域。LN则是在某一层输出时对所有的神经元的值做标准化,好处是不用依赖Batch大小的设置,也能起到一定的加速收敛的作用(其实LN的理解我还不是很到位,以后理解的更好时会更新这一块内容)。

    • Masking操作

    masking操作在论文原文中介绍的相对简洁,作者认为序列在解码的过程中,对于 [公式] 时刻的解码,只能依赖到 [公式] 之前时刻的词语信息,以保证解码过程中的有序性。因此要对 [公式] 时刻后的信息进行masking操作。关于masking的具体做法,主要是设置一个与序列长度相同维度的mask向量,将其第 [公式] 个分量以后的分量全部置为0,第 [公式] 个分量以前的分量全部置为1。用于标记解码序列哪些在网络中的计算是有效的[2]。

    至此,Transformer的基本内容就全都介绍完了。这个模型框架只用了Attention的思想,在执行效率以及一些任务效果上较以前的RNN都有了一定的提高。目前在自然语言处理领域已经有了相对广泛的应用,比如最新的BERT模型,听说就是基于Transformer提出的,后续我也将会补充总结。

    那么说有了“又快又好”的Transformer以后,RNN系列的模型是不是可以从此摒弃?说不好,只能看后续的发展了。

     

    感谢你的阅读。

     

    【注1】这个形式在论文原文中并未提到,是我在加性Attention和乘性Attention的基础上归纳出来的,式(1)其中的内涵是Q矩阵内的每个query向量都要与K矩阵去做一个比较打分,因为对于单独的query向量来说,要遍历K的每一个key去比较。比较后得到一个权重的分布,以 [公式] 为例,也就是 :[公式]

    是个n维的行向量,与后面的n维列向量相乘代表着对V中的每个value赋予权重进而加权求和。

    【注2】对于缩放因子这个事,论文原文给了一些解释。假设Q,K中的每一个 [公式] 维向量是q,k。q,k中的每个分量独立同分布于均值为0,方差为1的随机变量。那么 [公式] 就将服从于均值为0,方差为 [公式] 的随机变量。这就在作为 [公式] 的方差很大的时候,导致对于固定的 [公式] 来说,其与每个 [公式] 的内积将会差异很大。那么在进行softmax运算的时候,就会呈现要么趋向于0,要么趋向于1的情况(这根据softmax的计算式可以验证)。这个时候如果再更新Attention中某个待估参数w,其梯度计算大概是:

    [公式]

    其中 [公式]是反向传播中的某个中间变量, [公式] 为模型优化的目标函数。

    由于 [公式] 这一项在这种情况下基本趋于0(类比sigmoid函数比较水平的那段曲线),因此导致整体梯度的更新处于一个较小的区域,这才引入了缩放因子以消除大方差的影响。

    参考:

    https://zhuanlan.zhihu.com/p/50217835

     

  • 相关阅读:
    JAVA 程序pending 数据库锁
    圆形相遇问题
    DROP TABLE
    sed 删除
    JVM程序计数器
    《神奇的数学》颠覆你对数学的初始感觉
    error "OPatch cannot find a valid oraInst.loc file to locate Central Inventory
    【linux】提醒"libc.so.6: version `GLIBC_2.14' not found"系统的glibc版本太低
    Linux 常用命令随笔(一)
    国际结算业务--国际结算中的票据
  • 原文地址:https://www.cnblogs.com/jiayibing2333/p/12116613.html
Copyright © 2020-2023  润新知