1. 基于注意力机制的编码器解码器
1.1 整体流程
1.1.1 基本概念
在这张架构图中,decoder的输入吃的都是同样的vector
而DCG的架构是这样的:
记
t
t
t为编码器中的时间步长,
t
′
t'
t′为解码器中的时间步长。
注意力机制模型类似于encoder-decoder模型,只不过,在编码解码器的连接部分有部分的差别。总的来说可以概括为下面4个步骤:
计算 value
在输入的数据中,每个单词或者字均由一个向量表示,按照标准LSTM流程输入到模型中,每一个timestamps都会有对应的隐藏状态,与普通LSTM模型不同的是,每一个timestamps得到的隐藏状态值均需要被保留下来。
先计算Query和key
这个时候初始化一个东西,
z
0
z^0
z0(这个东西是乱出来的,需要model学习),它的作用相当于一个Query,去匹配第一步中所有隐藏状态的输出值,对于每一个隐藏状态值
h
t
h^t
ht都计算一个匹配度(Key),计算匹配程度的算法叫做:match。在该步骤中,0代表第0时刻,
α
0
1
\alpha_0^1
α01由
z
0
z_0
z0和
h
1
h^1
h1共同计算得出,其意义在于,计算
z
0
z_0
z0和
h
1
h^1
h1的匹配程度,。
这样计算
z
0
z_0
z0和
h
i
h^i
hi四个的匹配程度后,得到
α
0
1
,
α
0
2
,
α
0
3
,
α
0
4
\alpha_0^1, \alpha_0^2, \alpha_0^3, \alpha_0^4
α01,α02,α03,α04,也就是上文提到的Key。
note:softmax层可加可不加,看情况而定。
在这一步骤中,
α
0
1
\alpha_0^1
α01由
z
0
z_0
z0和
h
1
h^1
h1共同计算得出,具体如何计算,则没有具体的要求,自主性比较大。一般可以抽象为如下表达式:
e
t
′
t
=
f
u
n
c
t
i
o
n
(
z
d
e
c
o
d
e
_
t
,
a
e
n
c
o
d
e
_
t
)
e_{t't}=function( z^{decode\_t}, a^{encode\_t})
et′t=function(zdecode_t,aencode_t)
有两个通常的方法:
- 构建一个小型的神经网络
- 通过向量空间中的內积
计算Attention的结果,并应用在解码器中
将第2步中的得到的匹配度(Key)与隐藏状态的值(Value)进行加权作为新的解码器在t时刻的输入也就是
c
0
c^0
c0。这个时候decoder解码器LSTM神经网络输出的值为“machine”,同时可以把隐藏状态
h
h
h或者记忆单元
c
c
c作为
z
1
z^1
z1。
1.2 抽象成Query、Key、Value
先上结论:
- Query对应 z z z
- Key对应 a a a
- Value对应 h h h
将Source中的构成元素想象成是由一系列的<Key,Value>数据对构成,此时给定Target中的某个元素Query,通过计算Query和各个Key的相似性或者相关性,得到每个Key对应Value的权重系数,然后对Value进行加权求和,即得到了最终的Attention数值。所以本质上Attention机制是对Source中元素的Value值进行加权求和,而Query和Key用来计算对应Value的权重系数。
1.3 具体说明
以下内容来自动手学深度学习。
1.3.1 计算背景变量
我们先描述第一个关键点,即计算背景变量。下图描绘了注意力机制如何为解码器在时间步2计算背景变量。首先,函数a根据解码器在时间步1的隐藏状态和编码器在各个时间步的隐藏状态计算softmax运算的输入。softmax运算输出概率分布并对编码器各个时间步的隐藏状态做加权平均,从而得到背景变量。
具体来说,令编码器在时间步t的隐藏状态为
h
t
\boldsymbol{h}_t
ht,且总时间步数为
T
T
T。那么解码器在时间步
t
′
t'
t′的背景变量为所有编码器隐藏状态的加权平均:
c
t
′
=
∑
t
=
1
T
α
^
t
′
t
h
t
,
\boldsymbol{c}^{t'} = \sum_{t=1}^T \hat{\alpha}_{t'}^{t} \boldsymbol{h}_t,
ct′=t=1∑Tα^t′tht,
其中给定
t
′
t'
t′时,权重
α
t
′
t
在
t
=
1
,
…
,
T
\alpha_{t' t}在t=1,\ldots,T
αt′t在t=1,…,T的值是一个概率分布。为了得到概率分布,我们可以使用softmax运算:
α
^
t
′
t
=
exp
(
α
t
′
t
)
∑
k
=
1
T
exp
(
α
t
′
t
)
,
t
=
1
,
…
,
T
.
\hat{\alpha}_{t'}^{t} = \frac{\exp(\alpha_{t'}^{t})}{ \sum_{k=1}^T \exp(\alpha_{t'}^{t}) },\quad t=1,\ldots,T.
α^t′t=∑k=1Texp(αt′t)exp(αt′t),t=1,…,T.
现在,我们需要定义如何计算上式中softmax运算的输入 α t ′ t \alpha_{t'}^{t} αt′t。由于 α t ′ t \alpha_{t'}^{t} αt′t同时取决于解码器的时间步 t ′ t' t′和编码器的时间步 t t t,我们不妨以解码器在时间步 t ′ − 1 t'-1 t′−1的隐藏状态 z t ′ − 1 \boldsymbol{z}_{t' - 1} zt′−1与编码器在时间步 t t t的隐藏状态 h t \boldsymbol{h}_t ht为输入,并通过函数 f u n c t i o n function function计算 α t ′ t ) \alpha_{t'}^{t}) αt′t):
e
t
′
t
=
f
u
n
c
t
i
o
n
(
z
t
′
−
1
,
h
t
)
.
e_{t' t} = function(\boldsymbol{z}_{t' - 1}, \boldsymbol{h}_t).
et′t=function(zt′−1,ht).
这里函数
f
u
n
c
t
i
o
n
function
function有多种选择,如果两个输入向量长度相同,一个简单的选择是计算它们的内积
f
u
n
c
t
i
o
n
(
z
,
h
)
=
z
⊤
h
function(\boldsymbol{z}, \boldsymbol{h})=\boldsymbol{z}^\top \boldsymbol{h}
function(z,h)=z⊤h。而最早提出注意力机制的论文则将输入连结后通过含单隐藏层的多层感知机变换 [1]:
f
u
n
c
t
i
o
n
(
z
,
h
)
=
v
⊤
tanh
(
W
z
z
+
W
h
h
)
function(\boldsymbol{z}, \boldsymbol{h}) = \boldsymbol{v}^\top \tanh(\boldsymbol{W}_z\boldsymbol{z} + \boldsymbol{W}_h \boldsymbol{h})
function(z,h)=v⊤tanh(Wzz+Whh)
其中
v
、
W
s
、
W
h
\boldsymbol{v}、\boldsymbol{W}_s、\boldsymbol{W}_h
v、Ws、Wh都是可以学习的模型参数。
1.3.2 矢量化计算
我们还可以对注意力机制采用更高效的矢量化计算。广义上,注意力机制的输入包括查询项以及一一对应的键项和值项,其中值项是需要加权平均的一组项。在加权平均中,值项的权重来自查询项以及与该值项对应的键项的计算。
在上面的例子中,查询项为解码器的隐藏状态,键项和值项均为编码器的隐藏状态。让我们考虑一个常见的简单情形,即编码器和解码器的隐藏单元个数均为
h
h
h,且函数
f
u
n
c
t
i
o
n
(
z
,
h
)
=
z
⊤
h
function(\boldsymbol{z}, \boldsymbol{h})=\boldsymbol{z}^\top \boldsymbol{h}
function(z,h)=z⊤h。
假设我们希望根据解码器单个隐藏状态
s
t
′
−
1
∈
R
h
\boldsymbol{s}_{t' - 1} \in \mathbb{R}^{h}
st′−1∈Rh和编码器所有隐藏状态
h
t
∈
R
h
,
t
=
1
,
…
,
T
\boldsymbol{h}_t \in \mathbb{R}^{h}, t = 1,\ldots,T
ht∈Rh,t=1,…,T来计算背景向量
c
t
′
∈
R
h
\boldsymbol{c}^{t'}\in \mathbb{R}^{h}
ct′∈Rh。
我们可以将查询项矩阵
Q
∈
R
1
×
h
设
为
s
t
′
−
1
⊤
\boldsymbol{Q} \in \mathbb{R}^{1 \times h}设为\boldsymbol{s}_{t' - 1}^\top
Q∈R1×h设为st′−1⊤,并令键项矩阵
K
∈
R
T
×
h
\boldsymbol{K} \in \mathbb{R}^{T \times h}
K∈RT×h和值项矩阵
V
∈
R
T
×
h
\boldsymbol{V} \in \mathbb{R}^{T \times h}
V∈RT×h相同且第
t
t
t行均为
h
t
⊤
\boldsymbol{h}_t^\top
ht⊤。此时,我们只需要通过矢量化计算
softmax
(
Q
K
⊤
)
V
\text{softmax}(\boldsymbol{Q}\boldsymbol{K}^\top)\boldsymbol{V}
softmax(QK⊤)V
即可算出转置后的背景向量
c
t
′
⊤
\boldsymbol{c}^{{t'}^\top}
ct′⊤。当查询项矩阵
Q
\boldsymbol{Q}
Q的行数为
n
n
n时,上式将得到
n
n
n行的输出矩阵。输出矩阵与查询项矩阵在相同行上一一对应。
1.3.3 更新隐藏状态
现在我们描述第二个关键点,即更新隐藏状态。以门控循环单元为例,在解码器中我们可以对“门控循环单元(GRU)”一节中门控循环单元的设计稍作修改,从而变换上一时间步 t ′ − 1 的 输 出 y t ′ − 1 t'-1的输出\boldsymbol{y}_{t'-1} t′−1的输出yt′−1、隐藏状态 s t ′ − 1 \boldsymbol{s}_{t' - 1} st′−1和当前时间步 t ′ t' t′的含注意力机制的背景变量 c t ′ \boldsymbol{c}_{t'} ct′。解码器在时间步 t ’ t’ t’的隐藏状态为
z
t
′
=
s
t
′
⊙
z
t
′
−
1
+
(
1
−
s
t
′
)
⊙
z
~
t
′
,
\boldsymbol{z}_{t'} = \boldsymbol{s}_{t'} \odot \boldsymbol{z}_{t'-1} + (1 - \boldsymbol{s}_{t'}) \odot \tilde{\boldsymbol{z}}_{t'},
zt′=st′⊙zt′−1+(1−st′)⊙z~t′,
其中的重置门、更新门和候选隐藏状态分别为
r
t
′
=
σ
(
W
y
r
y
t
′
−
1
+
W
z
r
z
t
′
−
1
+
W
c
r
c
t
′
+
b
r
)
,
s
t
′
=
σ
(
W
y
z
y
t
′
−
1
+
W
z
s
s
t
′
−
1
+
W
c
s
c
t
′
+
b
s
)
,
z
~
t
′
=
tanh
(
W
y
z
y
t
′
−
1
+
W
z
z
(
z
t
′
−
1
⊙
r
t
′
)
+
W
c
z
c
t
′
+
b
z
)
,
\begin{aligned} \boldsymbol{r}_{t'} &= \sigma(\boldsymbol{W}_{yr} \boldsymbol{y}_{t'-1} + \boldsymbol{W}_{zr} \boldsymbol{z}_{t' - 1} + \boldsymbol{W}_{cr} \boldsymbol{c}_{t'} + \boldsymbol{b}_r),\\ \boldsymbol{s}_{t'} &= \sigma(\boldsymbol{W}_{yz} \boldsymbol{y}_{t'-1} + \boldsymbol{W}_{zs} \boldsymbol{s}_{t' - 1} + \boldsymbol{W}_{cs} \boldsymbol{c}_{t'} + \boldsymbol{b}_s),\\ \tilde{\boldsymbol{z}}_{t'} &= \text{tanh}(\boldsymbol{W}_{yz} \boldsymbol{y}_{t'-1} + \boldsymbol{W}_{zz} (\boldsymbol{z}_{t' - 1} \odot \boldsymbol{r}_{t'}) + \boldsymbol{W}_{cz} \boldsymbol{c}_{t'} + \boldsymbol{b}_z), \end{aligned}
rt′st′z~t′=σ(Wyryt′−1+Wzrzt′−1+Wcrct′+br),=σ(Wyzyt′−1+Wzsst′−1+Wcsct′+bs),=tanh(Wyzyt′−1+Wzz(zt′−1⊙rt′)+Wczct′+bz),
其中含下标的
W
\boldsymbol{W}
W和
b
\boldsymbol{b}
b分别为门控循环单元的权重参数和偏差参数。
2. self-Attention
其实,在上文提到的Attention模型中,存在一个严重性的问题,也就是LSTM网络的致命缺陷,没有办法并行化计算,必须等上一个时刻神经元输出后才能够进行本时刻的计算。
因此,有的学者为了加快计算速度,提出了使用卷积的方法代替LSTM中 h t h^t ht的值,但是这种方法存在一个弊端:提取信息的大小只和超参数卷积核的大小有关,而且没有办法处理长期的信息(卷积核大小毕竟有限)。所以,就提出了这种Transformer架构,里面用到的思想就是self Attention的方法。
2.1 Self-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,然后将每一个
a
i
a^i
ai都乘上三个矩阵,得到对应的
q
i
,
k
i
,
v
i
q^i, k^i, v^i
qi,ki,vi,再将
q
j
q^j
qj分别对每一个
k
i
k^i
ki进行attention操作得到
a
j
1
,
a
j
2
,
a
j
3
,
a
j
4
a_{j1},a_{j2}, a_{j3}, a_{j4}
aj1,aj2,aj3,aj4。其中,
q
j
q^j
qj对
k
i
k^i
ki的公式为:
a
i
j
=
q
i
k
j
/
k
a_{ij}=q^i k^j/\sqrt{k}
aij=qikj/k
d
d
d是
q
,
k
q, k
q,k的维度数,除以
d
\sqrt{d}
d的原因是:
q
,
k
q,k
q,k的维度越大,则他们的乘积就越大,所以需要正则化。
再之后,将每一个
a
i
j
a_{ij}
aij通过一个softmax值得到
a
^
i
j
\hat{a}_{ij}
a^ij
重复上述过程,则可以得到输出序列
b
1
,
b
2
,
b
3
,
b
4
b^1, b^2, b^3, b^4
b1,b2,b3,b4。
那么,如何并行化呢?
首先将所有的
a
i
a^i
ai都拼起来,得到
I
I
I,乘上同一个矩阵
W
q
W^q
Wq得到
Q
Q
Q,以此类推得到
K
,
V
K, V
K,V
在得到
Q
,
K
,
V
Q, K, V
Q,K,V之后,按照之前的步骤,需要计算
a
^
i
j
\hat{a}_{ij}
a^ij,于是,将
k
j
k^j
kj全部拼起来,就有了下面的结果:
并行计算
b
b
b
2.2 Muti-head Self-Attention流程
这里以两个head为例:
做多头的好处:每个head的关注点都不一样,可以获得更加精确的值。
2.2.1 多头attention中句子的位置信息
在上述的算法过程中,输入数据的位置信息并没有影响到输出,为了增加输入数据的合理性,于是在计算 a i a^i ai时,增加了一个记录位置信息的向量 e i e^i ei,每一个 x i x^i xi都对应这不同的 e e e
e
e
e为什么是加到
a
i
a^i
ai上?这里给出了解释:
假设
p
i
p^i
pi是一个one-hot的向量,代表了
x
x
x位置的信息
2.3 Transformer的网络架构如下:
Transformer最大的改进在于,将Encode-Decode 层数叠了上去,而不仅仅是1.1节中的单层网络。在叠加的多层中,每一层都是使用了attention机制,Attention的来源就是来自于最初的输入信息,这个和ResNet有点像,都是跨层进行连接的。
2.3.1 self-Attention层
2.4 self-Attention层
还是在第一节中提到的
(
K
Q
V
)
(KQV)
(KQV)的应用。
假设我们想要重新表示
e
2
e_2
e2也就是计算
e
2
e_2
e2的权重时,需要进行以下操作:
计算key和Query
首先把目标 e 2 e_2 e2通过一个 f u n c t i o n function function变换成 Q u e r y Query Query(在1.1节的单层中是和解码器的 t ′ − 1 t'-1 t′−1时刻的隐藏状态联系起来,求解Query的)然后把 e 2 e_2 e2的邻居们,或者是所有的输入都看成是key
3. 通用的一些技巧
3.1 regularization attention
在注意力机制中,有时候注意力可能仅仅集中在某几个特殊的状态中,例如:
这个时候输出的结果可能就只有妹子了,那么怎么办,我们希望注意力集能够均匀分布,因此需要正则化,所以:
3.2 Mismatch test data
在RNN的Seq2Seq模型的训练过程中,不管训练输出的结果是啥,都使用的正确输入数据作为下一时刻的输入。
这样的方式可能会造成一个问题,那就是在生成数据的时候,可能你第一个输出就是错误的,这样的结果就是错上加错。
解决方法:
- Beam搜索
即每个可能的输出都进行一次运算,保留可能性最大的K个值作为下一时刻的输入。
参考文献
- Attention Is All You Need - NIPS 2017: 5998-6008 - 论文链接
- 发表时间:2017 - 发表单位:Google - transformer原理参考文章
- transformer中文讲解视频(简单)
- transformer中文讲解视频(进阶)
- 哈佛大学的ptorch版transformer代码实现