Sequence-to-sequence models-把一个序列转换成另一个序列的模型,简称Seq2Seq。Seq2Seq作为深度学习模型,在机器翻译,文字概括总结和图片说明取得了很多成功。谷歌翻译在2016年开始在生产环境中使用类似模型。见如下文章These models are explained in the two pioneering papers (Sutskever et al., 2014 (opens in a new tab), Cho et al., 2014 (opens in a new tab)).
但我发现要对模型理解的足够好来使用它需要需要先拆解一系列层层递进的概念。我觉得,如果把其中不少想法用可视化的方式表达出来,会更容易理解。这也正是我写这篇文章想做的事情。阅读这篇文章需要你对深度学习有一些基础了解。我希望它能作为阅读前面提到的那些论文,以及本文后面链接到的 Attention 相关论文时的有用辅助材料。
Sequence to sequence模型是一个输入一系列item并输出另一系列item的模型。在基于神经网络的机器翻译中,序列是一系列单词,依次处理。输出同样是一系列单词。
seq2seq 2
深入了解模型构成
模型底层由编码器 encoder 和解码器 decoder 组成。 编码器处理输入序列中的每个项,将捕获的信息编译成一个向量(称为context上下文)。处理完整个输入序列后,编码器将上下文发送给解码器,解码器开始逐项输出序列。机器翻译也是如此。
seq2seq 3
在机器翻译中,Context上下文是一个向量(基本上是数字数组)。编码器和解码器通常都是循环神经网络(请务必阅读Luis Serrano的《A friendly introduction to Recurrent Neural Networks (opens in a new tab)》了解RNNs)。 Context上下文是由一个浮点数组成的向量。在这篇文章的后面,我们将为数值更高的单元格分配更亮的颜色,便于可视化向量。 你可以在设置模型时设置上下文向量的大小。它基本上是编码器RNN中隐藏单元的数量。这些可视化显示的向量大小为4,但在现实应用中,上下文矢量大小如256、512或1024。
在设计上,RNN 在每个时间步都会接收两个输入:一个是当前输入数据——对于编码器来说,就是输入句子中的一个词;另一个是hidden state-隐藏状态。
不过,词本身无法直接输入神经网络,因此需要先用一个向量来表示。为了将词转换成向量,我们会使用一类称为“word embedding-词嵌入”的方法。词嵌入可以把词映射到一个向量空间中,并在这个空间里保留大量与词义和语义相关的信息。例如,在这个向量空间中,可能存在类似“国王 − 男人 + 女人 ≈ 王后”这样的关系。 我们需要在处理输入的单词之前将它们转换为向量,为此我们可以使用预训练模型来生成单词对应的嵌入,或在我们的数据集上训练我们自己的嵌入。嵌入大小通常为 200 或 300 ,为简单起见,这里每个单词只显示了一个大小为 4 的嵌入。
现在我们已经介绍了几个主要的张量tensor,接下来,让我们回顾一下 RNN 的运行机制,并建立一套用于描述这类模型的可视化表达方式。
RNN 1
在 RNN 的下一个时间步中,模型会将第二个输入向量与上一时刻的隐藏状态(Hidden State # 1 )一起作为输入,计算出当前时间步的输出。本文后面,我们会用类似的动画来演示神经机器翻译(NMT)模型内部各种向量是如何传递和变化的。
在下面的可视化图中,编码器(Encoder)或解码器(Decoder)的每一次“脉冲”(pulse),都表示对应的 RNN 正在处理当前时间步的输入,并生成该时间步的输出。由于编码器和解码器本身都是 RNN,因此每经过一个时间步,相应的 RNN 都会执行一次计算,并根据当前输入以及此前已经处理过的输入,更新自己的隐藏状态(Hidden State)。
下面让我们来看一下编码器的隐藏状态(Hidden States)。请注意,编码器最后一个隐藏状态实际上就是我们传递给解码器的上下文向量(Context Vector)。
seq2seq 5
解码器(Decoder)同样会维护一个隐藏状态(Hidden State),并在相邻的时间步之间不断传递。只是为了突出模型的主要组成部分,我们暂时没有在这张图中将它绘制出来。
现在,让我们换一种方式来展示序列到序列(Sequence-to-Sequence,Seq2Seq)模型。这种动画形式能够帮助我们更容易理解后续介绍这些模型时所使用的静态示意图。
这种表示方法称为“展开图(Unrolled View)”。它不是只画一个解码器,而是为每一个时间步分别画出一个解码器的副本。这样,我们就能够清楚地观察每个时间步的输入和输出。
seq2seq 6
Let’s Pay Attention Now
对于这类模型来说,上下文向量(Context Vector)最终成为了一个瓶颈。由于所有输入信息都必须压缩到这一个固定长度的向量中,因此模型在处理较长的句子时会变得十分困难。
为了解决这一问题,Dzmitry Bahdanau 等人在 2014 年以及 Minh-Thang Luong 等人在 2015 年提出并进一步完善了一种名为 Attention(注意力机制) 的技术。这项技术显著提升了机器翻译系统的翻译质量。
Attention 机制使模型能够在生成每一个输出时,根据需要动态地关注输入序列中最相关的部分,而不是仅仅依赖一个固定的上下文向量。 在第 7 个时间步,注意力机制(Attention)使解码器能够在生成英文翻译之前,将注意力集中到法语单词“étudiant”(意为“学生”)上。
这种能够动态增强输入序列中相关部分信息的能力,使得带有 Attention 的模型相比没有 Attention 的模型能够取得更好的翻译效果。
接下来,我们仍然从较高层次的抽象角度来理解 Attention 模型。 Attention 模型与传统的序列到序列(Sequence-to-Sequence,Seq2Seq)模型主要有两个区别。 第一个区别是,编码器(Encoder)会向解码器(Decoder)传递更多的信息。传统 Seq2Seq 模型只将编码阶段最后一个隐藏状态(Hidden State)传递给解码器,而在 Attention 模型中,编码器会将所有时间步的隐藏状态都传递给解码器。
seq2seq 7
第二个区别是,Attention 解码器(Attention Decoder)在生成输出之前,会额外执行一个步骤。为了在当前解码时间步关注输入序列中最相关的部分,解码器会执行以下操作: 1.查看编码器传递过来的所有隐藏状态(Hidden States)。每个隐藏状态都与输入句子中的某个单词密切对应。 2.为每个隐藏状态计算一个分数(Score)(暂时先不讨论分数是如何计算的) 3.将每一个 Hidden State 与它对应的 Softmax 分数相乘,因此重要的 Hidden State分数更高,对最终结果贡献更多,减少低分Hidden State的影响
attention process
上述打分(Scoring)过程会在解码器(Decoder)的每一个时间步重复执行。现在,让我们结合下面的示意图,把整个过程串联起来,看看 Attention 是如何工作的: 1.Attention 解码器 RNN 接收 的嵌入向量(Embedding)以及解码器的初始隐藏状态作为输入。 2.RNN 对这些输入进行处理,产生当前时间步的输出以及新的隐藏状态向量(h₄)。这里,RNN 的输出会被丢弃,只保留新的隐藏状态。 3.**注意力步骤:**我们使用编码器的所有隐藏状态和向量 h₄,计算当前时间步的上下文向量(C₄)。 4.我们将 h₄ 和 C₄ 拼接成一个向量。 5.我们将这个向量传入一个前馈神经网络(feedforward neural network)。这个前馈神经网络会与整个模型一起进行联合训练。 6.前馈神经网络的输出指示当前时间步应当输出的单词。 7.在接下来的各个时间步中重复上述过程。
attention tensor dance
这是另一种展示方式,用来观察在每一个解码时间步中,我们关注的是输入句子的哪一部分。
seq2seq 9
需要注意的是,模型并不是机械地将输出中的第一个单词与输入中的第一个单词对齐。实际上,它在训练阶段已经学会了如何对该语言对中的单词进行对齐——在我们的例子中,这个语言对是法语和英语。
前面提到的 Attention 相关论文中给出了一个例子,可以看出这种机制的对齐能力能够精确到什么程度:
你可以看到,当模型输出“European Economic Area(欧洲经济区)”时,它正确地将注意力集中在了对应的输入部分。
在法语中,这几个词的排列顺序与英语相反,法语中的表达顺序是“européenne économique zone”。而句子中的其他单词,其排列顺序与英语基本相同。
If you feel you’re ready to learn the implementation, be sure to check TensorFlow’s Neural Machine Translation (seq2seq) Tutorial (opens in a new tab).