第二步:将得到的单词表示向量矩阵 (如上图所示,每一行是一个单词的表示
x
x
x) 传入 Encoder 中,经过 6 个 Encoder block 后可以得到句子所有单词的编码信息矩阵
C
C
C,如下图。单词向量矩阵用
X
n
×
d
X_{n \times d}
Xn×d表示,
n
n
n 是句子中单词个数,
d
d
d 是表示向量的维度 (论文中
d
=
512
d = 512
d=512)。每一个 Encoder block 输出的矩阵维度与输入完全一致。
上图展示了 Transformer Encoder 编码句子信息。
第三步:将 Encoder 输出的编码信息矩阵
C
C
C 传递到 Decoder 中,Decoder 依次会根据当前翻译过的单词 1~ i 翻译下一个单词
i
+
1
i + 1
i+1,如下图所示。在使用的过程中,翻译到单词
i
+
1
i + 1
i+1 的时候需要通过 Mask (掩盖) 操作遮盖住
i
+
1
i + 1
i+1 之后的单词。
Transofrmer Decoder 预测。
上图 Decoder 接收了 Encoder 的编码矩阵
C
C
C,然后首先输入一个翻译开始符 “”,预测第一个单词 “I”;然后输入翻译开始符 “” 和单词 “I”,预测单词 “have”,以此类推。这是 Transformer 使用时候的大致流程,接下来是里面各个部分的细节。
二、Transformer 的输入
Transformer 中单词的输入表示
x
x
x 由单词 Embedding 和位置 Embedding (Positional Encoding)相加得到。
位置 Embedding 用 PE表示,PE 的维度与单词 Embedding 是一样的。PE 可以通过训练得到,也可以使用某种公式计算得到。在 Transformer 中采用了后者,计算公式如下:
P
E
(
p
o
s
,
2
i
)
=
sin
(
p
o
s
/
1000
0
2
i
/
d
)
P
E
(
p
o
s
,
2
i
+
1
)
=
cos
(
p
o
s
/
1000
0
2
i
/
d
)
PE_{(pos,2i)}=\sin(pos / 10000^{2i / d})\\ PE_{(pos,2i+1)}=\cos(pos / 10000^{2i / d})
PE(pos,2i)=sin(pos/100002i/d)PE(pos,2i+1)=cos(pos/100002i/d) 其中,pos表示单词在句子中的位置,
d
d
d表示 PE 的维度(与词 Embedding 一样),
2
i
2i
2i表示偶数的维度,
2
i
+
1
2i+1
2i+1表示奇数维度(即
2
i
≤
d
2i \leq d
2i≤d,
2
i
+
1
≤
d
2i+1 \leq d
2i+1≤d)。使用这种公式计算 PE 有以下的好处:
使 PE 能够适应比训练集里面所有句子更长的句子,假设训练集里面最长的句子是有 20 个单词,突然来了一个长度为 21 的句子,则使用公式计算的方法可以计算出第 21 位的 Embedding。
可以让模型容易地计算出相对位置,对于固定长度的间距
k
k
k,
P
E
(
p
o
s
+
k
)
PE_{(pos + k)}
PE(pos+k) 可以用
P
E
(
p
o
s
)
PE_{(pos)}
PE(pos) 计算得到。
因为
sin
(
A
+
B
)
=
sin
(
A
)
cos
(
B
)
+
cos
(
A
)
sin
(
B
)
,
cos
(
A
+
B
)
=
cos
(
A
)
cos
(
B
)
−
sin
(
A
)
sin
(
B
)
\sin(A + B) = \sin(A) \cos(B) + \cos(A) \sin(B), \cos(A + B) = \cos(A) \cos(B) - \sin(A) \sin(B)
sin(A+B)=sin(A)cos(B)+cos(A)sin(B),cos(A+B)=cos(A)cos(B)−sin(A)sin(B)。
将单词的词 Embedding 和位置 Embedding 相加,就可以得到单词的表示向量
x
x
x,
x
x
x 就是 Transformer 的输入。
上图是 Self-Attention 的结构,在计算的时候需要用到矩阵
Q
Q
Q(查询),
K
K
K(键值),
V
V
V(值)。
在实际中,Self-Attention 接收的是输入(单词的表示向量
x
x
x 组成的矩阵
X
X
X ) 或者上一个 Encoder block 的输出。而
Q
Q
Q,
K
K
K,
V
V
V正是通过 Self-Attention 的输入进行线性变换得到的。
3.2 Q, K, V 的计算
Self-Attention 的输入用矩阵
X
X
X 进行表示,则可以使用线性变阵矩阵
W
Q
W_Q
WQ,
W
K
W_K
WK,
W
V
W_V
WV 计算得到
Q
Q
Q,
K
K
K,
V
V
V。计算如下图所示,注意
X
X
X,
Q
Q
Q,
K
K
K,
V
V
V 的每一行都表示一个单词。
3.3 Self-Attention 的输出
得到矩阵
Q
Q
Q,
K
K
K,
V
V
V 之后就可以计算出 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
)
Attention(Q, K, V) = softmax(\frac{QK^T}{\sqrt{d_k}})
Attention(Q,K,V)=softmax(dkQKT)
d
k
d_k
dk是
Q
Q
Q,
K
K
K 矩阵的列数,即向量维度。
公式中计算矩阵
Q
Q
Q 和
K
K
K 每一行向量的内积,为了防止内积过大,因此除以
d
k
d_k
dk 的平方根。
Q
Q
Q 乘以
K
K
K 的转置后,得到的矩阵行列数都为
n
n
n,
n
n
n 为句子单词数,这个矩阵可以表示单词之间的 attention 强度。下图为
Q
Q
Q 乘以
K
T
K^T
KT,1234 表示的是句子中的单词。
【
Q
Q
Q 乘以
K
K
K 的转置的计算】
得到
Q
K
T
QK^T
QKT 之后,使用 Softmax 计算每一个单词对于其他单词的 attention 系数,公式中的 Softmax 是对矩阵的每一行进行 Softmax,即每一行的和都变为 1。
【对矩阵的每一行进行 Softmax】
得到 Softmax 矩阵之后可以和
V
V
V 相乘,得到最终的输出
Z
Z
Z。
【Self-Attention 输出】
上图中 Softmax 矩阵的第 1 行表示单词 1 与其他所有单词的 attention 系数,最终单词 1 的输出
Z
1
Z_1
Z1 等于所有单词
i
i
i 的值
V
i
V_i
Vi 根据 attention 系数的比例加在一起得到,如下图所示:
【
Z
i
Z_i
Zi 的计算方法】
3.4 Multi-Head Attention
在上一步,我们已经知道怎么通过 Self-Attention 计算得到输出矩阵
Z
Z
Z,而 Multi-Head Attention 是由多个 Self-Attention 组合形成的,下图是论文中 Multi-Head Attention 的结构图:
从上图可以看到 Multi-Head Attention 包含多个 Self-Attention 层,首先将输入
X
X
X 分别传递到
h
h
h 个不同的 Self-Attention 中,计算得到
h
h
h 个输出矩阵
Z
Z
Z。下图是
h
=
8
h = 8
h=8 时候的情况,此时会得到 8 个输出矩阵
Z
Z
Z。
得到 8 个输出矩阵
Z
1
Z_1
Z1到
Z
8
Z_8
Z8 之后,Multi-Head Attention 将它们拼接在一起 (Concat),然后传入一个 Linear 层,得到 Multi-Head Attention 最终的输出
Z
Z
Z。
可以看到 Multi-Head Attention 输出的矩阵
Z
Z
Z 与其输入的矩阵
X
X
X 的维度是一样的。
Add & Norm 层由 Add 和 Norm 两部分组成,其计算公式如下:
L
a
y
e
r
N
o
r
m
(
X
+
M
u
l
t
i
H
e
a
d
A
t
t
e
n
t
i
o
n
(
X
)
)
LayerNorm(X + MultiHeadAttention(X))
LayerNorm(X+MultiHeadAttention(X))
L
a
y
e
r
N
o
r
m
(
X
+
F
e
e
d
F
o
r
w
a
r
d
(
X
)
)
LayerNorm(X + FeedForward(X))
LayerNorm(X+FeedForward(X)) 其中
X
X
X 表示 Multi-Head Attention 或者 Feed Forward 的输入,MultiHeadAttention(
X
X
X) 和 FeedForward(
X
X
X) 表示输出 (输出与输入
X
X
X 维度是一样的,所以可以相加)。
Add 指
X
X
X + MultiHeadAttention(
X
X
X),是一种残差连接,通常用于解决多层网络训练的问题,可以让网络只关注当前差异的部分,在 ResNet 中经常用到:
Feed Forward 层比较简单,是一个两层的全连接层,第一层的激活函数为 Relu,第二层不使用激活函数,对应的公式如下:
max
(
0
,
X
W
1
+
b
1
)
W
2
+
b
2
\max(0, XW_1 + b_1)W_2 + b_2
max(0,XW1+b1)W2+b2
X
X
X 是输入,Feed Forward 最终得到的输出矩阵的维度与
X
X
X 一致。
4.3 组成 Encoder
通过上面描述的 Multi-Head Attention, Feed Forward, Add & Norm 就可以构造出一个 Encoder block,Encoder block 接收输入矩阵
X
(
n
×
d
)
X_{(n \times d)}
X(n×d),并输出一个矩阵
O
(
n
×
d
)
O_{(n \times d)}
O(n×d)。通过多个 Encoder block 叠加就可以组成 Encoder。
第一个 Encoder block 的输入为句子单词的表示向量矩阵,后续 Encoder block 的输入是前一个 Encoder block 的输出,最后一个 Encoder block 输出的矩阵就是编码信息矩阵
C
C
C,这一矩阵后续会用到 Decoder 中。
第二个 Multi-Head Attention 层的
K
K
K,
V
V
V 矩阵使用 Encoder 的编码信息矩阵
C
C
C 进行计算,而
Q
Q
Q 使用上一个 Decoder block 的输出计算;
最后有一个 Softmax 层计算下一个翻译单词的概率。
5.1 第一个 Multi-Head Attention
Decoder block 的第一个 Multi-Head Attention 采用了 Masked 操作,因为在翻译的过程中是顺序翻译的,即翻译完第
i
i
i 个单词,才可以翻译第
i
+
1
i + 1
i+1 个单词。通过 Masked 操作可以防止第
i
i
i 个单词知道
i
+
1
i + 1
i+1 个单词之后的信息。下面以 “我有一只猫” 翻译成 “I have a cat” 为例,了解一下 Masked 操作。
Decoder 可以在训练的过程中使用 Teacher Forcing 并且并行化训练,即将正确的单词序列 ( I have a cat) 和对应输出 (I have a cat ) 传递到 Decoder。那么在预测第
i
i
i 个输出时,就要将第
i
+
1
i + 1
i+1 之后的单词掩盖住,注意 Mask 操作是在 Self-Attention 的 Softmax 之前使用的,下面用 0 1 2 3 4 5 分别表示 “ I have a cat ”。
第二步:接下来的操作和之前的 Self-Attention 一样,通过输入矩阵
X
X
X 计算得到
Q
Q
Q,
K
K
K,
V
V
V 矩阵。然后计算
Q
Q
Q 和
K
T
K^T
KT 的乘积
Q
K
T
QK^T
QKT。
【
Q
Q
Q 乘以
K
K
K 的转置】
第三步:在得到
Q
K
T
QK^T
QKT 之后需要进行 Softmax,计算 attention score,我们在 Softmax 之前需要使用 Mask 矩阵遮挡住每一个单词之后的信息,遮挡操作如下:
【Softmax 之前 Mask】
得到 Mask
Q
K
T
QK^T
QKT 之后在 Mask
Q
K
T
QK^T
QKT 上进行 Softmax,每一行的和都为 1。但是单词 0 在单词 1, 2, 3, 4 上的 attention score 都为 0。
第四步:使用 Mask
Q
K
T
QK^T
QKT 与矩阵
V
V
V 相乘,得到输出
Z
Z
Z,则单词 1 的输出向量
Z
1
Z_1
Z1 是只包含单词 1 信息的。
【Mask 之后的输出】
第五步:通过上述步骤就可以得到一个 Mask Self-Attention 的输出矩阵
Z
i
Z_i
Zi ,然后和 Encoder 类似,通过 Multi-Head Attention 拼接多个输出
Z
i
Z_i
Zi 然后计算得到第一个 Multi-Head Attention 的输出
Z
Z
Z,
Z
Z
Z 与输入
X
X
X 维度一样。
5.2 第二个 Multi-Head Attention
Decoder block 第二个 Multi-Head Attention 变化不大, 主要的区别在于其中 Self-Attention 的
K
K
K,
V
V
V 矩阵不是使用 上一个 Decoder block 的输出计算的,而是使用 Encoder 的编码信息矩阵
C
C
C 计算的。
根据 Encoder 的输出
C
C
C 计算得到
K
K
K,
V
V
V,根据上一个 Decoder block 的输出
Z
Z
Z 计算
Q
Q
Q (如果是第一个 Decoder block 则使用输入矩阵
X
X
X 进行计算),后续的计算方法与之前描述的一致。