Sequence to Sequence Basics

形式上,在机器翻译任务中,我们有一个输入序列 x 1 , x 2 , … , x m x_1, x_2, \dots, x_m x1,x2,,xm 和一个输出序列 y 1 , y 2 , … , y n y_1, y_2, \dots, y_n y1,y2,,yn (注意它们的长度可以不同)。翻译可以被认为是寻找在给定输入下概率最大的目标序列;形式上,即寻找最大化条件概率 p ( y ∣ x ) p(y|x) p(yx) 的目标序列:

y ∗ = arg ⁡ max ⁡ y p ( y ∣ x ) (1) y^{\ast}=\arg\max\limits_{y}p(y|x) \tag{1} y=argymaxp(yx)(1)

如果你是双语者并且可以轻松地在不同语言之间进行翻译,那么你会对 p ( y ∣ x ) p(y|x) p(yx) 有一种直观的感受,并且可以说出类似 “……嗯,这个翻译对这句话来说感觉更自然一点” 这样的话。但在机器翻译中,我们要学习一个带有参数 θ \theta θ 的函数 p ( y ∣ x , θ ) p(y|x, \theta) p(yx,θ) ,然后针对给定的输入寻找它的 argmax:

y ′ = arg ⁡ max ⁡ y p ( y ∣ x , θ ) (2) y'=\arg\max\limits_{y}p(y|x, \theta) \tag{2} y=argymaxp(yx,θ)(2)

在这里插入图片描述


为了定义一个机器翻译系统,我们需要回答三个问题:

  • 建模 - p ( y ∣ x , θ ) p(y|x, \theta) p(yx,θ) 的模型是什么样子的?
  • 学习 - 如何寻找参数 θ \theta θ
  • 推断 - 如何寻找最佳的 y y y

在本节中,我们将完整地回答第二个和第三个问题,但只考虑最简单的模型。更“真实”的模型将在后面的 Attention 和 Transformer 章节中进行讨论。

Encoder-Decoder Framework

编码器-解码器是序列到序列任务的标准建模范式。该框架由两个组件组成:

  • 编码器 - 读取源序列并生成其表示;
  • 解码器 - 使用来自编码器的源表示来生成目标序列。

在本讲中,我们将看到不同的模型,但它们都具有这种编码器-解码器结构。

在这里插入图片描述

Conditional Language Models

在语言模型讲座中,我们学习了估计词元序列 y = ( y 1 , y 2 , … , y n ) y=(y_1, y_2, \dots, y_n) y=(y1,y2,,yn) 的概率 p ( y ) p(y) p(y) 。虽然语言模型估计序列 y y y 的无条件概率 p ( y ) p(y) p(y) ,但序列到序列模型需要估计在给定源 x x x 的情况下序列 y y y 的条件概率 p ( y ∣ x ) p(y|x) p(yx) 。这就是为什么序列到序列任务可以被建模为 条件语言模型 (Conditional Language Models,CLM) ——它们的运作方式与语言模型类似,但额外接收源信息 x x x


在这里插入图片描述

Lena:注意,条件语言建模不仅仅是解决序列到序列任务的一种方法。在最一般的意义上, x x x 可以是除词元序列之外的其他东西。例如,在图像字幕任务中, x x x 是一张图像,而 y y y 是对该图像的描述。


由于与语言模型的唯一区别在于源 x x x 的存在,因此建模和训练与语言模型非常相似。特别是(In particular),高层流程如下:

  • 将 source 和先前生成的目标词输入到网络中;
  • 从网络的解码器中获取上下文(包括源和先前目标)的向量表示;
  • 根据此向量表示,预测下一个词元的概率分布。

与神经分类器和语言模型类似,我们可以用一种非常简单的方式来思考分类部分(即,如何从文本的向量表示中获取词元概率)。文本的向量 h h h 表示具有某个维度 d d d ,但最终,我们需要一个大小为 ∣ V ∣ |V| V 的向量( ∣ V ∣ |V| V 个词元/类别的概率)。为了从大小为 d d d 的向量中获得大小为 ∣ V ∣ |V| V 的向量,我们可以使用一个线性层。一旦我们有了一个大小为 ∣ V ∣ |V| V 的向量,剩下的就是应用 softmax 操作将原始数字转换为词元概率。



The Simplest Model: Two RNNs for Encoder and Decoder

在这里插入图片描述

最简单的编码器-解码器模型由两个 RNN(LSTM)组成:一个用于编码器,另一个用于解码器。编码器 RNN 读取源句子,其最终状态用作解码器 RNN 的初始状态。人们希望最终的编码器状态能够“编码”关于源句子的所有信息,并且解码器能够基于该向量生成目标句子。

这个模型可以有不同的变体:例如,编码器和解码器可以有多个层。这种具有多层的模型,例如被用于《Sequence to Sequence Learning with Neural Networks》这篇论文中——这是最早尝试使用神经网络解决序列到序列任务的研究之一。

在同一篇论文中,作者观察了最后的编码器状态并可视化了几个例子——如下所示。有趣的是,含义相似但结构不同的句子的表示彼此很接近!

在这里插入图片描述


Training: The Cross-Entropy Loss (Once Again)

Lena:这与我们之前在文本分类和语言模型讲座中讨论的交叉熵损失相同——你可以跳过这部分或非常轻松地过一遍 😃

与神经语言模型类似,神经序列到序列模型的训练目的是在给定先前上下文(源词元和先前的目标词元)的情况下预测下一个词元的概率分布。直观地说,在每一步我们都要最大化模型分配给正确词元的概率。

形式上,假设我们有一个训练实例,其源为 x = ( x 1 , … , x m ) x=(x_1, \dots, x_m) x=(x1,,xm) 且目标为 y = ( y 1 , … , y n ) y=(y_1, \dots, y_n) y=(y1,,yn) 。然后在时间步 t t t ,模型预测一个概率分布 p ( t ) = p ( ∗ ∣ y 1 , … , y t − 1 , x 1 , … , x m ) p^{(t)} = p(\ast|y_1, \dots, y_{t-1}, x_1, \dots, x_m) p(t)=p(y1,,yt1,x1,,xm) 。这一步的目标是 p ∗ = one-hot ( y t ) p^{\ast}=\text{one-hot}(y_t) p=one-hot(yt) ,也就是说,我们希望模型将概率 1 分配给正确的词元 y t y_t yt ,而将零分配给其余词元。

标准的损失函数是交叉熵损失。目标分布 p ∗ p^{\ast} p 和预测分布 p p p 的交叉熵损失为:

L o s s ( p ∗ , p ) = − p ∗ log ⁡ ( p ) = − ∑ i = 1 ∣ V ∣ p i ∗ log ⁡ ( p i ) (1) Loss(p^{\ast}, p)= - p^{\ast} \log(p) = -\sum\limits_{i=1}^{|V|}p_i^{\ast} \log(p_i) \tag{1} Loss(p,p)=plog(p)=i=1Vpilog(pi)(1)

由于 p i ∗ p_i^{\ast} pi 中只有一个非零(对应于正确的词元 y t y_t yt ),我们将得到:

L o s s ( p ∗ , p ) = − log ⁡ ( p y t ) = − log ⁡ ( p ( y t ∣ y < t , x ) ) (2) Loss(p^{\ast}, p) = -\log(p_{y_t})=-\log(p(y_t| y_{<t}, x)) \tag{2} Loss(p,p)=log(pyt)=log(p(yty<t,x))(2)

在每一步中,我们最大化模型分配给正确词元的概率。请看单个时间步的图示。

在这里插入图片描述

对于整个示例,损失将是 − ∑ t = 1 n log ⁡ ( p ( y t ∣ y < t , x ) ) -\sum\limits_{t=1}^n\log(p(y_t| y_{<t}, x)) t=1nlog(p(yty<t,x)) 。请看训练过程的图示(该图示是针对 RNN 模型的,但模型也可以是其他的)。


Training: The Cross-Entropy Loss (Once Again)

Attention

The Problem of Fixed Encoder Representation

问题:固定的源表示不是最优的:(i) 对于编码器来说,很难压缩整个句子;(ii) 对于解码器来说,在不同的步骤中,不同的信息可能具有相关性。

在我们目前为止所看到的模型中,编码器将整个源句子压缩成一个单一的向量。这可能非常困难——可能的源句子的数量(以及它们的含义)是无限的。当编码器被迫将所有信息放入一个单一向量中时,它很可能会遗忘一些东西。

在这里插入图片描述

Lena:想象一下整个宇宙及其所有的美丽——试着在脑海中描绘你在那里能找到的一切,以及你如何用语言来描述它。然后想象所有这些都被压缩成一个大小(例如 512)的单一向量。你觉得这个宇宙还能完好无损吗?

不仅编码器很难将所有信息塞进一个单一的向量中,这对解码器来说同样困难。解码器只能看到源句子的唯一一种表示。然而,在每一个生成步骤中,源句子的不同部分可能比其他部分更有用。但在当前的设定下,解码器必须从同一个固定的表示中提取出相关的信息——这绝非易事。

Attention: A High-Level View

注意力机制是在《Neural Machine Translation by Jointly Learning to Align and Translate》这篇论文中引入的,旨在解决固定表示的问题。

注意力:在不同的步骤中,让模型 关注 输入的不同部分。

注意力机制是神经网络的一部分。在每一个解码器步骤中,它决定源句子的哪些部分更为重要。在这种设定下,编码器不必将整个源句子压缩成一个单一的向量——它为所有的源词元提供表示(例如,所有的 RNN 状态,而不是仅仅最后一个)。

在这里插入图片描述

在每个解码器步骤中,注意力机制:

  • 接收注意力输入:一个解码器状态 h t h_t ht 和所有编码器状态 s 1 , s 2 , … , s m s_1, s_2, \dots, s_m s1,s2,,sm
  • 计算注意力分数
    对于每个编码器状态 s k s_k sk ,注意力机制计算它对于当前解码器状态 h t h_t ht 的“相关性”。形式上,它应用一个注意力函数,该函数接收一个解码器状态和一个编码器状态,并返回一个标量值 s c o r e ( h t , s k ) score(h_t, s_k) score(ht,sk)
  • 计算注意力权重:一个概率分布——对注意力分数应用 softmax;
  • 计算注意力输出:带有注意力权重的编码器状态的加权和。

一般的计算方案如下所示。

在这里插入图片描述

注意:一切都是可微的——端到端学习!

如果只用单向 RNN, s k s_k sk 虽然包含了前面的记忆,但却不知道句子后面的内容。这在翻译时是很吃亏的(比如某些语言的动词在句末)。为了解决这个问题,引入注意力机制的编码器几乎都会使用双向 RNN (Bidirectional RNN, 简称 BiRNN)。在双向 RNN 中, s k s_k sk 实际上是两个向量的“合体”:

  • 前向 RNN 的状态 h k → \overrightarrow{h_k} hk :它从左往右读,包含了从第 1 1 1 个词到第 k k k 个词的压缩信息。
    后向 RNN 的状态 h k ← \overleftarrow{h_k} hk :它从右往左读(倒着读),包含了从最后一个词到第 k k k 个词的压缩信息。

最终发给注意力模块的 s k s_k sk ,其实是这两个状态的拼接: s k = [ h k → ; h k ← ] s_k = [\overrightarrow{h_k}; \overleftarrow{h_k}] sk=[hk ;hk ]

主要思想是网络可以在每一步学习哪些输入部分更重要。由于这里的每一个环节都是可微的(注意力函数、softmax 以及所有其他部分),带有注意力机制的模型可以进行端到端的训练。你不需要特别教模型去挑选你想要的单词——模型自己会学习挑选重要信息。

How to Compute Attention Score?

在上面的通用流程中,我们还没有具体说明究竟如何计算注意力分数。你可以应用任何你想要的函数,甚至是非常复杂的函数。然而,通常你不需要这样做,有几种流行且简单的变体效果非常好。

点积 (Dot-product):

score ( h t , s k ) = h t T s k (1) \text{score}(h_t, s_k) = h_t^T s_k \tag{1} score(ht,sk)=htTsk(1)

双线性 (Bilinear):

score ( h t , s k ) = h t T W s k (2) \text{score}(h_t, s_k) = h_t^T W s_k \tag{2} score(ht,sk)=htTWsk(2)

多层感知机 (Multi-Layer Perceptron):

score ( h t , s k ) = w 2 T ⋅ tanh ⁡ ( W 1 [ h t , s k ] ) (3) \text{score}(h_t, s_k) = w_2^T \cdot \tanh(W_1 [h_t, s_k]) \tag{3} score(ht,sk)=w2Ttanh(W1[ht,sk])(3)

在这里插入图片描述

  • 点积 - 最简单的方法;
  • 双线性函数(又名“Luong 注意力”) - 在论文《Effective Approaches to Attention-based Neural Machine Translation》中使用;
  • 多层感知机(又名“Bahdanau 注意力”) - 在原始论文中提出的方法。

Model Variants: Bahdanau and Luong

当谈论早期的注意力模型时,你最有可能听到这些变体:

  • Bahdanau 注意力 - 来自 Dzmitry Bahdanau、KyungHyun Cho 和 Yoshua Bengio 的论文《Neural Machine Translation by Jointly Learning to Align and Translate》(这是首次引入注意力机制的论文);
  • Luong 注意力 - 来自 Minh-Thang Luong、Hieu Pham、Christopher D. Manning 的论文《Effective Approaches to Attention-based Neural Machine Translation》。

这些可能指的是评分函数,或者是这些论文中使用的整个模型。在这一部分中,我们将更仔细地研究这两个模型变体。

Bahdanau 模型

  • 编码器:双向的
    为了更好地对每个源单词进行编码,编码器具有两个 RNN(前向和后向),它们以相反的方向读取输入。对于每个词元,两个 RNN 的状态被拼接在一起。
  • 注意力分数:多层感知机
    为了获得注意力分数,将多层感知机 (MLP) 应用于一个编码器状态和一个解码器状态。
  • 注意力应用:在解码器步骤之间
    注意力在解码器步骤之间使用:状态 h t − 1 h_{t-1} ht1 用于计算注意力及其输出 c ( t ) c^{(t)} c(t) ,并且 h t − 1 h_{t-1} ht1 c ( t ) c^{(t)} c(t) 都被传递给时间步 t t t 的解码器。

在这里插入图片描述

Luong 模型

虽然该论文考虑了几个模型变体,但通常被称为“Luong 注意力”的变体如下:

  • 编码器:单向的(简单的)
  • 注意力分数:双线性函数
  • 注意力应用:在解码器 RNN 状态 t t t 和此步骤的预测之间
    注意力在 RNN 解码器时间步 t t t 之后、进行预测之前使用。状态 h t h_t ht 用于计算注意力及其输出 c ( t ) c^{(t)} c(t) 。然后将 h t h_t ht c ( t ) c^{(t)} c(t) 结合以获得更新的表示 h ~ t \tilde{h}_t h~t ,该表示用于获取预测。

在这里插入图片描述
Bahdanau 模型 (B 模型) 和 Luong 模型 (L 模型) 的所有核心差异

  1. 计算注意力的时机与依赖状态 (Timing & State)

    • B 模型 (Bahdanau):“看旧状态,算新状态”。在时间步 t t t,它依赖解码器上一步的旧状态 h t − 1 h_{t-1} ht1 去和编码器对齐,计算出注意力权重。
    • L 模型 (Luong):“出新状态,再回头看”。在时间步 t t t,解码器先自己更新一步得到当前的新状态 h t h_t ht,然后拿这个 h t h_t ht 去和编码器对齐计算注意力。
  2. 上下文向量的融合位置 (Fusion Path)也就是你刚才敏锐发现的那一点,决定了“查到的资料”用在哪里。

    • B 模型 (提前融合/内部消化):算出的上下文向量 c ( t ) c^{(t)} c(t) 会和上一个生成的单词一起,作为输入喂给解码器的 RNN。RNN 消化吸收后,输出 h t h_t ht,直接用 h t h_t ht 去做最终预测。
    • L 模型 (滞后融合/外部直达):算出的上下文向量 c ( t ) c^{(t)} c(t) 不进入解码器的 RNN。而是和 RNN 刚刚输出的 h t h_t ht 在外部进行拼接,融合成一个更强的组合向量 h ~ t \tilde{h}_t h~t。然后直接用 h ~ t \tilde{h}_t h~t 去做最终预测。
  3. 注意力打分函数 (Scoring Function)也就是它们底层数学公式的不同。

    • B 模型 (多层感知机 / 加性注意力):将解码器状态和源状态拼接起来,通过一个带有权重矩阵和 tanh ⁡ \tanh tanh 激活函数的单层神经网络来打分: score ( h , s k ) = w 2 T ⋅ tanh ⁡ ( W 1 [ h , s k ] ) \text{score}(h, s_k) = w_2^T \cdot \tanh(W_1 [h, s_k]) score(h,sk)=w2Ttanh(W1[h,sk])。计算相对复杂。
    • L 模型 (双线性 / 乘性注意力):直接使用矩阵乘法(点积的变体)来打分: score ( h t , s k ) = h t T W s k \text{score}(h_t, s_k) = h_t^T W s_k score(ht,sk)=htTWsk。计算更加直接、高效,也更容易进行矩阵加速。
  4. 编码器结构 (Encoder Architecture)虽然这不是注意力机制本身的强制要求,但在两篇经典论文的原始设定中有所不同。

    • B 模型:强调必须使用双向 RNN (Bidirectional),将前向和后向的隐藏状态拼接,以便在翻译时每个词都能拥有完整的全局视野。
    • L 模型:为了验证架构的通用性和高效性,其基础版本使用了最简单的单向 RNN (Unidirectional)(当然,在后来的实际工程应用中,L 模型的编码器也经常会被替换为双向的)。

Attention Learns (Nearly) Alignment

还记得注意力机制的动机吗?在不同的步骤中,解码器可能需要关注不同的源词元,也就是在当前步骤中更相关的那些。让我们来看看注意力权重——解码器使用了哪些源单词?

在这里插入图片描述

这些例子来自论文《Neural Machine Translation by Jointly Learning to Align and Translate》。

从这些例子中,我们看到注意力机制学习到了源单词和目标单词之间的(软)对齐——解码器会关注它在当前步骤正在翻译的那些源词元。

Lena:“对齐(Alignment)” 是统计机器翻译中的一个术语,但在这一部分,把它直观地理解为“什么被翻译成了什么”就足够了。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐