序列到序列模型
学习如何使用深度学习处理序列数据(尤其是文本)。
要理解注意力机制,我们需要先探讨它在自然语言处理中的起源。机器翻译——即将一种语言的输入句子转换为另一种语言——是一个非常典型的应用场景。
那么,在此之前我们是如何处理自然语言中的文本和句子的呢?
从机器学习的角度建模文本
我们首先从机器学习的角度来形式化这个问题。
先思考输入与输出的关系,有助于我们理解这类模型。
表示方式非常直观:句子可以被视为词语的序列。
在展示任何复杂的模型之前,让我们先全面了解一下。我们将输入句和输出句都表示为序列。
序列到序列模型(Seq2Seq)
理想情况下,模型需要理解一种语言中的输入句子,这一过程由所谓的“编码器”(encoder)完成。编码器生成一个中间表示,图中记作 z。
接着我们需要将这种语义信息转换成另一种语言,因此引入“解码器”(decoder)模型来完成这一任务。
事实上,这些术语本身并无特别之处。
该类方法统称为序列到序列(Seq2Seq),其工作原理大致如上图所示。
序列中的元素 等通常被称为 token(词元),它们可以是任意形式的内容。
例如,它们可以是文本的表示、像素值,甚至在视频任务中可以是图像帧。
但为什么我们要使用这类模型?
目标是将一个输入序列(源序列)转换为另一个新序列(目标序列)。这两个序列可以长度相同,也可以是任意长度。
你可能已经注意到,在此前课程中介绍过的循环神经网络(RNNs)曾主导了序列到序列任务。
原因很简单:我们习惯于按顺序处理序列。这听起来似乎很自然且高效?然而注意力机制以及后来的Transformer模型证明,事实并非如此!
编码器与解码器的完整视角
假设这里的 编码器 和 解码器 是由堆叠的 RNN 或 LSTM 单元构成,比如 LSTM 网络。
编码器逐个处理输入序列,并基于所有时间步的输入生成一个紧凑的中间表示,称为 z。
z 可以被看作是对输入信息的一种压缩表示。
另一方面,解码器接收上下文向量 z,并据此生成输出序列。
Seq2Seq 最常见的应用就是机器翻译。
我们可以把输入序列理解为一句英文句子的表示,而输出则是该句子对应的法语翻译。
事实上,基于 RNN 的架构曾经表现非常出色,尤其是结合 LSTM 组件时。
问题出在哪里?仅限于较短的序列(<20 个时间步)。直观来看:
让我们分析一下背后的原因。
RNN 的局限性
主要问题在于:中间表示 z 无法有效编码所有输入时间步的信息。这通常被称为 瓶颈问题。向量 z 必须承载整个源句子的全部信息。
理论上,数学上认为这是可能的;但在实践中,模型能回顾的历史信息(即所谓的“感受野”)是有限的。数据量有限也是一个重要因素。因此,RNN 容易遗忘较早时间步的信息。
来看一个具体的例子。设想一个包含 97 个单词的句子:
“当那个男人主动提出要帮助那位盲人时,他还没有产生任何恶意念头,恰恰相反,他所做的不过是遵从了人们普遍具有的慷慨与利他之心,众所周知,这两种品质正是人性中最优秀的特质,甚至连比他更凶恶的罪犯身上也常常能找到。实际上,此人不过是个毫无前途可言的普通偷车贼,受雇于幕后真正的老板,因为真正从中获利的是那些利用穷人困境的人。” ~ 若泽·萨拉马戈,《失明症漫记》
你是否注意到什么问题?帮助理解的关键词(加粗部分)之间相隔甚远!
大多数情况下,向量 z 很难同时保留开头几个词和第 97 个词的完整信息。
最终,系统往往更关注序列末尾的部分。但这通常不是处理序列任务的最佳方式,也不符合人类翻译或理解语言的习惯。
此外,堆叠的 RNN 层还常常引发著名的 梯度消失问题。由于反向传播过程中涉及多个小于 1 的数值连乘,导致梯度逐渐趋近于零。而这些乘法运算是梯度在网络中回传所必需的,在 RNN 结构中难以避免。下图可帮助你直观理解这一现象:
图中蓝色的深浅表示梯度值的衰减程度。