Seq2seq模型及注意力机制

ryluo 2020-06-14 01:29:22
循环神经网络

Seq2Seq模型的结构及序列模型注意力的理解

Seq2Seq模型

我们知道Seq2Seq模型的结构是基于编码器-解码器,可以解决输入和输出序列不等长的问题,例如机器翻译问题。编码器和解码器本质上是两个RNN,其中编码器对输入序列进行分析编码成一个上下文向量(Context vector),解码器利用这个编码器生成的向量根据具体任务来进行解码,得到一个新的序列。

编码器

如下图所示为一个编码器的结构,就是将输入序列$x_1$至$x_4$依次输入到编码器中得到了$h_1$至$h_4$的隐含状态,而最终的上下文向量$c$,可以是编码器最后一个时间步的隐藏状态,也可以是编码器每个时间步得到的隐藏状态进行一个函数映射(就是使用某个度量函数去表示原始序列的信息),这个上下文向量后面会再解码器生成序列中。

preview

图二

解码器

下图是两种比较常见的Seq2Seq模型的结构,两个图的左半部分都是上面所说的编码器部分,而右半部分就是解码器部分了。如图二所示,其直接将编码器的输出作为解码器的初始隐藏状态,然后直接进行解码。图二是直接将编码器得到的上下文向量输入到解码器的每个时间步中,并且每个时间步的上下文向量是相同,换句话说就是解码器每个时间步都使用了相同的上下文向量。这两种情况可能带来的问题是,当需要编码的句子太长的时候,由于上下文向量能够存储信息的容量是有限的,所以可能会导致,信息的丢失,此外,解码器每个时间步的上下文向量都是一个相同的对输入序列的表征,对于上面两种问题,基于注意力机制的Seq2Seq模型给了很好的解决办法。

preview

图二

preview

图三

Attention机制的Seq2Seq

基于Attention的Seq2Seq模型本质上就是在上述的图三中的解码器部分进行了改进,在解码器的每个时间步上使用不同的上下文向量$c$如下图所示的$c_1,c_2,c_3$,但是对于解码器的初始化一般还是会使用编码器最后时间步的隐藏状态,即图中的$h’_0=c$(此处的c表示的是编码器最后时间步的隐藏状态),如何得到解码器不同时间步不同的上下文向量就是Attention要做的事情了。

preview

Attention机制生成的上下文向量可以自动的去选取与当前时间步输出最有用的信息,用有限的上下文向量的容量去表示当前时间步对输入信息最关注的那部分信息,最简单的做法就是对编码器输出的所有时间步的隐藏状态进行一个加权平均,不同的权值所对应的隐含状态就是对不同时间步的输入信息关的注程度,如下图就很清楚的说明了具体是怎么操作的(下图来自《动手学深度学习》第447页)。图中的$a$表示是编码器不同时间步对应的权值,而其权值又决定于编码器该时间步的隐藏状态以及解码器上一个时间步的隐藏状态(这里直接这么说比较绕,很容易看不明白,建议去看课本上的解释)。下面给出一个简单的解释:设解码器当前隐藏状态为$s_{t’} $

则无注意力的解码器当前的隐藏状态表示为:$s_{t’} = g(y_{t’-1}, c, s_{t’-1})$
基于注意力的解码器当前的隐藏状态表示为:$s_{t’} = g(y_{t’-1}, c_{t’}, s_{t’-1}) $

其中:

$y_{t’-1}: $解码器上一时间步的输出
$c: $编码器最后时间步(或者之前所有时间步隐藏状态的某种映射)的隐藏状态
$c_{t’}: $解码器在t’时间步通过注意力机制获得的的上下文向量
$s_{t’-1}: $解码器的$t’-1$时间步的隐藏状态

下面两个图是背景变量$c_t’$的生成过程,最后就剩下如何计算$a_{ij}$的值了。这里的a其实$a_{ij}$是注意力打分函数的输出,跟三部分东西有关系,分别是查询项$q(quary)$:解码器上一时间步的隐藏状态$s_{t’-1}$,键项k(key)和值项v(value)都是编码器的隐含状态($h_1, h_2, h_3$)。常见的注意力打分函数有:

加性模型:$ s_{(x_i,q)}= v^Ttanh(Wx_i+Uq)$
点积模型: $s_{(x_i,q)}= x_i^Tq$
缩放点积模型:$ s_{(x_i,q)}= \frac{x_i^Tq}{\sqrt{d}}$
双线性模型:$ s_{(x_i,q)}= x_i^TWq$

preview

点积模型可视化如下:

preview

最后基于注意力的Seq2Seq模型可以用下图进行表示:

Image Name

参考链接(知乎高赞文章):完全图解RNN、RNN变体、Seq2Seq、Attention机制
参考书籍: 《动手学深度学习》、《神经网络与深度学习》
注意力的具体实现参考代码,也可以更深刻的理解。