seq2seq学习笔记

来源:互联网 发布:5.1声道耳机推荐 知乎 编辑:程序博客网 时间:2024/06/17 08:39

2017-04-23 更新说明:
今天重新看了一下之前写的这个文章,然后发现当时对模型的理解存在一个非常严重的错误,主要是 Decoder 部分,我之前以为 Encoder 输出的固定长度的 状态向量 C 只是 LSTMs2 的一个初始状态 h0 而已,但是实际上并不是这样的,所以向之前看过这篇文章而造成错误理解的朋友表示抱歉。下文中的内容我已经改过来了。

=========================================

1. RNN基础

对于RNN,我看到讲得最通俗易懂的应该是Andrej发的博客:
The Unreasonable Effectiveness of Recurrent Neural Networks](http://karpathy.github.io/2015/05/21/rnn-effectiveness/)

这里有它的中文翻译版本:
递归神经网络不可思议的有效性](http://www.csdn.net/article/2015-08-28/2825569)

如果想了解 LSTM 的原理,可以参考这篇文章:(译)理解 LSTM 网络 (Understanding LSTM Networks by colah)。
下面的连接中对RNN还有BPTT(RNN的反向传播算法),LSTM和GRU的原理和实现讲解得也是非常棒:
http://www.wildml.com/2015/09/recurrent-neural-networks-tutorial-part-1-introduction-to-rnns/

2.seq2seq

2.1 seq2seq是什么

首先介绍几篇比较重要的 seq2seq 相关的论文:
[1] Cho et al., 2014 . Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation
[2] Sutskever et al., 2014. Sequence to Sequence Learning with Neural Networks
[3] Bahdanau et al., 2014. Neural Machine Translation by Jointly Learning to Align and Translate
[4] Jean et. al., 2014. On Using Very Large Target Vocabulary for Neural Machine Translation

顾名思义,seq2seq 模型就像一个翻译模型,输入是一个序列(比如一个英文句子),输出也是一个序列(比如该英文句子所对应的法文翻译)。这种结构最重要的地方在于输入序列和输出序列的长度是可变的。

举个栗子

在机器翻译:输入(hello) -> 输出 (你好)。输入是1个英文单词,输出为2个汉字。
在对话机器中:我们提(输入)一个问题,机器会自动生成(输出)回答。这里的输入和输出显然是长度没有确定的序列(sequences).

要知道,在以往的很多模型中,我们一般都说输入特征矩阵,每个样本对应矩阵中的某一行。就是说,无论是第一个样本还是最后一个样本,他们都有一样的特征维度。但是对于翻译这种例子,难道我们要让每一句话都有一样的字数吗,那样的话估计五言律诗和七言绝句又能大火一把了,哈哈。但是这不科学呀,所以就有了 seq2seq 这种结构。

论文[1] 算是比较早提出 Encoder-Decoder 这种结构的,其中 Encoder 部分应该是非常容易理解的,就是一个RNNCell(RNN ,GRU,LSTM 等) 结构。每个 timestep, 我们向 Encoder 中输入一个字/词(一般是表示这个字/词的一个实数向量),直到我们输入这个句子的最后一个字/词 < EOS> ,得到最后的一个状态值 c(一般情况下, c=hXT,XT 是最后一个输入)。因为 RNN 的特点就是把前面每一步的输入信息都考虑进来了,所以理论上这个 c 就能够把整个句子的信息都包含了,我们可以把 C 当成这个句子的一个语义表示,也就是一个句向量。在 Decoder 中,我们根据 Encoder 得到的句向量 c, 一步一步地把蕴含在其中的信息分析出来。论文[1] 中的公式表示如下:

h<t>=f(h<t1>,yt1,c)

同样,根据 h<t> 我们就能够求出 yt 的条件概率:

P(yt|yt1,yt2,...,y1,c)=g(h<t>,yt1,c)

至于这里的两个函数 f 和 g, 论文中并没有给出具体的公式,但是一般来说,f 函数结构应该是一个 RNNCell 结构或者类似的结构,g 函数一般是 softmax (或者是论文 [4] 中提出的 sampled_softmax 函数)。我们可以先这样来理解:在 Encoder 中我们得到了一个涵盖了整个句子信息的实数向量 c ,现在我们一步一步的从 c 中抽取信息。首先给 Decoder 输入一个启动信号 y0(GO), 然后Decoder 根据 h<0>,y0,c (一般可以把h<0>初始化为0或者其他值),就能够计算出 y1 的概率分布了,以此类推直到预测到结束的特殊标志 < EOS>,才结束预测。值得注意的是,在 Decoder 中, 每次预测(yt), 输入除了用到 h<t1>, yt1 以外, 还有 c, 也就是每个 timestep, RNNCell 有三个输入,而之前接触的模型都是两个输入。

至于 f 函数和 g 函数的具体形式长啥样,文中没有具体的公式。暂时我也还没整清楚,后面有时间的话准备把 TensorFlow 中的 seq2seq 代码撸一遍,到时候就一清二楚了。敬请期待哈哈哈~

论文 [2] 是 Google 的 seq2seq 模型, Encoder 和 Decoder 都是 4 层的 LSTM 。但是遗憾的是论文中也没有具体的公式。

论文[3] 是在 Encoder 和 Decoder 的基础上提出了注意力机制。在上面提到的结构中,每次预测都是从句向量 c 中进行信息提取。但是如果句子很长的话,c 未必能把所有的信息都保留好呀,所以就有了 Attention Model 这样一种东西出现了,它的出现让机器翻译的效果大大地提升了。在这里我就不做展开,有兴趣的可以参考下面这篇文章,讲得非常好:张俊林: 自然语言处理中的Attention Model:是什么及为什么

论文[4]介绍了机器翻译在训练时经常用到的一个方法(小技巧)sample_softmax ,主要解决词表数量太大的问题。

关于seq2seq是什么,下面几篇文章讲得挺不错的,可以参考。
seq2seq模型
使用机器学习进行语言翻译:神经网络和seq2seq为何效果非凡?

2.2 seq2seq模型分析

seq2seq模型由两个RNNs( 一般是LSTMs: LSTM可以理解为一种升级版的RNN)构成。其中一个LSTMs理解为encoder,我们就用LSTMs1来称呼它;另外一个为decoder,我们用LSTMs2来表示。

在论文中,每个LSTMs都是4层的(MultiLSTMCell),论文中提到深层的LSTMs表现比浅层的要好很多。但是为了方便理解,我们只拿一个LSTM层的网络来分析就好了,思路是一样的。直观上的模型是这样的:

来自论文[5]
注:模型图中的颜色框是本人加上去的,便于理解。绿色框部分对应的是LSTM1(encoder),红色框部分对应的是LSTM2(decoder)。

在模型中,输入一个sentence “ABC” ,会得到输出 “WXYZ” 作为翻译的结果。可以看到输出和输入的长度是不相同的,因为模型会不断地根据前面的状态和结果来预测下一个输出的符号。当模型预测到要输出一个 < EOS >(end-of-sentence ) token(符号)的时候,它才会停止输出。

我们把这个模型展开来看如下图(2017-04-23更新):



fig1. seq2seq 按时间展开的结构

上图主要参考了论文[1],下面是对图中的符号进行解释(原文中没有这么详细的解释,这是我根据个人的理解写下来的,欢迎指出错误):

** xiϵRn×1(i=1,2,...,T) ——> 每个x表示输入源的一个词向量(word embedding),比如文中用的是1000维的词向量,那么有n=1000. (当然我们也可以用ont-hot 词向量来输入,然后加上一个Embedding layer)。
** yiϵRn×1(i=1,2,...,T) ——> 每个y表示输出源的一个词向量。比如文中是把英文翻译为法语,输入源就是英文词汇,输出源是法语词汇。假设两种词汇都是用相同长度的词向量的话,那么xy的维度是一样的。
** hi,hjϵRk×1(i=1,2,...,T;j=1,2,...,T) ——> 图中的每个圆圈表示的是隐含的状态(每个状态,即每一个圆圈表示的是一个实数向量)。每一个箭头表示一个函数操作(e.g 矩阵相乘)。每个箭头处都有一个权重矩阵这里没有全部画出来,在RNN中对应位置的权重矩阵是一样的,可以参照[1]来进行理解。 注意我说的每个圆圈是一个层而不是一个节点,因为上图是把模型按照时间步进行展开来讨论的,图中的所有绿色圆圈表示的是同一层,从左到右表示该层的状态随着输入而变化的过程。红色的圈也是一样。
** cϵRk×1, ——> c是LSTM1的最终输出,是一个长度固定的实数向量。我们把 C 理解为输入句子的中间语义表示,也就是说, C 包含了整个输入句子的信息。就是LSTM2中隐含节点的初始状态,LSTM2就是根据这个初始状态不停地进行预测输出后面的结果。 在 Decoder 中,每次预测下一个词,都会用到 C 中的信息:

Chty1y2y3=hT=f1(ht1,yt1,C),yt=f2(ht)=g(C,h0)=g(C,y1,h1)=g(C,y2,h2)...

上面的函数 g 最后输出的是预测 yt 的概率,具体是怎样的等我之后弄懂了再来补充,但是一般 g 最后一层应该是 softmax 来输出的。至于模型参数的调整用的是RNN反向传播算法(BPTT),对于这个我还没看懂,所以之后再更新吧。

2.3 模型应用

seq2seq其实可以用在很多地方,比如机器翻译,自动对话机器人。比如Google就基于seq2seq开发了一个对话模型([5]A Neural Conversational Model),和论文[1,2]的思路基本是一致的,使用两个LSTM的结构,LSTM1将输入的对话编码成一个固定长度的实数向量,LSTM2根据这个向量不停地预测后面的输出(解码)。只是在对话模型中,使用的语料是((input)你说的话-我答的话(input))这种类型的pairs 。而在机器翻译中使用的语料是(hello-你好)这样的pairs。

此外,如果我们的输入是图片,输出是对图片的描述,用这样的方式来训练的话就能够完成图片描述的任务。等等,等等。

可以看出来,seq2seq具有非常广泛的应用场景,而且效果也是非常强大。同时,因为是端到端的模型(大部分的深度模型都是端到端的),它减少了很多人工处理和规则制定的步骤。在seq2seq上,人们又引入了attention mechanism等技术,使得这些深度方法在各个任务上表现更加突出。

2 1