seq2seq入门详解:从RNN到Attention
1. 前馈神经网络的缺点
对于输入向量中个分量的位置信息不感知,也即无法利用序列型输入特征向量中的位置信息(将个分量调换顺序最后训练出的模型是等价的),但是在实际的任务中,各分量是有先后关系的。例如,我们在理解一段文本时,孤立地理解每个字或者词是不够的,还要将它们作为一个整体的序列来理解。
2. 循环神经网络RNN
2.1. RNN的基本结构与数学定义
输入层的维数是 ( n x , m , T x ) (n_x,m,T_x) (nx,m,Tx),其中 n x n_x nx是每个训练样本的维数,例如输入词one-hot向量的大小,也即词典大小; m m m是一个batch的大小; T x T_x Tx是输入序列的长度。
输出层的维数是 ( n y , m , T y ) (n_y,m,T_y) (ny,m,Ty),其中 n y n_y ny是输出预测向量的维数; m m m是一个batch的大小; T y T_y Ty是输出序列的长度。
我们先研究输入向量和输出向量相等,即
n
x
=
n
y
n_x=n_y
nx=ny的情况,结构图如下所示(图片来源https://www.coursera.org/learn/nlp-sequence-models/notebook/X20PE/building-a-recurrent-neural-network-step-by-step)。
上下标说明举例:
a
5
(
2
)
[
3
]
<
4
>
a_5^{(2)[3]<4>}
a5(2)[3]<4>表示第2个训练样本,第3层,第4个时刻,**函数输出向量的第5维。
每个RNN-Cell的内部结构见下图
注意,输出
y
^
\hat y
y^是状态向量
a
a
a经过线性变换再经过softmax变换得到的。
a
⟨
t
⟩
=
t
a
n
h
(
W
a
x
x
⟨
t
⟩
+
W
a
a
a
⟨
t
−
1
⟩
+
b
a
)
y
^
⟨
t
⟩
=
s
o
f
t
m
a
x
(
W
y
a
a
⟨
t
⟩
+
b
y
)
(2-1)
\begin{aligned} a^{\langle t\rangle}&=tanh\left(W_{ax}x^{\langle t\rangle}+W_{aa}a^{\langle t-1\rangle}+b_a\right)\\ \hat y^{\langle t\rangle}&=softmax\left(W_{ya}a^{\langle t\rangle}+b_y\right)\\ \tag{2-1} \end{aligned}
a⟨t⟩y^⟨t⟩=tanh(Waxx⟨t⟩+Waaa⟨t−1⟩+ba)=softmax(Wyaa⟨t⟩+by)(2-1)
需要注意的是,在不同的RNN-Cell中,上述公式里面的参数
W
,
b
W,b
W,b都是共享的。
2.2. 输入输出长度的讨论
2.2.1. n x = n y = n n_x=n_y=n nx=ny=n
第一种情况是输入输出长度相等的情况,如下图所示(图片来源https://www.jianshu.com/p/c5723c3bb921)
常用于序列标注模型,例如命名实体识别模型中。
2.2.2. n x = n , n y = 1 n_x=n,n_y=1 nx=n,ny=1
第二种情况是输入长度为N,输出长度为1(图片来源https://www.jianshu.com/p/c5723c3bb921)
模型只在最后一个时刻输出,常用于文本分类模型
2.2.3. n x = 1 , n y = n n_x=1,n_y=n nx=1,ny=n
第三种情况是输入长度为1,输出长度为N。uti实现时,可以将输入作为最开始时刻的输入,也可以作为所有时刻的输入(图片来源https://www.jianshu.com/p/c5723c3bb921)
常用于文字生成模型中。
2.2.4. n x = n , n y = m n_x=n,n_y=m nx=n,ny=m,Encoder-Decoder模型
第四种情况是输入长度为N,输出长度为M的情况,也即Encoder-Decoder模型(图片来源https://www.jianshu.com/p/c5723c3bb921)
常用于语音识别、机器翻译等场景。在后面的章节中我们会详细介绍Encoder-Decoder模型
3. RNN的复杂变种
3.1. GRU(Gated Recurrent Unit)
GRU的提出是为了解决RNN难以学习到输入序列中的长距离信息的问题。
GRU引入一个新的变量——记忆单元,简称
C
C
C。
C
⟨
t
⟩
C^{\langle t\rangle}
C⟨t⟩其实就是
a
⟨
t
⟩
a^{\langle t\rangle}
a⟨t⟩
C
C
C的表达式不是一步到位的,首先定义
C
C
C的候选值
C
~
\tilde C
C~:
C
~
⟨
t
⟩
=
t
a
n
h
(
W
c
[
C
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
c
)
\tilde C^{\langle t\rangle}=tanh\left(W_c[C^{\langle t-1\rangle},x^{\langle t\rangle}]+b_c\right)
C~⟨t⟩=tanh(Wc[C⟨t−1⟩,x⟨t⟩]+bc)
更新门:
Γ
u
=
σ
(
W
u
[
C
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
u
)
\Gamma_u=\sigma\left(W_u[C^{\langle t-1\rangle},x^{\langle t\rangle}]+b_u\right)
Γu=σ(Wu[C⟨t−1⟩,x⟨t⟩]+bu)
在实际训练好的网络中
Γ
\Gamma
Γ要么很接近1要么很接近0,对应着输入序列里面有些元素起作用有些元素不起作用。
C
⟨
t
⟩
=
Γ
u
∗
C
~
⟨
t
⟩
+
(
1
−
Γ
u
)
∗
C
⟨
t
−
1
⟩
C^{\langle t\rangle}=\Gamma_u*\tilde C^{\langle t\rangle}+(1-\Gamma_u)* C^{\langle t-1\rangle}
C⟨t⟩=Γu∗C~⟨t⟩+(1−Γu)∗C⟨t−1⟩
也即输入序列的有些元素,记忆单元不需要更新,有些元素需要更新。
The cat, which already ate …, was full
cat后面的词直到was之前,都不需要更新
C
C
C,直接等于cat对应的
C
C
C
可以解决梯度消失的问题.输出层的梯度可以传播到cat处
注:
C
C
C和
Γ
\Gamma
Γ都可以是想聊,它们在相乘时采用的是element-wise的乘法。当为向量时,与cat的单复数无关的词对应的
Γ
\Gamma
Γ可能有些维度为零,有些维度不为零。为零的维度,是用来保留cat的单复数信息的;不为零的维度可能是保留其他语义信息的,比如是不是food呀之类的
目前讨论的是简化版的GRU,结构图如下
完整的GRU:
C
~
⟨
t
⟩
=
t
a
n
h
(
W
c
[
Γ
r
∗
C
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
c
)
Γ
u
=
σ
(
W
u
[
C
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
u
)
Γ
r
=
σ
(
W
r
[
C
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
r
)
C
⟨
t
⟩
=
Γ
u
∗
C
~
⟨
t
⟩
+
(
1
−
Γ
u
)
∗
C
⟨
t
−
1
⟩
a
⟨
t
⟩
=
C
⟨
t
⟩
(3-1)
\begin{aligned} \tilde C^{\langle t\rangle}&=tanh\left(W_c[\Gamma_r*C^{\langle t-1\rangle},x^{\langle t\rangle}]+b_c\right)\\ \Gamma_u&=\sigma\left(W_u[C^{\langle t-1\rangle},x^{\langle t\rangle}]+b_u\right)\\ \Gamma_r&=\sigma\left(W_r[C^{\langle t-1\rangle},x^{\langle t\rangle}]+b_r\right)\\ C^{\langle t\rangle}&=\Gamma_u*\tilde C^{\langle t\rangle}+(1-\Gamma_u)* C^{\langle t-1\rangle}\\ a^{\langle t\rangle}&=C^{\langle t\rangle}\\ \tag{3-1} \end{aligned}
C~⟨t⟩ΓuΓrC⟨t⟩a⟨t⟩=tanh(Wc[Γr∗C⟨t−1⟩,x⟨t⟩]+bc)=σ(Wu[C⟨t−1⟩,x⟨t⟩]+bu)=σ(Wr[C⟨t−1⟩,x⟨t⟩]+br)=Γu∗C~⟨t⟩+(1−Γu)∗C⟨t−1⟩=C⟨t⟩(3-1)
Γ
r
\Gamma_r
Γr表示了
C
~
⟨
t
⟩
\tilde C^{\langle t\rangle}
C~⟨t⟩和
C
⟨
t
−
1
⟩
C^{\langle t-1\rangle}
C⟨t−1⟩之间的相关程度
3.2. LSTM(Long Short-Term Memory)
没有了
Γ
r
\Gamma_r
Γr,将
1
−
Γ
u
1-\Gamma_u
1−Γu用
Γ
f
\Gamma_f
Γf代替
C
~
⟨
t
⟩
=
t
a
n
h
(
W
c
[
a
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
c
)
Γ
u
=
σ
(
W
u
[
a
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
u
)
Γ
f
=
σ
(
W
f
[
a
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
f
)
Γ
o
=
σ
(
W
o
[
a
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
o
)
C
⟨
t
⟩
=
Γ
u
∗
C
~
⟨
t
⟩
+
Γ
f
∗
C
⟨
t
−
1
⟩
a
⟨
t
⟩
=
Γ
o
∗
t
a
n
h
(
C
⟨
t
⟩
)
y
~
⟨
t
⟩
=
s
o
f
t
m
a
x
(
a
⟨
t
⟩
)
(3-2)
\begin{aligned} \tilde C^{\langle t\rangle}&=tanh\left(W_c[a^{\langle t-1\rangle},x^{\langle t\rangle}]+b_c\right)\\ \Gamma_u&=\sigma\left(W_u[a^{\langle t-1\rangle},x^{\langle t\rangle}]+b_u\right)\\ \Gamma_f&=\sigma\left(W_f[a^{\langle t-1\rangle},x^{\langle t\rangle}]+b_f\right)\\ \Gamma_o&=\sigma\left(W_o[a^{\langle t-1\rangle},x^{\langle t\rangle}]+b_o\right)\\ C^{\langle t\rangle}&=\Gamma_u*\tilde C^{\langle t\rangle}+\Gamma_f* C^{\langle t-1\rangle}\\ a^{\langle t\rangle}&=\Gamma_o*tanh\left(C^{\langle t\rangle}\right)\\ \tilde y^{\langle t\rangle}&=softmax(a^{\langle t\rangle})\\ \tag{3-2} \end{aligned}
C~⟨t⟩ΓuΓfΓoC⟨t⟩a⟨t⟩y~⟨t⟩=tanh(Wc[a⟨t−1⟩,x⟨t⟩]+bc)=σ(Wu[a⟨t−1⟩,x⟨t⟩]+bu)=σ(Wf[a⟨t−1⟩,x⟨t⟩]+bf)=σ(Wo[a⟨t−1⟩,x⟨t⟩]+bo)=Γu∗C~⟨t⟩+Γf∗C⟨t−1⟩=Γo∗tanh(C⟨t⟩)=softmax(a⟨t⟩)(3-2)
(注意公式里面的
Γ
u
\Gamma_u
Γu等价于图片中的
Γ
i
\Gamma_i
Γi)
3.2.1. peephole连接
C ~ ⟨ t ⟩ = t a n h ( W c [ a ⟨ t − 1 ⟩ , a ⟨ t − 1 ⟩ , x ⟨ t ⟩ ] + b c ) Γ u = σ ( W u [ c ⟨ t − 1 ⟩ , a ⟨ t − 1 ⟩ , x ⟨ t ⟩ ] + b u ) Γ f = σ ( W f [ c ⟨ t − 1 ⟩ , a ⟨ t − 1 ⟩ , x ⟨ t ⟩ ] + b f ) Γ o = σ ( W o [ c ⟨ t ⟩ , a ⟨ t − 1 ⟩ , x ⟨ t ⟩ ] + b o ) C ⟨ t ⟩ = Γ u ∗ C ~ ⟨ t ⟩ + Γ f ∗ C ⟨ t − 1 ⟩ a ⟨ t ⟩ = Γ o ∗ t a n h ( C ⟨ t ⟩ ) y ~ ⟨ t ⟩ = s o f t m a x ( a ⟨ t ⟩ ) (3-3) \begin{aligned} \tilde C^{\langle t\rangle}&=tanh\left(W_c[a^{\langle t-1\rangle},a^{\langle t-1\rangle},x^{\langle t\rangle}]+b_c\right)\\ \Gamma_u&=\sigma\left(W_u[c^{\langle t-1\rangle},a^{\langle t-1\rangle},x^{\langle t\rangle}]+b_u\right)\\ \Gamma_f&=\sigma\left(W_f[c^{\langle t-1\rangle},a^{\langle t-1\rangle},x^{\langle t\rangle}]+b_f\right)\\ \Gamma_o&=\sigma\left(W_o[c^{\langle t\rangle},a^{\langle t-1\rangle},x^{\langle t\rangle}]+b_o\right)\\ C^{\langle t\rangle}&=\Gamma_u*\tilde C^{\langle t\rangle}+\Gamma_f* C^{\langle t-1\rangle}\\ a^{\langle t\rangle}&=\Gamma_o*tanh\left(C^{\langle t\rangle}\right)\\ \tilde y^{\langle t\rangle}&=softmax(a^{\langle t\rangle})\\ \tag{3-3} \end{aligned} C~⟨t⟩ΓuΓfΓoC⟨t⟩a⟨t⟩y~⟨t⟩=tanh(Wc[a⟨t−1⟩,a⟨t−1⟩,x⟨t⟩]+bc)=σ(Wu[c⟨t−1⟩,a⟨t−1⟩,x⟨t⟩]+bu)=σ(Wf[c⟨t−1⟩,a⟨t−1⟩,x⟨t⟩]+bf)=σ(Wo[c⟨t⟩,a⟨t−1⟩,x⟨t⟩]+bo)=Γu∗C~⟨t⟩+Γf∗C⟨t−1⟩=Γo∗tanh(C⟨t⟩)=softmax(a⟨t⟩)(3-3)
3.2.2 projection
对隐藏层状态a进行一次线性变换,降低其维数
C
~
⟨
t
⟩
=
t
a
n
h
(
W
c
[
a
⟨
t
−
1
⟩
,
a
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
c
)
Γ
u
=
σ
(
W
u
[
c
⟨
t
−
1
⟩
,
a
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
u
)
Γ
f
=
σ
(
W
f
[
c
⟨
t
−
1
⟩
,
a
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
f
)
Γ
o
=
σ
(
W
o
[
c
⟨
t
⟩
,
a
⟨
t
−
1
⟩
,
x
⟨
t
⟩
]
+
b
o
)
C
⟨
t
⟩
=
Γ
u
∗
C
~
⟨
t
⟩
+
Γ
f
∗
C
⟨
t
−
1
⟩
a
0
⟨
t
⟩
=
Γ
o
∗
t
a
n
h
(
C
⟨
t
⟩
)
a
⟨
t
⟩
=
W
p
r
o
j
a
0
⟨
t
⟩
+
b
p
r
o
j
y
~
⟨
t
⟩
=
s
o
f
t
m
a
x
(
a
⟨
t
⟩
)
(3-4)
\begin{aligned} \tilde C^{\langle t\rangle}&=tanh\left(W_c[a^{\langle t-1\rangle},a^{\langle t-1\rangle},x^{\langle t\rangle}]+b_c\right)\\ \Gamma_u&=\sigma\left(W_u[c^{\langle t-1\rangle},a^{\langle t-1\rangle},x^{\langle t\rangle}]+b_u\right)\\ \Gamma_f&=\sigma\left(W_f[c^{\langle t-1\rangle},a^{\langle t-1\rangle},x^{\langle t\rangle}]+b_f\right)\\ \Gamma_o&=\sigma\left(W_o[c^{\langle t\rangle},a^{\langle t-1\rangle},x^{\langle t\rangle}]+b_o\right)\\ C^{\langle t\rangle}&=\Gamma_u*\tilde C^{\langle t\rangle}+\Gamma_f* C^{\langle t-1\rangle}\\ a_0^{\langle t\rangle}&=\Gamma_o*tanh\left(C^{\langle t\rangle}\right)\\ a^{\langle t\rangle}&=W_{proj}a_0^{\langle t\rangle}+b_{proj}\\ \tilde y^{\langle t\rangle}&=softmax(a^{\langle t\rangle})\\ \tag{3-4} \end{aligned}
C~⟨t⟩ΓuΓfΓoC⟨t⟩a0⟨t⟩a⟨t⟩y~⟨t⟩=tanh(Wc[a⟨t−1⟩,a⟨t−1⟩,x⟨t⟩]+bc)=σ(Wu[c⟨t−1⟩,a⟨t−1⟩,x⟨t⟩]+bu)=σ(Wf[c⟨t−1⟩,a⟨t−1⟩,x⟨t⟩]+bf)=σ(Wo[c⟨t⟩,a⟨t−1⟩,x⟨t⟩]+bo)=Γu∗C~⟨t⟩+Γf∗C⟨t−1⟩=Γo∗tanh(C⟨t⟩)=Wproja0⟨t⟩+bproj=softmax(a⟨t⟩)(3-4)
4. Encoder-Decoder模型
由前面的章节我们知道,Encoder-Decoder模型就是输入输出长度为一般情况的RNN模型,示意图如下:
其中Encoder负责将输入进行编码,得到语义编码向量C;Decoder负责将语义编码向量C进行解码,得到输出。以机器翻译为例,英文作为输入,输出为中文。可以用如下的数学模型来表示:
i
n
p
u
t
=
l
t
x
1
,
x
2
,
⋯
,
x
n
g
t
C
=
f
(
i
n
p
u
t
)
y
i
=
g
(
C
,
y
1
,
y
2
,
⋯
,
y
i
−
1
)
,
i
=
1
,
2
,
⋯
,
m
o
u
t
p
u
t
=
l
t
y
1
,
y
2
,
⋯
,
y
m
g
t
(4-1)
\begin{aligned} input&=< x_1,x_2,\cdots,x_n >\\ C&=f(input)\\ y_i&=g( C,y_1,y_2,\cdots,y_{i-1} ),i=1,2,\cdots,m\\ output&=< y_1,y_2,\cdots,y_m >\\ \tag{4-1} \end{aligned}
inputCyioutput==f(input)=g(C,y1,y2,⋯,yi−1),i=1,2,⋯,m=ltx1,x2,⋯,xnlty1,y2,⋯,ymgtgt(4-1)
从Encoder得到C的方式有多种,可以将Encoder最后一个时刻的隐藏状态作为C,也可以将所有的隐藏状态进行某种变换得到C。
语义编码C在Decoder中的作用当时有多种,常见的有如下两种
(1) C作为Decoder的初始状态
h
0
h_0
h0。
(2) C作为Decoder的每一步输入。
4.1. 几种典型的encoder-decoder
4.1. 第一种
Cho et al.(2014) Learning Phrase Representations using RNN Encoder–Decoder for Statistical Machine Translation
https://zhuanlan.zhihu.com/p/70880679
4.2. Encoder-Decoder的缺点
- 对于输入序列的每个分量的重要程度没有区分,这和人的思考过程是不相符的,例如人在翻译的时候,对于某个一词多义的词,可能会结合上下文中某些关键词进行辅助判断。
- 如果在Decoder阶段,仅仅将C作为初始状态,随着时间往后推进,C的作用会越来越微弱。
事实上,Attention机制的提出,主要就是为了解决上述问题。
5. Attention机制详解
前面讲到,在一般形式的encoder-decoder中,输入信息先经过encoder编码保存在C中,C再被decoder使用。这种“直接粗暴”的方式,可能会导致输入信息没有被合理的利用,尤其是当输入信息过长的时候。为了解决这个问题,Attention机制被提出,解决的思路是:在decoder阶段,每个时间点输入的C是不同的(示意图如下图所示),需要根据当前时刻要输出的y去合理地选择输入x中的上下文信息。
具体来讲,就是对encoder的隐藏状态进行加权求和,以便得到不同的C,以中文翻译英文为例,示意图如下:
记
a
i
j
a_{ij}
aij为encoder中第
j
j
j个隐藏状态
h
j
h_j
hj到decoder中第
i
i
i个隐藏状态
h
i
′
h_i'
hi′对应的
c
i
c_i
ci的权重,可以通过训练确定的,具体计算方法见后文。attention机制的核心思想可以概括为"对输入信息加权求和得到编码信息c",也即如下公式:
c
i
=
∑
j
=
1
n
x
a
i
j
h
j
(5-1)
c_i=\sum_{j=1}^{n_x}a_{ij}h_j\tag{5-1}
ci=j=1∑nxaijhj(5-1)
5.1. attention机制中权重系数的计算过程
attention机制中权重系数有多种计算过程,对应于不同种类的attention机制。但是大部分的attention机制,都能表示为下文提到的三个抽象阶段。这里先引入几个概念。
我们将模型输入内容记为source,输出内容记为target。
source可以表示为一个一个的<key,value>,target则表示为一个一个的query。在机器翻译中,key和value合并为一个,就是输入句子中每个单词对应的隐藏层状态。
通过计算Query和各个Key的相似性或者相关性(需要进行softmax归一化),得到每个Key对应Value的权重系数,然后对Value进行加权求和,即得到了最终的Attention数值。
A
t
t
e
n
t
i
o
n
(
Q
u
e
r
y
i
,
S
o
u
r
c
e
)
=
∑
j
=
1
L
x
S
i
m
i
l
a
r
i
t
y
(
Q
u
e
r
y
,
k
e
y
j
)
∗
v
a
l
u
e
j
(5-2)
Attention(Query_i,Source)=\sum_{j=1}^{L_x}Similarity(Query,key_j)*value_j\tag{5-2}
Attention(Queryi,Source)=j=1∑LxSimilarity(Query,keyj)∗valuej(5-2)
具体来说可以分为三个阶段,如下图所示:
其中第一阶段计算相似性时有多种方法,例如向量点积、余弦相似度,甚至可以用一个小的神经网络来通过学习的方式计算。
第二阶段softmax归一化的公式如下:
a
i
j
=
s
o
f
t
m
a
x
(
S
i
j
)
=
e
x
p
(
S
i
m
i
j
)
∑
j
=
1
L
x
e
x
p
(
S
i
m
i
j
)
(5-3)
a_{ij}=softmax(S_{ij})=\frac{exp(Sim_{ij})}{\sum_{j=1}^{L_x}exp(Sim_{ij})}\tag{5-3}
aij=softmax(Sij)=∑j=1Lxexp(Simij)exp(Simij)(5-3)