Transformer:Attention Is All You Need
论文名称:Attention Is All you Need
作者:Ashish Vaswani,Noam Shazeer,Niki Parmar,Jakob Uszkoreit,Llion Jones,Aidan N. Gomez,Łukasz Kaiser,Illia Polosukhin
code:https://github.com/jadore801120/attention-is-all-you-need-pytorch
基于 RNN 或 CNN 的 Encoder-Decoder 模型在 NLP 领域占据大壁江山,然而她们也并非是完美无缺的:
LSTM,GRU 等 RNN 模型受限于固有的循环顺序结构,无法实现并行计算 ,在序列较长时,计算效率尤其低下,虽然最近的工作如因子分解技巧 1 ,条件计算 2 在一定程度上提高了计算效率和性能,但是顺序计算的限制依然存在;
Extended Neural GPU3 , ByteNet 4 ,和 ConvS2S 5 等 CNN 模型虽然可以进行并行计算,但是学习任意两个位置的信号的长距离关系依旧比较困难,其计算复杂度随距离线性或对数增长。
而谷歌选择抛弃了主流模型固有的结构,提出了完全 基于注意力机制的 Transformer,拥有其他模型无法比拟的优势:
Transformer 可以高效的并行训练,因此速度十分快,在8个 GPU 上训练了3.5天;
对于长距离关系的学习,Transformer 将时间复杂度降低到了常数,并且使用多头注意力来抵消位置信息的平均加权造成的有效分辨率降低
Transform 是一种自编码(Auto-Encoding)模型,能够同时利用上下文
整体结构
Transformer 的整体结构是一个 Encoder-Decoder,自编码模型主要应用于语意理解,对于生成任务还是自回归模型更有优势
我们可以将其分为四个部分:输入,编码块,解码块与输出
接下来让我们按照顺序来了解整个结构,希望在阅读下文前你可以仔细观察这幅图,阅读时也请参考该图
使用 nn.Embedding
进行 Word Embedding,论文中嵌入维度 d m o d e l = 512 d_{model}=512 d m o d e l = 512
在嵌入时,左右两部分的权 重会共享
得到词嵌入向量后需要乘以 d m o d e l \sqrt{d_{model}} d m o d e l ,其原因可能是为了相对减小位置编码的影响
同时会将上一层的输出加入进来,网络的第一层则会直接使用 Inputs 充当“上一层”
在输入之后会进行位置编码 ,使得 Transformer 拥有捕捉序列顺序的能力
Encoder-Decoder
整体结构如图
Encoder-Decoder 的内部结构如下图:
Encoder :编码块是由6个完全相同的 layer 组成的,每个 layer 有两个子层
第一层包括一个 M u l t i H e a d S e l f − A t t e n t i o n Multi\ Head\ Self-Attention M u lt i He a d S e l f − A tt e n t i o n 、L a y e r N o r m a l i z a t i o n Layer\ Normalization L a yer N or ma l i z a t i o n 和残差连接
第二层包括一个二层的全连接前馈层:F F N ( x ) = m a x ( 0 , x W 1 + b 1 ) W 2 + b 2 FFN(x)=max(0,xW_1+b_1)W_2+b_2 FFN ( x ) = ma x ( 0 , x W 1 + b 1 ) W 2 + b 2 ,中间层的维度为2048;同样包含 L a y e r N o r m a l i z a t i o n Layer\ Normalization L a yer N or ma l i z a t i o n 和残差连接
Decoder :解码块同样由6个完全 相同的 layer 组成,每个子层同样有残差连接和 L a y e r N o r m a l i z a t i o n Layer\ Normalization L a yer N or ma l i z a t i o n
额外添加了第三个子层—— M a s k e d M u l t i H e a d A t t e n t i o n Masked\ Multi\ Head \ Attention M a s k e d M u lt i He a d A tt e n t i o n ,这是针对于上一层输出的,将在下文详细解读
此外,还修改了子注意力子层(如上图,由原来的 Self-Attention 变 Encoder-Decoder Attention)
Layer Normalization :NLP 任务中主要使用 L a y e r N o r m Layer\ Norm L a yer N or m 而不是 B a t c h N o r m Batch\ Norm B a t c h N or m ,因为在批次上进行归一化会混乱不同语句之间的信息,我们需要在每个语句之中进行归一化。
对解码器的输出使用普通的线性变化与 S o f t m a x Softmax S o f t ma x ,作为下一层的输入
注意力机制
Self-Attention
具体内容可参考我的另一篇博客——注意力机制
缩放点积注意力
缩放点积注意力,图式如下:
其公式为
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 A tt e n t i o n ( Q , K , V ) = so f t ma x ( d k Q K T ) V
缩放点积指的是其中的打分函数
Q K T d \frac{QK^T}{\sqrt d} d Q K T
常见的注意力模型有加性模型和点积模型,点积模型相较于加性模型效率更高,但是当输入向量维度过高,点积模型通常有较大的方差,从而导致softmax函数梯度很小 ,而缩放点积模型可以很好地解决这个问题。
另为,Transformer 在实现过程中使用了残差连接
Softmax梯度问题 :
S i = e x i ∑ j = 1 N e x j S_i=\frac{e^{x_i}}{\sum_{j=1}^Ne^{x_j}} S i = ∑ j = 1 N e x j e x i
我们知道,S o f t m a x Softmax S o f t ma x 的作用是拉大数据之间的差距
对于一组数据[ x , x , 2 x ] [x,x,2x] [ x , x , 2 x ] ,让我们给其赋不同的值,来观察方差和S 3 S_3 S 3 的变化
import numpy as np x = np . array ( [ np . exp ( [ i , i , 2 * i ] ) for i in [ 1 , 10 , 100 ] ] ) print ( np . square ( np . linalg . norm ( x , axis = 1 , ord = 2 ) ) ) print ( x [ : , 2 ] / x . sum ( axis = 1 ) . T )
{ x = 1 S = 6.938 S 3 = 0.576 x = 10 S = 2.253 e 17 S 3 = 0.999 x = 100 S = 5.221 e 173 S 3 = 1.0 \begin{cases}{}
x=1\quad S=6.938\quad S_3=0.576 \\
x=10 \quad S=2.253e17\quad S_3=0.999\\
x=100\quad S=5.221e173\quad S_3=1.0
\end{cases} ⎩ ⎨ ⎧ x = 1 S = 6.938 S 3 = 0.576 x = 10 S = 2.253 e 17 S 3 = 0.999 x = 100 S = 5.221 e 173 S 3 = 1.0
即使数据之间成比例,在数量级较大时,Softmax将几乎全部的概率分布都分配给了最大的那个数
Softmax 的梯度为
∂ S ( x ) ∂ x = [ y 1 0 ⋯ 0 0 y 2 ⋯ 0 ⋮ ⋮ ⋱ ⋮ 0 0 ⋯ y d ] − [ y 1 2 y 1 y 2 ⋯ y 1 y d y 2 y 1 y 2 2 ⋯ y 2 y d ⋮ ⋮ ⋱ ⋮ y d y 1 y d y 2 ⋯ y d 2 ] \frac{\partial S(x)}{\partial x}=
\left[\begin{array}
{c}y_1&0&\cdots&0\\
0&y_2&\cdots&0\\
\vdots&\vdots&\ddots&\vdots\\
0&0&\cdots&y_d
\end{array}\right]-
\left[\begin{array}
{}
y_1^2&y_1y_2&\cdots&y_1y_d\\
y_2y_1&y_2^2&\cdots&y_2y_d\\
\vdots&\vdots&\ddots&\vdots\\
y_dy_1&y_dy_2&\cdots&y_d^2
\end{array}\right] ∂ x ∂ S ( x ) = y 1 0 ⋮ 0 0 y 2 ⋮ 0 ⋯ ⋯ ⋱ ⋯ 0 0 ⋮ y d − y 1 2 y 2 y 1 ⋮ y d y 1 y 1 y 2 y 2 2 ⋮ y d y 2 ⋯ ⋯ ⋱ ⋯ y 1 y d y 2 y d ⋮ y d 2
当出现上述的情况时,softmax 会输出一个近似 one-hot 的向量 [ 1 , 0 , 0 , ⋯ , 0 ] [1,0,0,\cdots,0] [ 1 , 0 , 0 , ⋯ , 0 ] ,此时梯度为
∂ S ( x ) ∂ x = [ 1 0 ⋯ 0 0 0 ⋯ 0 ⋮ ⋮ ⋱ ⋮ 0 0 ⋯ 0 ] − [ 1 2 0 ⋯ 0 0 0 ⋯ 0 ⋮ ⋮ ⋱ ⋮ 0 0 ⋯ 0 ] = 0 \frac{\partial S(x)}{\partial x}=
\left[\begin{array}
{c}1&0&\cdots&0\\
0&0&\cdots&0\\
\vdots&\vdots&\ddots&\vdots\\
0&0&\cdots&0
\end{array}\right]-
\left[\begin{array}
{}
1^2&0&\cdots&0\\
0&0&\cdots&0\\
\vdots&\vdots&\ddots&\vdots\\
0&0&\cdots&0
\end{array}\right]=0 ∂ x ∂ S ( x ) = 1 0 ⋮ 0 0 0 ⋮ 0 ⋯ ⋯ ⋱ ⋯ 0 0 ⋮ 0 − 1 2 0 ⋮ 0 0 0 ⋮ 0 ⋯ ⋯ ⋱ ⋯ 0 0 ⋮ 0 = 0
缩放点积为什么有效?
在论文的注脚中给出了如下假设:
**假设向量 Q Q Q 和 K K K 的各个分量是互相独立的随机变量,均值是0,方差是1,那么点积 Q K QK Q K 的均值是0,方差是 d k d_k d k **
具体推理过程可参考我的另一篇博客概率论 2.3.5和2.3.6节
我们在高二就学过方差的一个基本性质,对于随机变量 Y = a X + b Y=aX+b Y = a X + b
σ Y 2 = a 2 σ X 2 \sigma_Y^2=a^2\sigma_X^2 σ Y 2 = a 2 σ X 2
所以除以 d k \sqrt{d_k} d k 可以将方差控制为1,从而有效地解决梯度消失的情况
Multi-Head Attention
多头注意力,图式如下
相比于使用 d m o d e l d_{model} d m o d e l 维数(此处为512维)的 Q 、 K 、 V Q、K、V Q 、 K 、 V 来执行一个 A t t e n t i o n Attention A tt e n t i o n ,使用不同的线性映射得到多个 Q 、 K 、 V Q、K、V Q 、 K 、 V 来并行得执行 A t t e n t i o n Attention A tt e n t i o n 效果更佳,原因如下:
其增强了模型专注于不同信息的能力
为注意力层提供了多个“表示子空间”
具体操作 :
对于每一个头,我们使用一套单独的权重矩阵 W Q 、 W K 、 W V W_Q、W_K、W_V W Q 、 W K 、 W V ,并且将其维度降至 d m o d e l / H d_{model}/H d m o d e l / H
生成 H 个不同的注意力矩阵,将其拼接在一起
最后使用一 个单独的权重矩阵 W O W^O W O 得到最终的注意力权重
M u t i H e a d ( Q , K , V ) = C o n c a t ( h e a d 1 , h e a d 2 , ⋯ , h e a d h ) W O w h e r e 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 ) MutiHead(Q,K,V)=Concat(head_1,head_2,\cdots,head_h)W^O\\where\quad head_i=Attention(QW^Q_i,KW^K_i,VW^V_i) M u t i He a d ( Q , K , V ) = C o n c a t ( h e a d 1 , h e a d 2 , ⋯ , h e a d h ) W O w h ere h e a d i = A tt e n t i o n ( Q W i Q , K W i K , V W i V )
由于维度做了缩放,多头注意力的总代价和仅使用一个注意力的代价相近
与卷积的关系 :
我们可以发现,多头注意力实际上与卷积有着异曲同工之妙
正如多个头可以注意不同的信息,不同的卷积核可以提取图像中不同的特征
同样,正如特征图多个通道内的信息冗余,多头注意力也存在着信息冗余
位置编码
主要参考
为什么需要位置编码?
上文已经提到,Transformer 是一种并行计算,为了让模型能够捕捉到序列的顺序关系,引入了位置编码,来获得单词之间的相对距离 。
正余弦位置编码
P E ( p o s , 2 i ) = sin ( p o s 1000 0 2 i d m o d e l ) P E ( p o s , 2 i + 1 ) = cos ( p o s 1000 0 2 i d m o d e l ) PE(pos,2i) = \sin(\frac{pos}{10000^{\frac{2i}{d_{model}}}})\\
PE(pos,2i+1) = \cos(\frac{pos}{10000^{\frac{2i}{d_{model}}}})\\ PE ( p os , 2 i ) = sin ( 1000 0 d m o d e l 2 i p os ) PE ( p os , 2 i + 1 ) = cos ( 1000 0 d m o d e l 2 i p os )
对于奇数位置使用余弦函数进行编码
对于偶数位置使用正弦函数进行编码
注意 :这里的位置指的是一个词向量里数据的位置,pos 指的才是 单词在语句中的位置
例如某个单词在语句中的位置为 Pos=5,d m o d e l = 512 d_{model}=512 d m o d e l = 512 ,则其位置编码向量为
[ s i n ( 5 1000 0 0 512 ) c o s ( 5 1000 0 0 512 ) s i n ( 5 1000 0 2 512 ) c o s ( 5 1000 0 2 512 ) ⋮ s i n ( 5 1000 0 512 512 ) ] \left[\begin{array}{c}sin(\frac{5}{10000^{\frac{0}{512}}})\\cos(\frac{5}{10000^{\frac{0}{512}}})\\sin(\frac{5}{10000^{\frac{2}{512}}})\\cos(\frac{5}{10000^{\frac{2}{512}}})\\\vdots\\sin(\frac{5}{10000^{\frac{512}{512}}})\end{array}\right] s in ( 1000 0 512 0 5 ) cos ( 1000 0 512 0 5 ) s in ( 1000 0 512 2 5 ) cos ( 1000 0 512 2 5 ) ⋮ s in ( 1000 0 512 512 5 )
可以看到,2 i 、 2 i + 1 2i、2i+1 2 i 、 2 i + 1 仅仅决定使用的是 s i n sin s in 还是 c o s cos cos ,对于同一个 i i i ,内部是相同的
得到位置编码之后,将其与词向量相加,作为最终的输入
这里的直觉是,将位置编码添加到词向量,它们投影到 Q / K / V Q/K/V Q / K / V 并且进行点积时,会提供有意义的距离信息
为什么位置编码是有效的?
我们在小学二年级就学过三角函数的诱导公式:
sin ( α + β ) = s i n ( α ) c o s ( β ) + c o s ( α ) s i n ( β ) c o s ( α + β ) = c o s ( α ) c o s ( β ) − s i n ( α ) s i n ( β ) \sin(\alpha+\beta)=sin(\alpha)cos(\beta)+cos(\alpha)sin(\beta)\\
cos(\alpha+\beta)=cos(\alpha)cos(\beta)-sin(\alpha)sin(\beta) sin ( α + β ) = s in ( α ) cos ( β ) + cos ( α ) s in ( β ) cos ( α + β ) = cos ( α ) cos ( β ) − s in ( α ) s in ( β )
可以得到:
P E ( p o s + k , 2 i ) = P E ( p o s , 2 i ) P E ( k , 2 i + 1 ) + P E ( p o s , 2 i + 1 ) P E ( k , 2 i ) P E ( p o s + k , 2 i + 1 ) = P E ( p o s , 2 i + 1 ) P E ( k , 2 i + 1 ) − P E ( p o s , 2 i ) P E ( k , 2 i ) PE(pos+k,2i)=PE(pos,2i)PE(k,2i+1)+PE(pos,2i+1)PE(k,2i)\\
PE(pos+k,2i+1)=PE(pos,2i+1)PE(k,2i+1)-PE(pos,2i)PE(k,2i) PE ( p os + k , 2 i ) = PE ( p os , 2 i ) PE ( k , 2 i + 1 ) + PE ( p os , 2 i + 1 ) PE ( k , 2 i ) PE ( p os + k , 2 i + 1 ) = PE ( p os , 2 i + 1 ) PE ( k , 2 i + 1 ) − PE ( p os , 2 i ) PE ( k , 2 i )
我们令 u ( k ) = P E ( k , 2 i ) 、 v ( k ) = P E ( k , 2 i + 1 ) u(k)=PE(k,2i)、v(k)=PE(k,2i+1) u ( k ) = PE ( k , 2 i ) 、 v ( k ) = PE ( k , 2 i + 1 ) ,得:
[ P E ( p o s + k , 2 i ) P E ( p o s + k , 2 i + 1 ) ] = [ v ( k ) u ( k ) − u ( k ) v ( k ) ] [ P E ( p o s , 2 i ) P E ( p o s , 2 i + 1 ) ] \left[\begin{array}
{c}PE(pos+k,2i)\\ PE(pos+k,2i+1)
\end{array} \right]=
\left[\begin{array}
{c}v(k)&u(k)\\-u(k)&v(k)
\end{array} \right]
\left[\begin{array}
{c}PE(pos,2i)\\PE(pos,2i+1)
\end{array}\right] [ PE ( p os + k , 2 i ) PE ( p os + k , 2 i + 1 ) ] = [ v ( k ) − u ( k ) u ( k ) v ( k ) ] [ PE ( p os , 2 i ) PE ( p os , 2 i + 1 ) ]
给定相对距离 k k k ,P E ( p o s + k ) PE(pos+k) PE ( p os + k ) 与 P E ( p o s ) PE(pos) PE ( p os ) 之间具有线性关系
因此模型可以通过绝对位置 的编码来更好地捕捉单词的相对位置 关系
毫无疑问,位置编码在整个 Transformer 中的作用是巨大的
没有位置编码的 Tranformer 就是一个巨型词袋
接下来让我们看看正余弦位置编码的局限
相对距离的方向性
我们知道,点积 可以表示相对距离,注意力机制中就使用点积作为打分函数来获取 Q 、 K Q、K Q 、 K 的相似度,让我们 看看两个相对距离为 k 的位置编码的距离
对于 P E p o s PE_{pos} P E p os ,令 c i = 1 1000 0 2 i d c_i=\frac{1}{10000^{\frac{2i}{d}}} c i = 1000 0 d 2 i 1 :
P E p o s = [ P E ( p o s , 0 ) P E ( p o s , 1 ) P E ( p o s , 2 ) ⋮ P E ( p o s , d ) ] = [ s i n ( c 0 p o s ) c o s ( c 0 p o s ) s i n ( c 1 p o s ) ⋮ c o s ( c d 2 − 1 p o s ) ] \begin{align}
PE_{pos}&=
\left[\begin{array}
{c}PE(pos,0)\\PE(pos,1)\\PE(pos,2)\\ \vdots\\PE(pos,d)
\end{array}\right]\\
&=
\left[\begin{array}
{c}sin(c_0pos)\\cos(c_0pos)\\sin(c_1pos)\\\vdots\\cos(c_{\frac{d}{2}-1}pos)
\end{array}\right]
\end{align} P E p os = PE ( p os , 0 ) PE ( p os , 1 ) PE ( p os , 2 ) ⋮ PE ( p os , d ) = s in ( c 0 p os ) cos ( c 0 p os ) s in ( c 1 p os ) ⋮ cos ( c 2 d − 1 p os )
内积可得:
P E p o s T P E p o s + k = ∑ i = 0 d 2 − 1 s i n ( c i p o s ) s i n ( c i ( p o s + k ) ) + c o s ( c i p o s ) c o s ( c i ( p o s + k ) ) = ∑ i = 0 d 2 − 1 c o s ( c i ( p o s + k − p o s ) ) = ∑ i = 0 d 2 − 1 c o s ( c i k ) \begin{align}PE_{pos}^TPE_{pos+k}&=
\sum_{i=0}^{\frac{d}{2}-1}{sin(c_ipos)sin(c_i(pos+k))+cos(c_ipos)cos(c_i(pos+k))}\\
&=\sum_{i=0}^{\frac{d}{2}-1}
{cos(c_i(pos+k-pos))}\\
&=\sum_{i=0}^{\frac{d}{2}-1}cos(c_ik)
\end{align} P E p os T P E p os + k = i = 0 ∑ 2 d − 1 s in ( c i p os ) s in ( c i ( p os + k )) + cos ( c i p os ) cos ( c i ( p os + k )) = i = 0 ∑ 2 d − 1 cos ( c i ( p os + k − p os )) = i = 0 ∑ 2 d − 1 cos ( c i k )
而余弦函数是一个偶函数 ,因此正余弦位置编码仅能捕捉到两单词之间的距离关系,而无法判断其位置关系
自注意力对位置编码的影响
在 Transformer 中,位置编码之后会进行自注意力的计算,公式如下:
s c o r e ( x i ) = ( x i W Q ) ( x i W K ) T d = ( ( x i p o s i t i o n + x i w o r d ) W Q ) ( ( x i p o s i t i o n + x i w o r d ) W K ) T d score(x_i)=\frac{(x_iW_Q)(x_iW_K)^T}{\sqrt{d}}=\frac{((x_i^{position}+x_i^{word})W_Q)((x_i^{position}+x_i^{word})W_K)^T}{\sqrt{d}} score ( x i ) = d ( x i W Q ) ( x i W K ) T = d (( x i p os i t i o n + x i w or d ) W Q ) (( x i p os i t i o n + x i w or d ) W K ) T
可以看到,经过自注意力的计算,模型实际上是无法保留单词之间的位置信息
那么 Transformer 是如何 work 的呢?
题外话 :在 bert 中直接使用了 Learned Position Embedding 而非 Sinusoidal position encoding
解码块
Masked Multi-Head Attention
在机器翻译中,解码过程是一个顺序操作的过程,也就是当解码第 k k k 个特征向量时,我们只能看到第 k − 1 k-1 k − 1 及其之前的解码结果,因此使用了添加了 Mask,将当前词之后的词全都盖住
Endcoder-Decoder Attention
设计了一种解码块与编码块的交互模式
编码块最终的输入会生成不同的 K , V K,V K , V (在代码中是这样体现的),输入给所有的解码器,而 Q Q Q 则是来自于 Masked Multi-Head Attention
代码讲解
位置编码