Sequence to Sequence (seq2seq) and Attention
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(y∣x) 的目标序列:
y ∗ = arg max y p ( y ∣ x ) (1) y^{\ast}=\arg\max\limits_{y}p(y|x) \tag{1} y∗=argymaxp(y∣x)(1)
如果你是双语者并且可以轻松地在不同语言之间进行翻译,那么你会对 p ( y ∣ x ) p(y|x) p(y∣x) 有一种直观的感受,并且可以说出类似 “……嗯,这个翻译对这句话来说感觉更自然一点” 这样的话。但在机器翻译中,我们要学习一个带有参数 θ \theta θ 的函数 p ( y ∣ x , θ ) p(y|x, \theta) p(y∣x,θ) ,然后针对给定的输入寻找它的 argmax:
y ′ = arg max y p ( y ∣ x , θ ) (2) y'=\arg\max\limits_{y}p(y|x, \theta) \tag{2} y′=argymaxp(y∣x,θ)(2)

为了定义一个机器翻译系统,我们需要回答三个问题:
- 建模 - p ( y ∣ x , θ ) p(y|x, \theta) p(y∣x,θ) 的模型是什么样子的?
- 学习 - 如何寻找参数 θ \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(y∣x) 。这就是为什么序列到序列任务可以被建模为 条件语言模型 (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,…,yt−1,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)=−p∗log(p)=−i=1∑∣V∣pi∗log(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(yt∣y<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=1∑nlog(p(yt∣y<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)=w2T⋅tanh(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} ht−1 用于计算注意力及其输出 c ( t ) c^{(t)} c(t) ,并且 h t − 1 h_{t-1} ht−1 和 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 模型) 的所有核心差异
-
计算注意力的时机与依赖状态 (Timing & State)
- B 模型 (Bahdanau):“看旧状态,算新状态”。在时间步 t t t,它依赖解码器上一步的旧状态 h t − 1 h_{t-1} ht−1 去和编码器对齐,计算出注意力权重。
- L 模型 (Luong):“出新状态,再回头看”。在时间步 t t t,解码器先自己更新一步得到当前的新状态 h t h_t ht,然后拿这个 h t h_t ht 去和编码器对齐计算注意力。
-
上下文向量的融合位置 (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 去做最终预测。
-
注意力打分函数 (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)=w2T⋅tanh(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。计算更加直接、高效,也更容易进行矩阵加速。
-
编码器结构 (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)” 是统计机器翻译中的一个术语,但在这一部分,把它直观地理解为“什么被翻译成了什么”就足够了。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)