Transformer的原理

前言

这是第10个任务,本次任务主要是一下几个方面:

  • Transformer的原理
  • BERT的原理
  • 利用预训练的BERT模型将句子转换为句向量,进行文本分类

本文主要接受Transformer 原理,2017年,Google发表论文《Attention is All You Need》,提出经典网络结构Transformer,全部采用Attention结构的方式,代替了传统的Encoder-Decoder框架必须结合CNN或RNN的固有模式。并在两项机器翻译任务中取得了显著效果。该论文一经发出,便引起了业界的广泛关注,同时,Google于2018年发布的划时代模型BERT也是在Transformer架构上发展而来。

Transformer原理

和大多数seq2seq模型一样,transformer的结构也是由encoder和decoder组成。通俗结构图如下所示:

将上述图浓缩一下就是如下图,其中灰色长方形框框就是 Encoder和Decoder都如下所示:

再通俗一点的图,可能你在其他博客里看到的图,如下所示:

Position Embedding(位置向量)

在本文中,Embedding操作不是普通的Embedding而是加入了位置信息的Embedding,我们称之为Position Embedding。因为在本文的模型中,已经没有了循环神经网络这样的结构,因此序列信息已经无法捕捉。但是序列信息非常重要,代表着全局的结构,因此必须将序列的分词相对或者绝对position信息利用起来,每个时刻的输入是Word Embedding+Position Embedding。位置信息的计算公式如下:
P E p o s , 2 i = s i n ( p o s 1000 0 2 i d m o d e l ) PE_{pos,2i}=sin(\frac{pos}{10000^{\frac{2i}{d_{model}}}}) \\ PEpos,2i=sin(10000dmodel2ipos)
P E p o s , 2 i + 1 = c o s ( p o s 1000 0 2 i d m o d e l ) PE_{pos,2i+1}=cos(\frac{pos}{10000^{\frac{2i}{d_{model}}}}) PEpos,2i+1=cos(10000dmodel2ipos)
其中:

  • pos代表的是第几个词,单词的位置。
  • i代表embedding中的第几维,表示单词的维度。

即奇数位置用余弦编码,偶数位置用正弦编码,最终得到一个512维的位置向量。位置编码是不参与训练的,而词向量是参与训练的。作者通过实验发现,位置编码参与训练与否对最终的结果并无影响。

Encoder


Encoder由N=6个相同的layer组成,每一个layer就是上图左侧的单元,最左边有个“N”参数,这里N=6。每个Layer由两个sub-layer组成,分别是multi-head self-attention mechanism(左图中橙色部分)和fully connected feed-forward network(左图中蓝色部分)。其中每个sub-layer都加了residual connection和normalisation,因此可以将sub-layer的输出表示为:
s u b _ l a y e r _ o u t p u t = L a y e r N o r m ( x + ( S u b L a y e r ( x ) ) ) sub\_layer\_output = LayerNorm(x+(SubLayer(x))) sub_layer_output=LayerNorm(x+(SubLayer(x)))
接下来按顺序解释一下这两个sub-layer。

Multi-head self-attention

普通attention机制可由如下表示:
a t t e n t i o n _ o u t p u t = A t t e n t i o n ( Q , K , V ) attention\_output = Attention(Q,K,V) attention_output=Attention(Q,K,V)
第一部就是从每个编码器的输入向量(每个单词的词向量)中生成三个向量。也就是说对于每个单词,我们创造一个查询向量 Q Q Q、一个键向量 K K K和一个值向量 V V V。这三个向量是通过词嵌入与三个权重矩阵后相乘创建的。

其中:
Q i = X i ∗ W i Q K i = X i ∗ W i K V i = X i ∗ W i V Q_i=X_i * W^{Q}_i \\ K_i=X_i* W^{K}_i \\ V_i=X_i* W^{V}_i Qi=XiWiQKi=XiWiKVi=XiWiV

X 1 X1 X1 W Q WQ WQ权重矩阵相乘得到 q 1 q_1 q1, 就是与这个单词相关的查询向量。最终使得输入序列的每个单词的创建一个查询向量、一个键向量和一个值向量。可以发现这些新向量在维度上比词嵌入向量更低。他们的维度是64,而词嵌入和编码器的输入/输出向量的维度是512,但实际上不强求维度更小,这只是一种基于架构上的选择,它可以使多头注意力(multiheaded attention)的大部分计算保持不变。


第二部是计算得分,假设我们在为这个例子中的第一个词“Thinking”计算自注意力向量,我们需要拿输入句子中的每个单词对“Thinking”打分。这些分数决定了在编码单词“Thinking”的过程中有多重视句子的其它部分。这些分数是通过打分单词(所有输入句子的单词)的键向量 K K K与“Thinking”的查询向量 Q Q Q相点积来计算的。所以如果我们是处理位置最靠前的词的自注意力的话,第一个分数是 q 1 q_1 q1 k 1 k_1 k1的点积,第二个分数是 q 1 q_1 q1 k 2 k_2 k2的点积。

第三步和第四步是将分数除以8(8是论文中使用的键向量的维数64的平方根,这会让梯度更稳定。这里也可以使用其它值,8只是默认值),然后通过softmax传递结果。softmax的作用是使所有单词的分数归一化,得到的分数都是正值且和为1。

这个softmax分数决定了每个单词对编码当下位置(“Thinking”)的贡献。显然,已经在这个位置上的单词将获得最高的softmax分数,但有时关注另一个与当前单词相关的单词也会有帮助。
第五步是将每个值向量 V V V乘以softmax分数(这是为了准备之后将它们求和),不过这里有一个问题,比如输入有3个单词,就有3个 q q q和3个 k k k,比如第一个单词评分分别是 q 1 ∗ k 1 q_1*k_1 q1k1 q 1 ∗ k 2 q_1*k_2 q1k2 q 1 ∗ k 3 q_1*k_3 q1k3,这里就有3个softmax值,这3个值分别跟对应的 v i v_i vi相乘,就有3个向量。这里的直觉是希望关注语义上相关的单词,并弱化不相关的单词(例如,让它们乘以0.001这样的小数)。
第六步是对加权值向量求和,然后即得到自注意力层在该位置的输出(在我们的例子中是对于第一个单词),也就是第五步中我们说的3个向量。自注意力的另一种解释就是在编码某个单词时,就是将所有单词的表示(值向量)进行加权求和,而权重是通过该词的表示(键向量)与被编码词表示(查询向量)的点积并通过softmax得到。不过现在仔细想想,求和是各个向量同位置上的求和还是所有向量累加?看下图就是多个向量同位置的元素相加。

这里还有一个“多头”注意力(“multi-headed” attention)的机制,论文进一步完善了自注意力层,并在两方面提高了注意力层的性能:

  • 1.它扩展了模型专注于不同位置的能力。在上面的例子中,虽然每个编码都在z1中有或多或少的体现,但是它可能被实际的单词本身所支配。如果我们翻译一个句子,比如“The animal didn’t cross the street because it was too tired”,我们会想知道“it”指的是哪个词,这时模型的“多头”注意机制会起到作用。

  • 2.它给出了注意力层的多个“表示子空间”(representation subspaces)。接下来我们将看到,对于“多头”注意机制,我们有多个查询 Q Q Q、键 k k k、值 v v v权重矩阵集(Transformer使用八个注意力头,因此我们对于每个编码器/解码器有八个矩阵集合)。这些集合中的每一个都是随机初始化的,在训练之后,每个集合都被用来将输入词嵌入(或来自较低编码器/解码器的向量)投影到不同的表示子空间中。

    multi-head attention则是通过h个不同的线性变换对Q,K,V进行投影,最后将不同的attention结果拼接起来:
    M u l t i H e a d ( Q , K , V ) = C o n c a t ( h e a d 1 , . . . , h e a d h ) W O h e a d i = A t t e n t i o n ( Q W i Q , K W i K , V W i V ) MultiHead(Q,K,V) = Concat(head_1,...,head_h)W^O \\ head_i = Attention(QW_{i}^{Q},KW_{i}^{K},VW_{i}^{V}) \\ MultiHead(Q,K,V)=Concat(head1,...,headh)WOheadi=Attention(QWiQ,KWiK,VWiV)

h e a d i head_i headi公式中我们可以看出每一个 h e a d i head_i headi都独立维护一套Q/K/V的权值矩阵。假设我们有8个head,那么最终我们可以得到8个head值,然后拼接在一起作为一个向量,与 W 0 W_0 W0相乘,作为Multi-head self-attention 层的输出,计算流程如下图所示:

self-attention则是取Q,K,V维度相同。文章中attention的计算采用了scaled dot-product,即:
A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d k ) V Attention(Q,K,V) = softmax(\frac{QK^T}{\sqrt{d_k}})V Attention(Q,K,V)=softmax(dk QKT)V
于是,图中的 Z = s o f t m a x ( Q K T d k ) V Z=softmax(\frac{QK^T}{\sqrt{d_k}})V Z=softmax(dk QKT)V,其中 d k d_k dk表示为Q,K,V维度。同时,作者同样提到了另一种复杂度相似但计算方法additive attention,在 d k d_k dk很小的时候和dot-product结果相似, d k d_k dk大的时候,如果不进行缩放则表现更好,但dot-product的计算速度更快,进行缩放后可减少影响。
Transformer以三种不同的方式使用了多头attention:

  • 在encoder含有self-attention层。在一个self-attention层中,所有的keys,values以及queries都来自于同一个地方,本例中即encoder之前一层的的输出。
  • 类似的,decoder中的self-attention层也是一样。不同的是在scaled点乘attention操作中加了一个mask的操作,这个操作是保证softmax操作之后不会将非法的values连到attention中。
  • 在encoder-decoder的attention层,queries来自于之前的decoder层,而keys和values都来自于encoder的输出。这个类似于很多已经提出的seq2seq模型所使用的attention机制。
Position-wise feed-forward networks

位置全链接前馈网络——MLP变形。之所以是position-wise(i/o维度一样)是因为处理的attention输出是某一个位置i的attention输出。。

  • Position-wise: 顾名思义,就是对每个position采用相同的操作。
  • Feed-Forward Network: 就是最普通的全连接神经网络,这里采用的两层,relu作为激活函数。

Feed Forward Neural Network全连接有两层dense,第一层的激活函数是ReLU(或者其更平滑的版本Gaussian Error Linear Unit-gelu),第二层是一个线性激活函数,如果multi-head输出表示为Z,则FFN可以表示为:
F F N ( Z ) = m a x ( 0 , Z 1 W 1 + b 1 ) Z 2 + b 2 FFN(Z)=max(0,Z_1W_1+b_1)Z_2+b_2 FFN(Z)=max(0,Z1W1+b1)Z2+b2
Position-wise feed forward network其实就是一个MLP 网络,每个 d_model 维向量 x 在此先由 x W 1 + b 1 xW_1+b_1 xW1+b1变为 d f d_f df维的 x’,再经过 m a x ( 0 , x ′ ) W 2 + b 2 max(0,x')W_2+b_2 max(0,x)W2+b2回归 d_model 维。hidden_size变化为:768->3072->768(或者512->2048->512)。之后就是对hidden层进行dropout,最后加一个resnet并normalization(tensor的最后一维,即feature维进行)。Transformer通过对输入的文本不断进行这样的注意力机制层和普通的非线性层交叠来得到最终的文本表达。

Decoder


我们可以看大Decoder和Encoder的结构差不多, 不同的是Decoder有两个多头attention机制:

  • 一个是其自身的mask自注意力机制
  • 另一个则是从Encoder到Decoder的注意力机制,而且是Decoder内部先做一次attention后再接收Encoder的输出。

Decoder有N(默认是6)层,每层包括三个sub-layers(自下往上):

  • 1 )第一个是Masked multi-head self-attention,也是计算输入的self-attention,但是因为是生成过程,因此在时刻 i 的时候,大于 i 的时刻都没有结果,只有小于 i 的时刻有结果,因此需要做Mask,也就是去上一次的decoder层做输入。
  • 2 )第二个sub-layer是对encoder的输入进行attention计算,这里仍然是multi-head的attention结构,只不过输入的分别是encoder的输出和decoder的输入,encoder的输出会做用在每一层decoder中的第二个sub-layer,后面的动图可以帮助理解。
  • 3 )第三个sub-layer是全连接网络,与Encoder相同。

这里先明确一下decoder的输入输出和解码过程:

  • 输入:encoder的输出 和 对应 x i − 1 x_{i-1} xi1位置decoder的输出。所以中间的attention不是self-attention,它的K,V来自encoder,Q来自上一位置decoder的输出。向量K(键向量)和V(值向量)的注意力向量集来自 Encoder。这些向量将被每个解码器用于自身的“编码-解码注意力层”,并作用在Decoder的每一层。

  • 解码:这里要特别注意一下,编码可以并行计算,一次性全部encoding出来,但解码不是一次把所有序列解出来的,而是像RNN一样一个一个解出来的,因为要用上一个位置的输入当作attention的query

  • 输出:对应输入 x i x_i xi的输出词的概率分布

明确了解码过程之后最上面的图就很好懂了,这里主要的不同就是新加的attention多加了一个mask,因为训练时的output都是ground truth,这样可以确保预测 x i x_i xi时不会接触到未来的信息,下面是一个详细解析图:

以下动态图,可以体验下,第一个动图只展示了两个Encoder和两个Decoder,正常是各自6个,这里怕读者误解。生成第一个单词“I”


上面的动图可以看到,Encoders的输出结果值对一个Decoders的输出有影响,也就是对第一个单词“I”有影响,对第二个单词“am”没有什么作用。这个需要继续研究一下。再说一下

残差网络

不知道大家注意到没有,如下图红色箭头:

这个红色箭头表明这个可能是一个残差链接,残差连接其实在很多网络机构中都有用到。原理很简单,假设一个输入向量x,经过一个网络结构,得到输出向量 f ( x ) f(x) f(x),加上残差连接,相当于在输出向量中加入输入向量,即输出结构变为 f ( x ) + x f(x)+x f(x)+x,这样做的好处是在对x求偏导时,加入一项常数项1,避免了梯度消失的问题。详细的可以去参考这方面知识-Residual connection。

Mask

mask的思想非常简单:就是对输入序列中没某些值进行掩盖,使其不起作用。在论文中,做multi-head attention的地方用到了padding mask,在decode输入数据中用到了sequence mask。

  • (1)、padding mask在我们输入的数据中,因为每句话的长度不同,所以要对较短的数据进行填充补齐长度。而这些填充值并没有什么作用,为了减少填充数据对attention计算的影响,采用padding mask的机制,即在填充物的位置上加上一个趋紧于负无穷的负数,这样经过softmax计算后这些位置的概率会趋近于0。
  • (2)、sequence mask在上文中我们提到,预测t时刻的输出值 y t y_t yt,应该使用全部的输入序列X,和t时刻之前的输出序列 ( y 1 , y 2 , … … , y t − 1 ) (y_1,y_2,……,y_{t-1}) (y1,y2,,yt1)进行预测。所以在训练时,应该将t-1时刻之后的信息全部隐藏掉。所以需要用到sequence mask。实现也很简单,就是用一个上三角矩阵,上三角值均为1,下三角值均为0,对角线值为0,与输入序列相乘,就达到了目的。

总结

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

Transformer是第一个用纯attention搭建的模型,不仅计算速度更快,在翻译任务上也获得了更好的结果。Google现在的翻译应该是在此基础上做的,但是请教了一两个朋友,得到的答案是主要看数据量,数据量大可能用transformer好一些,小的话还是继续用rnn-based model。

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

参考博客

图解Transformer
【NLP】Transformer详解
Transformer注解及PyTorch实现
BERT大火却不懂Transformer?读这一篇就够了
详解Transformer (Attention Is All You Need)

你可能感兴趣的:(学术)