版权声明:本文为博主jmh原创文章,未经博主允许不得转载。 https://blog.csdn.net/jmh1996/article/details/84819936
前言
前一篇博客简要的介绍了一下传统的attention机制的基本思想, 本篇博客解读使用attention机制做机器翻译的第一篇论文,通过这篇论文看attention的使用方法。 论文: NEURAL MACHINE TRANSLATION BY JOINTLY LEARNING TO ALIGN AND TRANSLATE 论文地址:https://arxiv.org/pdf/1409.0473.pdf
论文motivation
这篇论文的motivation,就是在说attention之前的Encoder-Decoder机器翻译模型有一个明显的缺点:传统模型将源句子的所有信息都压缩成一个固定长度的向量,这样做的缺点是当句子长度很长的时候,模型无法利用句子前面部分的有效信息。换句话说,句子长了原来的技术都不好使了。 于是他们就提出了往Encoder-Decoder里面加入Attention机制的想法,加入这种想法以后模型可以同时学习如何进行翻译以及进行对齐。 如何进行翻译,大家都知道是啥意思。 那如何进行对齐是啥意思呢?其实这个就是Attention机制了。 还是上文那个例子: 源句: Tom chase Jerry. 翻译结果: 汤姆追逐杰瑞 我们可以看到,译文结果“汤姆”实际是对齐与“Tom”的,“追逐”对齐与chase。这个对齐,并不是唯一,因为翻译的时候肯定不是一个个对齐就能翻译好的。它其实是更想表达:译文“汤姆” 主要是根据“Tom”得到的,注意这里是“主要” 是一个高权值的思想。 于是这篇论文就是通过这种 对齐 来体现它的attention.
老生常谈
在Encoder-coder 模型框架里面,encoder复制先输入的句子的各个词的词向量,然后把它们压缩成一个句向量
c
c
c 。如果encoder和decoder都是使用rnn的话,就可以表示成:
c
=
q
(
h
1
,
h
2
,
…
,
h
T
x
)
c=q({h_{1},h_{2},\dots,h_{T_{x}}})
c = q ( h 1 , h 2 , … , h T x ) 其中
h
i
=
f
(
h
i
−
1
,
x
i
)
h_{i}=f(h_{i-1},x_{i})
h i = f ( h i − 1 , x i ) ,它是每个时间步iRNN隐藏层。
x是输入的各个词的词向量
X
=
(
x
1
,
x
2
,
…
,
x
T
x
)
X=(x_{1},x_{2},\dots,x_{T_{x}})
X = ( x 1 , x 2 , … , x T x ) .
f
,
q
f,q
f , q 是非线性激活函数。通常,人们取
c
=
h
T
x
c=h_{T_{x}}
c = h T x ,表示拿RNN的最后一个时间步的隐藏层输出作为句向量。 然后翻译的话就是在目标语言中,找到一个词串,使得下面的条件概率最大:
p
(
y
)
=
p
(
y
1
,
y
2
,
…
,
y
T
∣
c
)
=
p
(
y
1
∣
c
)
p
(
y
2
∣
{
y
1
,
c
}
)
p
(
y
3
∣
{
y
1
,
y
2
,
c
}
)
⋯
=
∏
t
=
1
t
=
T
p
(
y
t
∣
{
y
1
,
y
2
,
…
,
y
t
−
1
,
c
}
)
p(y)=p(y_{1},y_{2},\dots,y_{T}|c)=p(y_{1}|c)p(y_{2}|\{y_{1},c \})p(y_{3}|\{y_{1},y_{2},c \})\dots=\prod ^{t=T}_{t=1}p(y_{t}|\{y_{1},y_{2},\dots,y_{t-1},c\})
p ( y ) = p ( y 1 , y 2 , … , y T ∣ c ) = p ( y 1 ∣ c ) p ( y 2 ∣ { y 1 , c } ) p ( y 3 ∣ { y 1 , y 2 , c } ) ⋯ = t = 1 ∏ t = T p ( y t ∣ { y 1 , y 2 , … , y t − 1 , c } ) 其中
y
=
{
y
1
,
y
2
,
y
3
,
…
,
y
T
}
y=\{y_{1},y_{2},y_{3},\dots,y_{T}\}
y = { y 1 , y 2 , y 3 , … , y T } 是翻译结果,
T
T
T 是翻译结果的长度。 其中使用到的条件概率公式可以宏观的表示为:
p
(
y
t
∣
{
y
1
,
y
2
,
…
,
y
t
−
1
,
c
}
)
=
g
(
y
t
−
1
,
s
t
,
c
)
p(y_{t}|\{y_{1},y_{2},\dots,y_{t-1},c\})=g(y_{t-1},s_{t},c)
p ( y t ∣ { y 1 , y 2 , … , y t − 1 , c } ) = g ( y t − 1 , s t , c ) 。g是一个势能函数,
y
t
−
1
y_{t-1}
y t − 1 是上一步的输出,
s
t
s_{t}
s t 是decoder部分的rnn的隐藏层向量,而
c
c
c 就是输入句子的句向量。
以上是老生常谈的东西,使用一些符号来方便下面讲述attention.
核心的东西来啦
注意到在翻译的时候的,对于任意一个时间步
i
∈
{
1
,
2
,
…
,
T
}
i\in \{1,2,\dots,T\}
i ∈ { 1 , 2 , … , T } ,
条件概率
p
(
y
i
∣
{
y
1
,
y
2
,
…
,
y
i
−
1
,
c
}
)
=
g
(
y
i
−
1
,
s
i
,
c
)
p(y_{i}|\{y_{1},y_{2},\dots,y_{i-1},c\})=g(y_{i-1},s_{i},c)
p ( y i ∣ { y 1 , y 2 , … , y i − 1 , c } ) = g ( y i − 1 , s i , c ) 输入的
c
c
c 是固定的。
这样是不好的,于是作者就提出了每个时间步,
c
i
c_{i}
c i 是可以不同的想法。
把条件概率改写成:
p
(
y
i
∣
{
y
1
,
y
2
,
…
,
y
i
−
1
,
c
}
)
=
g
(
y
i
−
1
,
s
i
,
c
i
)
p(y_{i}|\{y_{1},y_{2},\dots,y_{i-1},c\})=g(y_{i-1},s_{i},c_{i})
p ( y i ∣ { y 1 , y 2 , … , y i − 1 , c } ) = g ( y i − 1 , s i , c i ) 而
s
i
s_{i}
s i 是decoder部分在第i个时间步的隐藏层,
c
i
c_{i}
c i 是Encoder部分的各个隐藏层的
h
j
h_{j}
h j 按某种权值的线性组合。
s
i
=
f
(
s
i
−
1
,
y
i
−
1
,
c
i
)
s_{i}=f(s_{i-1},y_{i-1},c_{i})
s i = f ( s i − 1 , y i − 1 , c i ) 也就是说在decoder部分,每一步的隐藏层计算的时候输入有三部分:上一步的输出,上一步的隐藏层,本步的
c
i
c_{i}
c i 。这个
c
i
c_{i}
c i 就是attention value.
那么这个
c
i
c_{i}
c i 是如何来的呢? 既然
c
i
c_{i}
c i 是encoder里面RNN的各个隐藏层的线性组合,那么必然有
c
i
=
α
1
h
1
+
α
2
h
2
+
⋯
+
α
T
x
h
T
x
c_{i}=\alpha_{1}h_{1}+\alpha_{2}h_{2}+\dots+\alpha_{T_{x}}h_{T_{x}}
c i = α 1 h 1 + α 2 h 2 + ⋯ + α T x h T x
T
x
T_{x}
T x 是输入句子的长度。 因此,如何确定其中的权值向量
α
\alpha
α 就是核心了。
论文提出的第i步的
c
i
c_{i}
c i 与Encoder的第j个隐藏层的权值
α
i
,
j
\alpha_{i,j}
α i , j 的计算方法为:
α
i
,
j
=
e
e
i
,
j
∑
k
=
1
T
x
e
e
i
,
k
\alpha_{i,j}=\frac{e^{e_{i,j}}}{\sum^{T_{x}}_{k=1} e^{e_{i,k}}}
α i , j = ∑ k = 1 T x e e i , k e e i , j 这是一个归一化势能函数,而
e
i
,
j
=
a
(
s
i
−
1
,
h
j
)
=
W
a
×
t
a
n
h
(
W
s
×
s
i
−
1
,
W
h
×
h
j
)
e_{i,j}=a(s_{i-1},h_{j})=W_{a} \times tanh(W_{s} \times s_{i-1},W_{h}\times h_{j})
e i , j = a ( s i − 1 , h j ) = W a × t a n h ( W s × s i − 1 , W h × h j )
e
i
,
j
e_{i,j}
e i , j 其实就一个以
s
i
−
1
,
h
j
s_{i-1},h_{j}
s i − 1 , h j 为输入的MLP。注意,这里面的
s
i
,
h
i
,
α
i
,
j
s_{i},h_{i},\alpha_{i,j}
s i , h i , α i , j 都是向量。
直观的理解
直观的理解就是,在decoder解码的时候,模型会拿着一个小型的MLP网络去encoder里面“扫描”一波,计算Encoder的各隐藏层向量
h
j
h_{j}
h j 中对于本次解码过程中的贡献权值,然后按照这些权值对各个
h
j
h_{j}
h j 进行线性组合。
显然对于decoder某个时间步i, 输入的向量中,肯定会有一个
h
j
h_{j}
h j 的权值
α
i
,
j
\alpha_{i,j}
α i , j 是最大的。而这个最大 就相当于把输入词
x
j
x_{j}
x j 与输出的
y
i
y_{i}
y i 对齐起来啦!!!!! 这也就是这篇文章所谓的 对齐 。
网络怎么训练呢
首先网络的结构还是使用的Encoder-Decoder框架,Encoder使用一个双层的LSTM,Decoder使用的是一个单层的LSTM.Attention的权值使用的是一个小型的MLP。 训练的时候,给定源句子
X
=
x
1
,
x
2
,
x
3
…
x
T
x
X={x_{1},x_{2},x_{3} \dots x_{T_{x}}}
X = x 1 , x 2 , x 3 … x T x ,比如说:
X
=
{
"
T
o
m
"
,
"
C
h
a
s
e
"
,
"
J
e
r
r
y
"
}
X=\{"Tom","Chase","Jerry"\}
X = { " T o m " , " C h a s e " , " J e r r y " } 。 首先,先从词嵌入向量表
l
o
o
k
u
p
lookup
l o o k u p 表找出Tom,chase,Jerry对应的词向量v(Tom),v(Chase),v(Jerry),v(< GO >)。注意其中的< GO>是一个翻译起始标志,主要是为了产生Decoder的起始隐藏层输入。 然后把这序列长度为4的序列输入到bilstm中,bilstm按照时间步展开后依次计算出
h
1
,
h
2
,
h
3
h_{1},h_{2},h_{3}
h 1 , h 2 , h 3 ,到了末尾就计算出来< GO>对应时间步的隐藏层
h
T
x
+
1
h_{T_{x} +1}
h T x + 1 。把这个
h
1
+
T
x
h_{1+T_{x}}
h 1 + T x 作为
s
0
s_{0}
s 0 。 OK,现在加入到Decoder了。 那么
c
1
c_{1}
c 1 怎么算呢? 拿着刚刚得到的
s
0
s_{0}
s 0 ,依次去和
h
1
,
h
2
,
h
3
h_{1},h_{2},h_{3}
h 1 , h 2 , h 3 两两匹配输入到那个计算权值的小MLP中,得到相应的打分
e
i
,
j
e_{i,j}
e i , j ,再对
e
i
,
j
e_{i,j}
e i , j 归一化一下得到权值。即:
e
1
,
1
=
a
(
s
0
,
h
1
)
=
W
a
×
t
a
n
h
(
W
s
×
s
0
,
W
h
×
h
1
)
e_{1,1}=a(s_{0},h_{1})=W_{a} \times tanh(W_{s} \times s_{0},W_{h}\times h_{1})
e 1 , 1 = a ( s 0 , h 1 ) = W a × t a n h ( W s × s 0 , W h × h 1 )
e
1
,
2
=
a
(
s
0
,
h
2
)
=
W
a
×
t
a
n
h
(
W
s
×
s
0
,
W
h
×
h
2
)
e_{1,2}=a(s_{0},h_{2})=W_{a} \times tanh(W_{s} \times s_{0},W_{h}\times h_{2})
e 1 , 2 = a ( s 0 , h 2 ) = W a × t a n h ( W s × s 0 , W h × h 2 )
e
1
,
3
=
a
(
s
0
,
h
3
)
=
W
a
×
t
a
n
h
(
W
s
×
s
0
,
W
h
×
h
3
)
e_{1,3}=a(s_{0},h_{3})=W_{a} \times tanh(W_{s} \times s_{0},W_{h}\times h_{3})
e 1 , 3 = a ( s 0 , h 3 ) = W a × t a n h ( W s × s 0 , W h × h 3 ) 再他们归一化一下:
α
1
,
1
=
e
1
,
1
e
1
,
1
+
e
1
,
2
+
e
1
,
3
\alpha_{1,1}=\frac{e_{1,1}}{e_{1,1}+e_{1,2}+e_{1,3}}
α 1 , 1 = e 1 , 1 + e 1 , 2 + e 1 , 3 e 1 , 1
α
1
,
2
=
e
1
,
2
e
1
,
1
+
e
1
,
2
+
e
1
,
3
\alpha_{1,2}=\frac{e_{1,2}}{e_{1,1}+e_{1,2}+e_{1,3}}
α 1 , 2 = e 1 , 1 + e 1 , 2 + e 1 , 3 e 1 , 2
α
1
,
3
=
e
1
,
3
e
1
,
1
+
e
1
,
2
+
e
1
,
3
\alpha_{1,3}=\frac{e_{1,3}}{e_{1,1}+e_{1,2}+e_{1,3}}
α 1 , 3 = e 1 , 1 + e 1 , 2 + e 1 , 3 e 1 , 3 然后在计算attention值:
c
1
c_{1}
c 1
c
1
=
α
1
,
1
×
h
1
,
1
+
α
1
,
2
×
h
1
,
2
+
α
1
,
3
×
h
1
,
3
c_{1}=\alpha_{1,1}\times h_{1,1}+\alpha_{1,2} \times h_{1,2}+\alpha_{1,3} \times h_{1,3}
c 1 = α 1 , 1 × h 1 , 1 + α 1 , 2 × h 1 , 2 + α 1 , 3 × h 1 , 3 然后,再计算Decoder的RNN的隐藏
s
1
s_{1}
s 1
s
1
=
f
(
s
0
,
y
0
,
c
1
)
s_{1}=f(s_{0},y_{0},c_{1})
s 1 = f ( s 0 , y 0 , c 1 ) ,其中
s
0
s_{0}
s 0 是< GO >标签对应的隐藏层向量,
y
0
y_{0}
y 0 是目标语库中句子的开头< start>对应的词向量。 然后计算词的概率分布
p
(
y
1
∣
c
1
,
y
0
)
=
g
(
s
1
,
y
0
,
c
1
)
p(y_{1}|c_{1},y_{0})=g(s_{1},y_{0},c_{1})
p ( y 1 ∣ c 1 , y 0 ) = g ( s 1 , y 0 , c 1 ) ,选择其中最大的概率的那个就是预测翻译的词
y
^
1
\hat y_{1}
y ^ 1 。 主要就完成了一轮了,接下来计算
c
2
c_{2}
c 2 。方法类似,但需要注意的是
s
2
=
f
(
s
1
,
c
2
,
y
1
)
s_{2}=f(s_{1},c_{2},y_{1})
s 2 = f ( s 1 , c 2 , y 1 ) ,其中的
y
1
y_{1}
y 1 是标准答案第一个词对应的词向量,并不是预测的
y
^
1
\hat y_{1}
y ^ 1 的词向量,这么选的原因是为了加快收敛速度。
这样一直迭代下去后,定义交叉熵损失函数,然后BTPP梯度下降去训练就是了。
网络怎么预测呢
预测方法和训练类似,只是计算
s
i
s_{i}
s i 有所不同: 预测时计算隐藏层
s
i
s_{i}
s i 中输入的词向量是上一次的预测词的向量,不再是标准答案的词的向量。这是因为:我们本来就是不知道标准答案呀。 即:
s
i
=
f
(
s
i
−
1
,
y
^
i
−
1
,
c
i
)
s_{i}=f(s_{i-1},\hat y_{i-1},c_{i})
s i = f ( s i − 1 , y ^ i − 1 , c i )
网络的效果怎么样
翻译效果: 这个图表说明了rnn+attention在翻译长句子的优势,普通的LSTM在处于长度大于30的句子就歇逼了,但是加入attention 当句子50以上也还是很棒的。
对齐效果: 这个图是可视化的方法是:在计算每一步的
c
i
c_{i}
c i 时,都会计算得到
α
i
,
j
\alpha_{i,j}
α i , j ,这是一个0-1的值,把它乘以255就可以转换为灰度了。 从结果可以看到,翻译结果的“南”和“韩” 都对齐到了“south korean”,而美国则对齐到了“the united state”,还是很正确的。