文章目录

这篇文章可以说是把Attention机制发扬光大的文章。提出了一个交Transformer的模型,对,就是变形金刚的那个transformer。Transformer模型只使用注意力机制(Attention mechanisms)来实现Encoder和Decoder,没有使用其他的RNN或者CNN。
Transformer模型是一个Seq2Seq的模型,即输入是一个序列,输出也为一个序列。
模型架构:
从模型架构上来看,主要有以下几个部分:
左侧是Encoder,右侧是Decoder,他们主要由以下模块组成:
- Input Embedding
- Positional Encoding
- Muti-Head Attention
- Norm
- Feed-Forward
- Output Embedding
Encoder和Decoder的数据流如图(以3个encoder和3个decoder为例):
接下来一一分解:
1. Attention
说到Attention,就得说两个东西:self-attention和multi-head attention:
1.1. Self-Attention
self-attention就是一个模型,这个模型只有三个训练参数:
- W q ∈ R k × n W_q \in \Bbb{R}^{k \times n} Wq∈Rk×n矩阵。
- W k ∈ R k × n W_k \in \Bbb{R}^{k \times n } Wk∈Rk×n矩阵。
- W v ∈ R v × n W_v\in \Bbb{R}^{v \times n } Wv∈Rv×n$矩阵。
对于每个输入的列向量 a i ∈ R n a_i \in \Bbb{R}^n ai∈Rn:
-
q i = W q a i q_i = W_q a_i qi=Wqai , q i q_i qi是k维列向量
k i , v i k_i, v_i ki,vi同理。
上图我们输入为a1,a2,a3,输入向量为b1,b2,b3,图中绘制出了b1的计算方法,b2,b3类似。
有以下几个步骤需要注意:
-
α i j \alpha_{ij} αij的计算
在计算 α i j \alpha_{ij} αij时,需要使用 q i q_i qi和 k j k_j kj来计算。有两种计算 α i j \alpha_{ij} αij的方法:
(1)点积法(Dot-Product Attention)
(2)相加法(Additive attention)
图片来自李宏毅深度学习ppt
这篇论文提出的Transformer使用的是Scaled Dot-Product Attention。顾名思义,就是在点积的基础上,对于得到的 α \alpha α再进行一次缩放,除以 d k \sqrt{d_k} dk。
d k d_k dk是k值和q值的维度(他俩维度相同)
在实际应用中点积法速度更快,而且空间效率更高。
在 d k d_k dk很小时,这两种方法表现差不多,但是当 d k d_k dk较大的时候,相加法效果就比没有缩放的点积法表现的更好。论文作者认为这是因为 d k d_k dk大的时候,点积的结果会变大。把softmax结果推入梯度更小的区域。
We suspect that for large values of dk, the dot products grow large in magnitude, pushing the softmax function into regions where it has extremely small gradients .
为了解决这个问题,才进行了一个除以 d k \sqrt{d_k} dk的缩放。
2. 矩阵化上述计算过程
根据图中描绘的计算过程,我们算出所有输入序列 a 1 . . . a k a_1...a_k a1...ak的q值 q 1 . . . q k q_1...q_k q1...qk,得到Q矩阵(列向量是q)
K、V矩阵同理。
假设我们使用的是点积(dot product)。那么我们的
α
i
=
q
i
⋅
k
i
T
\alpha_i = q_i \cdot k_i^T
αi=qi⋅kiT,所以
α
\alpha
α的矩阵为:
A
=
K
T
⋅
Q
\Alpha = K^T \cdot Q
A=KT⋅Q
接下来对A矩阵进行一个缩放(Scale),就是在我们得到的 A \Alpha A矩阵的每个元素都除以一个 d k \sqrt{d_k} dk,然后使用softmax对 A \Alpha A的每一列进行归一化处理。
最后计算b。b这里就不是矩阵乘法了。
v
i
v^i
vi是个列向量,
α
i
,
j
\alpha_{i,j}
αi,j是个数。
b
i
=
∑
j
v
j
α
i
,
j
′
b^i = \sum_jv^j\alpha'_{i,j}
bi=j∑vjαi,j′
Self-Attention过程的规范化表达:
这里的Q就是上面的 q i q_i qi构成的矩阵Q
不用在意点乘的顺序,思想是一样的,只是行列向量有区别。
在实现的时候,Decoder中Attention模块q计算时通过目标输出或者上一层encoder的输出来计算的,k、v是通过Encoder的输出来计算的。具体实现可见torch.nn.Modules.Transformer
1.2 Multi-Head Attention
Self-Attention是一个single-head attention版本(单头)。顾名思义,Multi-Head Attentions就是多个Self-Attention的叠加版本。
Multi-Head Attention的规范化表达:
这里Q似乎是我们前面所说的输入 a i a_i ai构成的输入序列矩阵,因为它乘以了权重。
输出层是通过多个self-Attention的向量结果进行横向联接然后通过一个线性层做映射。
2. Position encoding
Attention无法使用相对位置信息,如果要使用,就需将位置信息重新编码然后加到输入中。
有很多位置编码的方法:
位置编码的维度和输入Embedding后的维度相同,这样可以将位置编码的信息直接加到 α i \alpha_i αi上。
Transformer上使用的是三角函数的:
pos代表位置编号。
i代表特征的维度。偶数用上面的,奇数用下边的。
位置编码信息还可以使用指数的 e i e^i ei
3. Feed-Forward Networks
这个就是一个两层的全连接网络,第一层的激活函数为ReLU
F
F
N
(
x
)
=
R
e
L
U
(
x
W
1
+
b
1
)
W
2
+
b
2
FFN(x) = ReLU(xW_1+b_1)W_2+b_2
FFN(x)=ReLU(xW1+b1)W2+b2
输出层是512,隐藏层是2048。
4. Embeddings
这里使用的就是NLP中常用的Embedding方法。
5. Masking
应为是seq2seq模型,我们的输入序列不可能总是长度一样的。我们需要把他们设置成相同的长度,方法就是以最长的句子为基准,短的句子使用<padding>字符来填充。
假设我们的输入序列长度为5,但是我们的输入只有3个,那么这个序列为 s e q = { a 1 , a 2 , a 3 , p a d d i n g , p a d d i n g } seq =\{a_1, a_2, a_3, padding, padding\} seq={a1,a2,a3,padding,padding}
这样我们可以得到相同长度的序列了,但是带来一个新的问题,如果我们的句子很短,后面就有许多padding要跟着一起做运算。会不会影响我们Attention部分的输出呢?答案肯定是会的。不然也就没有masking啥事了。
Masking的原理:
原理很简单,我们再回顾一下b1是如何计算出来的:

b1是a1与其他的输入进行计算相关系数 α \alpha α的累加来的。假设上图中 a 3 a_3 a3是一个padding字符。我们只需要让 α 13 ′ \alpha_{13}' α13′为0,就可以忽略它的影响。
α 13 ′ \alpha_{13}' α13′为0,我们就需要 α 13 \alpha_{13} α13是一个较大的负数,这样经过softmax函数之后, α 13 ′ → 0 \alpha_{13}'\rightarrow 0 α13′→0。(注意这段话的 α ′ \alpha' α′和 α \alpha α)
论文中,有两种masking的方式:
- 在encoder中,我们只需要处理掉padding字符就行了。
- 在decoder中,我们的第i个位置的输出要依赖于前i-1个的输出,所以我们要把i以及之后的序列信息给masking掉。
6. Reference:
[1]. Vaswani A, Shazeer N, Parmar N, et al. Attention is all you need[J]. arXiv preprint arXiv:1706.03762, 2017.
[2]. 李宏毅深度学习课程2021