原文链接: http://chenhao.space/post/2a42add6.html
Transformer
以机器翻译为例:

其中 Add & Norm 层的意思是:将input到Multi-Head Attention中的 a a a,与Multi-Head Attention output的 b b b进行Add操作,得到 b ′ b' b′,再将 b ′ b' b′进行Layer Normalization。
Encoder:
Encoder总共包含 N = 6 N=6 N=6这样的相同的结构。该结构包含两个子层,分别为一个称为“Multi-Head Attention”的子层,和一个全连接的神经网络。这两个子层都采用了残差连接的方式,在加上了残差之后还做了一个归一化,公式表示为: N o r m ( x + S u b l a y e r ( x ) ) Norm(x+Sublayer(x)) Norm(x+Sublayer(x))其中 S u b l a y e r ( x ) Sublayer(x) Sublayer(x)代表每个特定的子层,为了保证残差的计算能够正常进行,每个子层的输出维度都规定为 d m o d e l = 512 d_{model}=512 dmodel=512。
Decoder:
Decoder总共包含 N = 6 N=6 N=6这样的相同的结构。该结构包含三个子层,分别为一个称为“Multi-Head Attention”的子层用于连接Encoder的输出,一个称为“Masked Multi-Head Attention”的子层,该层在“Multi-Head Attention”的基础上进行了调整(为使位置 t t t 处的预测仅依赖于 t t t 之前的输出, 在 Multi-Head Attention 内使用了mask),最后一个子层是一个全连接的神经网络。与Encoder相同,我们每一个子层都应用了残差连接并且进行了归一化。
Attention
引出Self-Attention

基于RNN模型的Sequence架构的缺点:Hard to parallel,很难进行并行计算。
于是有人提出用CNN替换RNN的想法。

上图这个模型中的CNN只能考虑非常有限的内容(只考虑了三个vector),但是CNN也可以考虑到更长的信息,通过叠加CNN:

CNN可以进行并行计算,但是它有个缺点就是需要叠加很多层才能看到长距离的信息。并⾏计算任意两个 位置相关性的操作随着距离的增加⽽增加,使得远距离位置之间的依赖学习变得更加困难。
所以提出了Self-Attention机制。
其中用 Self-Attention Layer 取代了 RNN Layer。
b i b^i bi is obtained based on the whole input sequence.
b 1 , b 2 , b 3 , b 4 b^1, b^2, b^3, b^4 b1,b2,b3,b4 can be parallelly computed.
Self-Attention的计算过程
关于 Q、K、V最直观简单的解释可以看这里: 对于Attention机制中Q,K,V的一些理解
q
q
q : query (to match others)
q
i
=
W
q
a
i
q^i=W^qa^i
qi=Wqai
k
k
k : key (to be matched)
k
i
=
W
k
a
i
k^i = W^ka^i
ki=Wkai
v
v
v : information to be extracted
v
i
=
W
v
a
i
v^i = W^va^i
vi=Wvai
接下来,拿每个 query
q
q
q 去对每个 key
k
k
k 做 attention。
x 1 , x 2 , x 3 , x 4 x^1,x^2,x^3,x^4 x1,x2,x3,x4 是输入的词序列, a 1 , a 2 , a 3 , a 4 a^1,a^2,a^3,a^4 a1,a2,a3,a4 是 word embedding。
先将 q 1 q^1 q1对 k 1 k^1 k1 做 attention,得到 α 1 , 1 α_{1,1} α1,1,将 q 1 q^1 q1对 k 2 k^2 k2 做 attention,得到 α 1 , 2 α_{1,2} α1,2,将 q 1 q^1 q1对 k 3 k^3 k3 做 attention,得到 α 1 , 3 α_{1,3} α1,3,将 q 1 q^1 q1对 k 4 k^4 k4 做 attention,得到 α 1 , 4 α_{1,4} α1,4。

然后将 α 1 , 1 , α 1 , 2 , α 1 , 3 , α 1 , 4 α_{1,1},α_{1,2},α_{1,3},α_{1,4} α1,1,α1,2,α1,3,α1,4 经过一个Softmax层进行归一化,得到 α ^ 1 , 1 , α ^ 1 , 2 , α ^ 1 , 3 , α ^ 1 , 4 \hatα_{1,1},\hatα_{1,2},\hatα_{1,3},\hatα_{1,4} α^1,1,α^1,2,α^1,3,α^1,4(它们都是一个数值)。
然后再将 α ^ 1 , 1 , α ^ 1 , 2 , α ^ 1 , 3 , α ^ 1 , 4 \hatα_{1,1},\hatα_{1,2},\hatα_{1,3},\hatα_{1,4} α^1,1,α^1,2,α^1,3,α^1,4 与 v 1 , v 2 , v 3 , v 4 v^1,v^2,v^3,v^4 v1,v2,v3,v4分别相乘,再求和,得到一个vector b 1 b^1 b1
我们注意到,产生的 b 1 b^1 b1 是考虑吧到了整个句子的信息。
类似的,我们可以并行计算得到 b 2 , b 3 , b 4 b^2,b^3,b^4 b2,b3,b4
Self-attention的并行化



Multi-head self-attention
- 所谓“多头”(Multi-Head),就是指多做几次同样的事情(参数不共享),然后把结果拼接
- 好处是可以允许模型在不同的表示子空间里学习到相关的信息
- 类似于CNN中多个卷积核的思想

2 heads as example
还可以将 b i , 1 , b i , 2 b^{i,1},b^{i,2} bi,1,bi,2进行concate,如果concate完之后这个dimension你不喜欢的话,可以乘一个参数矩阵进行降维,得到 b i b^i bi(也就是Multi-head self-attention最终的输出)。

细节补充
Residual connection
假设网络中某个层对输入
x
x
x作用后的输出
F
(
x
)
F(x)
F(x),那么增加residual connection之后,就变成了:
F
(
x
)
+
x
F(x)+x
F(x)+x
这里的+x
操作就是一个shortcut。
那么残差结构有什么好处?因为增加了一项 x x x,那么该层网络对 x x x求偏导的时候,多了一个常数项1,所以在反向传播过程中,梯度连乘,也不会造成梯度消失的问题。
LayerNorm
为什么要进行Normalization?learning rate 是不变的,但是在梯度大的时候我们希望lr更小,梯度小的时候lr大一些,所以通过数据归一化,使得梯度更加圆滑,可以使lr固定为一个值。
假设我们的输入是一个minibatch的数据,我们再假设每一个数据都是一个向量,则输入是一个矩阵,每一列是一个训练数据,每一行都是一个特征。BatchNorm是对每个特征进行Normalization,而LayerNorm是对每个样本的不同特征进行Normalization,因此LayerNorm的输入可以是一列(一个样本)。

Batch Normalization在CNN等地方用得很多。因为LayerNorm的每个样本都是独立计算的,因此minibatch可以很小甚至可以是1。LayerNorm多用于RNN的结构。
Mask
Transformer中涉及了两种mask,一种是padding mask,一种是sequence masking(也就是Masked Multi-Head Attention 中的mask)。后者是我们要重点讨论的。
Padding mask
因为在每个batch中的输入序列长度不一样,所以要闷要对输入序列进行对齐,具体来说,就是给较短的序列后面填充0
。因为这些填充的位置,其实是没什么意义的,所以我们的attention机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。
具体的做法是,把这些位置的值加上一个非常大的负数(可以是负无穷),这样的话,经过softmax,这些位置的概率就会接近0。
Sequence mask
Masked Multi-Head Attention层中的Masked是什么作用?
Sequence mask是为了使得decoder不能看见未来的信息。也就是对于一个序列,在time_step为t的时刻,我们的解码输出应该只能依赖于t时刻之前的输出,而不能依赖t之后的输出。因此我们需要想一个办法,把t之后的信息给隐藏起来。
具体的做法:
Masked Multi-Head Attention是Self-Attention,因此 Q = K = V Q=K=V Q=K=V,我们假设句子是这样的(其中 s 1 , s 2 , s 3 , s 4 s1,s2,s3,s4 s1,s2,s3,s4都是词向量,并假设两个句子的长度都是4 )

接下来进行计算 Q K T QK^T QKT

mask矩阵作用于 Q K T QK^T QKT上,可以得到

这里省略掉除以 d k \sqrt{d_k} dk,进行softmax可以得到

然后和 V V V相乘

那么使用 [ a 21 s 1 , a 22 s 2 , 0 , 0 ] [a_{21}s_1,a_{22}s_2,0,0] [a21s1,a22s2,0,0] 来预测第二个词的概率分布的时候,已经没有了第三个词、第四个词的信息,这就是让训练在生成当前词的时候不会注意到之后的词的原因。
Positional Encoding
截止目前为止,我们介绍的Transformer模型并没有捕捉顺序序列的能力,也就是说无论句子的结构怎么打乱,Transformer都会得到类似的结果。换句话说,Transformer只是一个功能更强大的词袋模型而已。为了解决这个问题,论文中在编码词向量时引入了位置编码(Position Embedding)的特征。具体地说,位置编码会在词向量中加入了单词的位置信息,这样Transformer就能区分不同位置的单词了。
- No position information in self-attention. 句子中的顺序信息没有被考虑到。
- Original paper : each position has a unique positional vector e i e^i ei (not learned from data)

其实也可以理解成下面这种计算形式:
- In other words : each x i x^i xi appends a one-hot vector p i p^i pi

论文中给出的编码公式是:

其中** p o s pos pos代表的是第几个词, 2 i 2i 2i表示偶数位置,使用正弦编码; 2 i + 1 2i+1 2i+1表示奇数位置,使用余弦编码**。
这个编码公式的意思就是:给定词语的位置 p o s pos pos,我们可以把它编码成 d m o d e l d_{model} dmodel维的向量。
上面公式计算的是绝对位置,同时它也能体现出词之间的相对位置,主要数学依据是以下公式:
s
i
n
(
α
+
β
)
=
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(α+β)=sinα·cosβ+cosα·sinβ \\cos(α+β)=cosα·cosβ-sinα·sinβ
sin(α+β)=sinα⋅cosβ+cosα⋅sinβcos(α+β)=cosα⋅cosβ−sinα⋅sinβ
两个位置
p
o
s
pos
pos 和
p
o
s
+
k
pos+k
pos+k 的位置编码是固定间距k的线性变化:
P
E
(
p
o
s
+
k
,
2
i
)
=
s
i
n
(
p
o
s
+
k
1000
0
2
i
d
m
o
d
e
l
)
PE_{(pos+k,2i)}=sin(\frac{pos+k}{10000^{\frac{2i}{d_{model}}}})
PE(pos+k,2i)=sin(10000dmodel2ipos+k)
= s i n ( p o s 1000 0 2 i d m o d e l ) ⋅ c o s ( k 1000 0 2 i d m o d e l ) + c o s ( p o s 1000 0 2 i d m o d e l ) ⋅ s i n ( k 1000 0 2 i d m o d e l ) =sin(\frac{pos}{10000^{\frac{2i}{d_{model}}}})·cos(\frac{k}{10000^{\frac{2i}{d_{model}}}}) + cos(\frac{pos}{10000^{\frac{2i}{d_{model}}}})·sin(\frac{k}{10000^{\frac{2i}{d_{model}}}}) =sin(10000dmodel2ipos)⋅cos(10000dmodel2ik)+cos(10000dmodel2ipos)⋅sin(10000dmodel2ik)
= 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 ) = PE_{(pos,2i)}·PE_{(k,2i+1)}+PE_{(pos,2i+1)}·PE_{(k,2i)} =PE(pos,2i)⋅PE(k,2i+1)+PE(pos,2i+1)⋅PE(k,2i)
P E ( p o s + k , 2 i + 1 ) = c o s ( p o s + k 1000 0 2 i d m o d e l ) PE_{(pos+k,2i+1)}=cos(\frac{pos+k}{10000^{\frac{2i}{d_{model}}}}) PE(pos+k,2i+1)=cos(10000dmodel2ipos+k)
= c o s ( p o s 1000 0 2 i d m o d e l ) ⋅ c o s ( k 1000 0 2 i d m o d e l ) − s i n ( p o s 1000 0 2 i d m o d e l ) ⋅ s i n ( k 1000 0 2 i d m o d e l ) =cos(\frac{pos}{10000^{\frac{2i}{d_{model}}}})·cos(\frac{k}{10000^{\frac{2i}{d_{model}}}}) - sin(\frac{pos}{10000^{\frac{2i}{d_{model}}}})·sin(\frac{k}{10000^{\frac{2i}{d_{model}}}}) =cos(10000dmodel2ipos)⋅cos(10000dmodel2ik)−sin(10000dmodel2ipos)⋅sin(10000dmodel2ik)
= 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,2i+1)}·PE_{(k,2i+1)}-PE_{(pos,2i)}·PE_{(k,2i)} =PE(pos,2i+1)⋅PE(k,2i+1)−PE(pos,2i)⋅PE(k,2i)
Scaled Dot-Product Attention

Scaled Dot-Product Attention:
α
1
,
i
=
q
1
⋅
k
i
/
d
k
α_{1,i}=q^1·k^i/\sqrt{d_k}
α1,i=q1⋅ki/dk
其中
q
1
q^1
q1 和
k
i
k^i
ki 做的操作是 dot product (点乘),
d
k
d_k
dk 是
q
q
q 和
k
k
k 的 dimension。
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(dkQKT)V
为什么除以 d k \sqrt{d_k} dk
Q={ q 1 , q 2 , q 3 , . . . , q d k q_1,q_2,q_3,...,q_{d_k} q1,q2,q3,...,qdk},K={ k 1 , k 2 , k 3 , . . . , k d k k_1,k_2,k_3,...,k_{d_k} k1,k2,k3,...,kdk},其中 q q q和 k k k都是标准正态分布的,所以 Q K T = ∑ i = 1 d q i k i QK^T=\sum_{i=1}^dq_ik_i QKT=∑i=1dqiki 服从均值为0,方差为 d k d_k dk的正态分布。下面给出证明:
当
d
k
d_k
dk越大,维度越大,方差也越大,也就意味着
Q
K
T
QK^T
QKT的分布离散,我们除以
d
k
\sqrt{d_k}
dk相当于把它标准化了,不然的话经过softmax,反向传播时会出现梯度消失的情况。
Q
K
T
−
0
(
均
值
)
d
k
=
Q
K
T
d
k
\frac{QK^T-0(均值)}{\sqrt{d_k}}=\frac{QK^T}{\sqrt{d_k}}
dkQKT−0(均值)=dkQKT
Why Self-Attention
- 时间复杂度较小
- 可以很好并行计算
- 可以捕获长距离依赖关系,一步到位捕捉全局关系
Attention Visualization

在上图中,每个word两两之间都进行了attention,所以也可以看作一个matrix。线条颜色越深代表attention的weight越大。
Isolated attentions from just the word ‘its’ for attention heads 5 and 6

很好的解决指代消歧问题。
在上图的两个句子中,it分别指代的对象不同,第一个句子的it指代的是animal,第二个句子指代的是street。
Multi-head Attention 中不同head的效果展示:
在上图中,红线图的query和key要找的明显是local部分的信息,每一个word都要attend到它之前的几个word。而在绿线图中,每个word要attend到很长时间点之后的word。
注:每个Head的参数不共享,所以它们attention到的效果也不一样。
总结
优点:
(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 Encoding也只是一个权宜之计,并没有改变Transformer结构上的固有缺陷。
参考资料
- Attention Is All You Need
- Transformer 模型的 PyTorch 实现
- 李宏毅Transformer视频
- The Annotated Transformer
- 详解Transformer
- Transformer图解
- 归一化
- Transformer的矩阵维度分析和Mask详解
- 对于Attention机制中Q,K,V的一些理解
致谢
感谢赵公子这一周陪我研究讨论Transformer内部的一些细节。