设想一场高规格的跨国技术峰会。台上,一位工程师正用流利的英文演讲;台下,观众戴着同传耳机,耳机里精准流畅的中文,出自一位翻译官——我们就叫他阿杰。 阿杰的工作方式有个耐人寻味的特点:他从不会「听到一个词就译一个词」。当演讲者说出 "Our model achieved unprecedented accuracy……" 时,阿杰不会急着开口——他会先让这串音流在脑中「存一下」,等到关键信息出现,甚至听到后半句还会推翻自己对前半句的理解。他真正做的,是听完一段意思完整的话,在脑海中凝练出一个「核心意思」,再基于这个核心意思,用中文重新组织语言,一句一句地讲出来。 这个「先听懂、再重新表达」的过程,正是 Seq2Seq(sequence-to-sequence,序列到序列)模型的工作范式。而它的骨架,就是本文的主角——编码器-解码器(Encoder-Decoder)架构:编码器负责「听懂」,把变长的输入序列浓缩成语义向量;解码器负责「表达」,把这个向量一步步展开为变长的目标序列。机器翻译、文本摘要、对话系统……今天无数AI应用的底层,都站着这套架构。 本文我们将跟随阿杰的视角,拆解编码器如何逐词消化输入、上下文向量如何储存语义、解码器如何逐步生成输出,以及注意力机制如何为长序列补上关键短板。

岗位关联

理解编码器-解码器架构,是进入 NLP 序列建模世界的「第一块敲门砖」。它让你在面对翻译、摘要、对话等任务时,能一眼看穿模型的骨架与瓶颈,为后续学好 Transformer 和各类大模型奠定扎实的直觉基础。

目录
  1. 可视化演示
  2. 架构总览
  3. 编码器机制
  4. 上下文向量
  5. 解码器机制
  6. 注意力机制
  7. 训练推理模式
  8. 典型应用场景
  9. 局限与发展
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示操作系统进程在新建、就绪、运行、等待、终止五种状态间的转换过程,支持自动播放与手动步进控制。

本节配有交互动效(进入视口后自动加载,约 3KB)。

进程五状态模型 新建状态:进程刚创建,等待被系统 admit 就绪状态:已准备好执行,等待 CPU 分配 状态转换由调度器和事件驱动 当前进程处于新建状态,等待进入就绪队列

架构总览

阿杰每天的工作可以简化为两次「点头」:第一次,他侧耳倾听,从头到尾听完发言人的一整句话;第二次,他面向观众,开始用另一种语言讲述同一个意思。中间的间隙,他的大脑飞快地完成了对源语言的「压缩」与对目标语言的「展开」。编码器-解码器架构正是把这两次点头背后的机制,显式地建模成了两个可学习的神经网络组件。

在 Seq2Seq 这个大家族里,输入和输出都是变长序列。机器翻译是典型例子:英文句子可能是 9 个 token,中文对应句可能是 7 个 token。编码器-解码器架构让模型无需人为定义输入与输出的对齐关系,而是通过「理解-表达」两个阶段完成转换。编码器(Encoder)读取整个输入序列,解码器(Decoder)根据前者的总结逐步生成输出序列。

这种端到端的学习方式,使从原始语料到最终翻译的整个过程可以被统一优化。传统方法往往把翻译拆成分词、调序、线性化等多个子模块;Seq2Seq 则把这一串流程折叠进一个模型里,只靠一个损失函数驱动。架构层面的核心连接点,是一个称为「上下文向量」(context vector)的张量——它承载了源序列的语义,充当编码器与解码器之间唯一的通道。

把阿杰的故事放进这个框架:输入序列是他听到的英文单词流,编码器是他的听觉-理解系统,上下文向量是他闭眼一瞬脑中的完整意思,解码器则是他开口组织中文的语音系统。四个角色各司其职,构成了序列转换任务最通用的一张蓝图。

Seq2Seq 总体框架:x1,x2,…,xT→编码器c→解码器y1,y2,…,yT′\text{Seq2Seq 总体框架}:\quad x_1, x_2, \ldots, x_T \xrightarrow{\text{编码器}} c \xrightarrow{\text{解码器}} y_1, y_2, \ldots, y_{T'}
这个公式把整个 Seq2Seq 压缩成一行:源序列经过编码器变成向量 c,再经解码器展开成目标序列。它既定义了任务边界,也预示了模型的学习目标。
  1. 输入序列$x_1, x_2, \ldots, x_T$ 是变长的源句子,例如英文 "I love you" 的三个词。
    x1,x2,…,xTx_1, x_2, \ldots, x_T
  2. 编码过程编码器从左到右逐词读取,输出一个浓缩了整句语义的向量。
    x1,x2,…,xT→编码器cx_1, x_2, \ldots, x_T \xrightarrow{\text{编码器}} c
  3. 语义向量$c$ 是固定维度的上下文向量,不随源句长度变化,相当于阿杰脑中的「核心意思」。
    cc
  4. 解码过程解码器从 $c$ 出发,逐词生成目标序列的第一个词、第二个词……
    c→解码器y1,y2,…,yT′c \xrightarrow{\text{解码器}} y_1, y_2, \ldots, y_{T'}
  5. 输出序列$y_1, \ldots, y_{T'}$ 是变长的目标句子,长度可以不同于源句,这正是 Seq2Seq 灵活性的来源。
    y1,y2,…,yT′y_1, y_2, \ldots, y_{T'}

编码器机制

很多人以为翻译官是「人肉词典」,听到一个词就报一个词。真实的阿杰恰恰相反:他听每句话时,都会在脑中维护一张不断涂改的「理解草稿」。听到 'not',他会把草稿中的肯定判断划掉;听到 'but',他会预感到转折即将到来。每听一个词,草稿就更新一次——这正是 RNN 编码器的核心行为。

在编码器中,这个「理解草稿」被称为隐藏状态(hidden state),记作 $h_t$。初始时 $h_0$ 是一个全零向量(阿杰脑中一片空白);随后每读取一个输入词 $x_t$,模型就通过一个非线性变换,把上一步的隐状态与新词的嵌入向量融合,得到新的隐状态 $h_t$。这个变换由循环神经网络(RNN)单元完成,最常见的形式如下:

值得强调的是,单向 RNN 的 $h_t$ 只能看到 $x_t$ 及其左侧的历史信息。为了让模型「看到未来」,工程师们设计了双向 RNN(BiRNN):一个普通 RNN 从左往右读,另一个从右往左读,再把两个方向的隐状态拼接,作为每个位置最终的编码结果。这相当于阿杰在听完整句话后,快速回溯一遍之前的每个词,确保转折、否定等关键信息没有被遗漏。

有了双向编码,阿杰脑中的「理解草稿」就不再只是从前往后的线性笔记,而是一张正反两面都写满批注的大纸——这正是双向 Seq2Seq 在翻译、摘要等任务上普遍优于单向版本的原因。

ht=tanh⁡(Whh ht−1+Wxh xt+bh)h_t = \tanh(W_{hh}\, h_{t-1} + W_{xh}\, x_t + b_h)
一句话理解:新的理解草稿 = 旧草稿与当前新词的「加权融合」,再经过一个压缩激活函数。
  1. 上一步隐状态$h_{t-1}$ 是阿杰听完前 $t-1$ 个词后脑中的阶段性理解。
    ht−1h_{t-1}
  2. 旧信息延续$W_{hh} h_{t-1}$ 将旧草稿线性变换,决定旧信息多大程度被保留。
    Whh ht−1W_{hh}\, h_{t-1}
  3. 新词注入$W_{xh} x_t$ 将当前词 $x_t$ 映射到语义空间,相当于阿杰听到的第 $t$ 个词。
    Wxh xtW_{xh}\, x_t
  4. 信息合并新旧信息相加再加上偏置 $b_h$,完成一次「笔记更新」。
    Whh ht−1+Wxh xt+bhW_{hh}\, h_{t-1} + W_{xh}\, x_t + b_h
  5. 非线性压缩$\tanh$ 把合并结果压到 $(-1, 1)$,保证数值稳定并引入非线性表达力。
    tanh⁡(⋅)\tanh(\cdot)

上下文向量

当发言人说完最后一个词,阿杰会用零点几秒的时间「定稿」——把整个句子的意思凝练成一条不带冗余措辞的核心命题。这个命题不是某个词的字面翻译,而是一份高度压缩的语义快照。在 Seq2Seq 中,这份快照就是上下文向量 $c$。

编码器把所有时刻的隐状态收集起来后,需要通过一个聚合函数 $q$ 生成这个向量。最简单的做法是直接取最后时刻的隐状态 $c = h_T$,相当于阿杰只保留读完整个句子后那一刻的终态记忆;也可以通过平均池化、注意力加权等方式对全部隐状态做汇总。

无论哪种方式,上下文向量的维度都是固定的——这是它的硬约束,也是它的软肋。设想阿杰听到一句 50 词的复杂长句,却必须把它全部装进一个 256 维的向量里。词数越多,压缩率越高,开头和中间的信息就越容易被末尾覆盖。这正是早期 Seq2Seq 模型著名的「信息瓶颈」问题:固定长度的向量成了长句翻译质量的天然天花板。

在早期的神经机器翻译系统(如 2014 年的 Seq2Seq 模型)中,$c = h_T$ 曾是主流选择。它训练简单、实现方便,但研究者很快发现:源句越长,翻译质量下滑越严重。这就像阿杰在掌心记笔记——短句时应付自如,长句时字迹越来越挤,最终难以辨认。上下文向量的「容量天花板」,直接催生了下一章要讲的进化方案。

c=q(h1,h2,…,hT),最简形式: c=hTc = q(h_1, h_2, \ldots, h_T), \qquad \text{最简形式: } c = h_T
上下文向量就像写在掌心的一句话:短句时够用,长句时潦草字迹开始难以辨认。
  1. 全部隐状态$h_1, \ldots, h_T$ 是编码器在每个位置留下的阶段性理解,覆盖整条源序列。
    h1,h2,…,hTh_1, h_2, \ldots, h_T
  2. 聚合函数$q(\cdot)$ 把这些隐状态「拧成一股绳」,输出一个固定维度的向量。
    q(h1,h2,…,hT)q(h_1, h_2, \ldots, h_T)
  3. 最终向量$c$ 就是上下文向量,维度固定,不随 $T$ 变化。
    cc
  4. 最简形式直接取最后一个隐状态当作 $c$,实现最简单,但长序列信息易丢失。
    c=hTc = h_T

解码器机制

定稿之后,阿杰开始说话。他不会一口气输出整句中文,而是先说出第一个词,停一停,感觉自己说得是否通顺,再决定第二个词。每说出一个词,这个新词本身又成为下一轮决策的语境——这就是解码器的自回归本质。

解码器(Decoder)是另一个 RNN,维护自己的隐藏状态 $s_{t'}$。它与编码器最大的不同在于:它每一步的输入,是上一步生成的目标词 $y_{t'-1}$,而初始状态则来自编码器传来的上下文向量 $c$。也就是说,解码器的「创作条件」= 源句语义 + 已经产出的前缀。

在每一步 $t'$,解码器先更新自己的状态,再通过一个线性层将状态映射到词表大小,最后用 softmax 归一化为词表上的概率分布:

此外,训练与推理时序列的终止由专门的结束符 <EOS>(End of Sequence)控制。解码器一旦生成了 <EOS>,生成过程便画上句号,就像阿杰说完「以上就是我的翻译」——听众知道这句话结束了。训练阶段的每条目标句子都会被补上 <EOS>,让模型学会在恰当的位置收口。

逐步生成、自回归、终止符——解码器像一位一丝不苟的演说家:每一句都基于前一句的落点,最后用固定的方式宣告完结。

st′=tanh⁡(Wss st′−1+Wys yt′−1+Wcs c+bs)s_{t'} = \tanh(W_{ss}\, s_{t'-1} + W_{ys}\, y_{t'-1} + W_{cs}\, c + b_s)
P(yt′∣y<t′,c)=softmax(Wo st′+bo)P(y_{t'} \mid y_{<t'}, c) = \mathrm{softmax}(W_o\, s_{t'} + b_o)
第一个公式决定「怎么想」,第二个公式决定「怎么选」:先融合语境更新状态,再从词表中挑一个最合适的词。
  1. 上一步表达状态$s_{t'-1}$ 是解码器已经说出的内容形成的语言惯性。
    st′−1s_{t'-1}
  2. 上一步生成的词$y_{t'-1}$ 作为输入重新进入循环,让模型知道自己刚才说了什么。
    yt′−1y_{t'-1}
  3. 注入核心意思$W_{cs}\, c$ 把上下文向量融入当前状态,时刻提醒阿杰不要偏离主题。
    Wcs cW_{cs}\, c
  4. 状态更新三路信息相加经 $\tanh$ 压缩,得到新的表达状态 $s_{t'}$。
    st′=tanh⁡(Wss st′−1+Wys yt′−1+Wcs c+bs)s_{t'} = \tanh(W_{ss}\, s_{t'-1} + W_{ys}\, y_{t'-1} + W_{cs}\, c + b_s)
  5. 概率输出$W_o s_{t'} + b_o$ 映射为词表得分,$\mathrm{softmax}$ 归一化得到每个词的生成概率。
    P(yt′∣y<t′,c)=softmax(Wo st′+bo)P(y_{t'} \mid y_{<t'}, c) = \mathrm{softmax}(W_o\, s_{t'} + b_o)

注意力机制

第一次参加超长会议后,阿杰吃了亏:一句话 60 个词,他翻译到后半段时已经忘了前面某个关键数字。从此他养成一个习惯——手边放一沓源文笔记,讲到哪个词,就快速扫一眼源文对应位置,把目光停留在最相关的几个词上。这就是注意力(Attention)的雏形。

注意力机制的核心思想:解码器生成第 $t'$ 个词时,不再只看一个固定向量 $c$,而是重新访问编码器的全部隐状态 $h_1, \ldots, h_T$,为它们计算一组权重,再求加权和作为这一步的动态上下文向量 $c_{t'}$。权重越大,代表源文中对应位置的词对当前输出词越重要。

权重的计算通常分为三步:先算解码器上一步状态 $s_{t'-1}$ 与每个编码器隐状态 $h_t$ 的匹配分数 $e_{t',t}$;再对分数做 softmax 归一化得到权重 $\alpha_{t',t}$;最后按权重对 $h_t$ 求和:

注意力的引入一举打破了固定长度上下文向量的瓶颈:即使源句很长,解码器也可以在每一步精准「回看」到相关位置,把长距离依赖显式地建模为短距离的「查找」。这份工作最早由 Bahdanau 等人于 2015 年引入中英机器翻译,让 Seq2Seq 对长句的翻译质量有了质的提升,也点燃了后来用注意力取代循环结构的思想火花。

从「靠脑内记忆」到「随查随看」,阿杰的翻译生涯从此迈入新阶段:笔记不再是压缩版的掌心词条,而是一份可以随时翻阅、按需取用的完整档案——这正是注意力带给 Seq2Seq 的进化。

e_{t',t} = v^\top \tanh(W_s\, s_{t'-1} + W_h\, h_t), \qquad\alpha_{t',t} = \frac{\exp(e_{t',t})}{\sum_{k=1}^{T} \exp(e_{t',k})}, \qquadc_{t'} = \sum_{t=1}^{T} \alpha_{t',t}\, h_t
注意力让解码器学会了「翻笔记」:不再依赖唯一的固定向量,而是动态地从源文中挑选相关信息。
  1. 匹配打分$e_{t',t}$ 衡量「当前翻译需求」与「源文第 $t$ 个词」的匹配程度,分数越高越相关。
    et′,t=v⊤tanh⁡(Ws st′−1+Wh ht)e_{t',t} = v^\top \tanh(W_s\, s_{t'-1} + W_h\, h_t)
  2. 归一化权重对整句的分数做 softmax,把分数变成和为 1 的注意力权重。
    αt′,t=exp⁡(et′,t)∑k=1Texp⁡(et′,k)\alpha_{t',t} = \frac{\exp(e_{t',t})}{\sum_{k=1}^{T} \exp(e_{t',k})}
  3. 加权求和按权重汇总所有隐状态,得到这一步专用的上下文向量。
    ct′=∑t=1Tαt′,t htc_{t'} = \sum_{t=1}^{T} \alpha_{t',t}\, h_t

训练推理模式

阿杰所在的翻译公司有两位新手:一位是实习生小陈,一位是转正的正式员工。带小陈时,阿杰会在他每译完一个词后告诉他这个位置的标准译法;而正式员工独立工作时,没有人给参考答案,只能用自己的上一个输出继续翻译。训练与推理阶段的解码器,恰好处在这两种截然不同的模式中。

训练阶段,解码器使用「教师强制」(Teacher Forcing):即便模型上一步预测错了,仍然把真实的目标词喂给下一步。这样做的优点是训练信号清晰、收敛快;缺点是模型在推理时从未见过自己的错误输出,一步错可能导致后面连环错。这种「曝光偏差」(exposure bias)是训练与推理不一致的根源。

在训练中,目标是最小化所有词位置的平均负对数似然。假设第 $i$ 个样本的源序列为 $x^{(i)}$,目标词为 $y_1^{(i)}, \ldots, y_{T'}^{(i)}$,整体损失函数写为:

推理阶段则完全不同:没有标准答案,解码器从 <SOS> 开始,逐个用 argmax 选择概率最高的词并把它当作下一步输入。为了弥补这种「贪心」的短视,工程上常用束搜索(Beam Search):每一步不只保留概率最高的 1 条路径,而是保留得分最高的 $k$ 条候选路径,最后在序列结束时选择整体评分最优的一条。$k$ 通常取 4~8,像阿杰在口译时同时组织两三个版本的译法,挑最顺口的说出来。

教师强制是有人纠正的刻意练习,自回归是独自上阵的临场发挥,束搜索则是在脑内多留几个备选方案。这三种模式的转换,正是 Seq2Seq 从课堂走向实战的关键。

L(θ)=−1N∑i=1N∑t′=1T′log⁡Pθ(yt′(i)∣y<t′(i),c(i))\displaystyle \mathcal{L}(\theta) = -\frac{1}{N} \sum_{i=1}^{N} \sum_{t'=1}^{T'} \log P_{\theta}\bigl(y_{t'}^{(i)} \mid y_{<t'}^{(i)}, c^{(i)}\bigr)
损失函数 = 对每个样本、每个词位置的「预测错误程度」求和取平均,再取负号变成「越小越好」。
  1. 条件概率$P_{\theta}(y_{t'} \mid y_{<t'}, c)$ 是模型在给定前缀和上下文时预测该词的概率。
    Pθ(yt′∣y<t′,c)P_{\theta}\bigl(y_{t'} \mid y_{<t'}, c\bigr)
  2. 取对数$\log$ 把连乘的概率变成连加,避免浮点数下溢。
    log⁡Pθ(⋅)\log P_{\theta}(\cdot)
  3. 双重求和对所有训练样本 $i$、所有词位置 $t'$ 累积误差,覆盖整句翻译的每个词。
    ∑i=1N∑t′=1T′log⁡Pθ(⋅)\sum_{i=1}^{N} \sum_{t'=1}^{T'} \log P_{\theta}(\cdot)
  4. 负号与平均取负号使得「最大化概率」变成「最小化损失」,除以 $N$ 便于不同批量大小间比较。
    −1N∑i=1N∑t′=1T′log⁡Pθ(⋅)-\frac{1}{N} \sum_{i=1}^{N} \sum_{t'=1}^{T'} \log P_{\theta}(\cdot)

典型应用场景

会议翻译并不是阿杰唯一的工作。他能做英译中,也能把长文档改写成一段 140 字的会议纪要,还能在客服电话里充当人机沟通的桥梁。编码器-解码器架构同样如此——只要任务可以抽象成「一堆序列进去,另一堆序列出来」,它就是通用的装配线。

Seq2Seq 最早一鸣惊人的场景是神经机器翻译(NMT)。输入源语言句子,输出目标语言句子,编码器-解码器以端到端方式学习翻译。与传统的统计机器翻译相比,NMT 不再需要单独维护短语表、调序模型等复杂模块,一套架构即可覆盖整个翻译流程。

更广义地看,这类任务都可以用「给定源序列,最大化目标序列概率」来描述:

第二个高频场景是文本摘要:把一篇长新闻当作输入序列,把一句或几句话的摘要当作输出序列,模型学习的是「去粗取精」的压缩能力。第三个场景是对话系统:把用户的消息作为输入序列,把候选回答作为输出序列;大型聊天机器人的早期雏形,很多就是在这种架构上预训练的。三者共享同一个骨架,差异主要在数据形态和序列长度上。

无论阿杰穿的是同传耳机、编辑马甲还是客服工服,他解决问题的底层逻辑始终如一:听懂、提炼、表达。编码器-解码器架构也因此在翻译、压缩、对话等众多序列转换任务中,成为当之无愧的通用基石。

P(y1,y2,…,yT′∣x1,x2,…,xT)=∏t′=1T′P(yt′∣y<t′,c)P(y_1, y_2, \ldots, y_{T'} \mid x_1, x_2, \ldots, x_T) = \prod_{t'=1}^{T'} P(y_{t'} \mid y_{<t'}, c)
这句公式是三类应用共同的「母公式」:无论翻译、摘要还是对话,学到的都是源序列到目标序列的条件概率分布。
  1. 联合概率左边是给定源句时,生成一整句目标语的条件概率。
    P(y1,y2,…,yT′∣x1,…,xT)P(y_1, y_2, \ldots, y_{T'} \mid x_1, \ldots, x_T)
  2. 链式分解把整句概率拆成每个词条件概率的乘积,串行生成的本质。
    ∏t′=1T′P(yt′∣y<t′,c)\prod_{t'=1}^{T'} P(y_{t'} \mid y_{<t'}, c)
  3. 历史条件每一步都以已生成前缀为条件,模型像阿杰一样「一边说一边想」。
    y<t′=y1,…,yt′−1y_{<t'} = y_1, \ldots, y_{t'-1}

局限与发展

随着会议越来越长,阿杰的老搭档 RNN 的疲惫显而易见:必须按顺序听完才能理解,长句记不住,还要逐词等待。终于有一天,公司请来了一位叫 Transformer 的新同事——他不再逐词听,而是把整页文稿同时摊在桌上看,让每一个词直接与其他所有词对话。

RNN 时代的编码器有两个先天局限:一是长程依赖问题——信息沿时间步逐级传递,距离过远时梯度容易消失,模型记不住开头的关键内容;二是顺序计算瓶颈——第 $t$ 个隐状态依赖第 $t-1$ 个,无法并行,训练速度在大语料上捉襟见肘。注意力机制虽然缓解了前者,却仍在 RNN 骨架上运行。

Transformer 的答案是用自注意力(Self-Attention)彻底取代循环结构。它让序列中的每个词同时作为 Query 去「查询」其他所有词的 Key,再对 Value 做加权求和,从而在一步之内捕捉全序列依赖:

从架构关系看,Transformer 依然保留了编码器-解码器的宏观骨架:它的 Encoder 负责对输入序列做自注意力编码,Decoder 负责对已生成前缀做掩码自注意力,并通过交叉注意力(Cross-Attention)接入编码器的输出。所以,编码器-解码器架构不仅没有过时,反而在 Transformer 时代以更强大的形态延续着「先理解、再生成」的基因。

阿杰的新同事 Transformer 的办公方式改变了,但公司的工作流程没变:仍要有人先读懂材料,再整理成会议纪要。编码器-解码器架构正是这个流程的永恒骨架——它定义了「先听懂、再表达」这一认识世界的通用范式。

Attention(Q,K,V)=softmax ⁣(QK⊤dk)V\mathrm{Attention}(Q, K, V) = \mathrm{softmax}\!\left(\frac{Q K^\top}{\sqrt{d_k}}\right) V
自注意力让所有词「互相对视」:一次矩阵运算就能算出任意两个词之间的关联强度,不再需要逐步传递。
  1. 查询矩阵$Q$(Query)表示「我要找什么信息」,每个词都发起一次查询。
    QQ
  2. 键与值$K$(Key)表示「我能匹配什么」,$V$(Value)是真正携带信息的表示。
    K,  VK, \; V
  3. 点积相似度$Q K^\top$ 计算每对词的匹配分数。
    QK⊤Q K^\top
  4. 缩放除以 $\sqrt{d_k}$ 防止分数过大导致梯度消失,相当于对热度做「降温」。
    QK⊤dk\frac{Q K^\top}{\sqrt{d_k}}
  5. 加权聚合softmax 归一化成权重后乘 $V$,得到每个词融合全句信息的新表示。
    softmax ⁣(QK⊤dk)V\mathrm{softmax}\!\left(\frac{Q K^\top}{\sqrt{d_k}}\right) V

AI 应用场景

神经网络机器翻译系统

阶段:模型训练与推理部署

解决的问题:传统统计机器翻译需要人工维护短语表、调序模型和语言模型,模块多、级联误差大。基于编码器-解码器的 NMT 把「翻译」建模为「源序列到目标序列的条件概率估计」,一套端到端模型直接完成,工程师不再需要为每种语言对单独设计规则。

具体案例:某出海电商平台要支持中英日韩四语商品描述互译。团队用 Transformer 编码器-解码器在平行语料上训练翻译模型,线上服务时对每一句商品文案先编码、再束搜索解码,最终把人工审核成本降低了 60%,长描述翻译的 BLEU 值比旧系统提升 8 个点。

新闻文本自动摘要

阶段:数据预处理与模型微调

解决的问题:新闻 APP 的编辑每天要手工把数百篇长文压缩成摘要,耗时且标准不一。编码器-解码器架构天然支持「长序列进、短序列出」,通过端到端训练学会判断哪些句子承载核心信息,并将它们重组为通顺的摘要。

具体案例:某资讯平台在 50 万篇「新闻-摘要」对上微调了一个基于编码器-解码器的摘要模型。编码器读入整篇文章的 token 流,解码器用束搜索生成不超过 140 字的摘要。上线后摘要生产的吞吐量提高了 20 倍,人工编辑只需做最终润色。

Python 演示

python61 行
import torchimport torch.nn as nnimport torch.optim as optim  class Encoder(nn.Module):    def __init__(self, vocab_size, emb_dim, hid_dim):        super().__init__()        self.embedding = nn.Embedding(vocab_size, emb_dim)        self.rnn = nn.GRU(emb_dim, hid_dim)     def forward(self, src):        embedded = self.embedding(src)        outputs, hidden = self.rnn(embedded)        return hidden  class Decoder(nn.Module):    def __init__(self, vocab_size, emb_dim, hid_dim):        super().__init__()        self.embedding = nn.Embedding(vocab_size, emb_dim)        self.rnn = nn.GRU(emb_dim, hid_dim)        self.fc = nn.Linear(hid_dim, vocab_size)     def forward(self, trg, hidden):        embedded = self.embedding(trg)        output, hidden = self.rnn(embedded, hidden)        pred = self.fc(output)        return pred, hidden  class Seq2Seq(nn.Module):    def __init__(self, encoder, decoder):        super().__init__()        self.encoder = encoder        self.decoder = decoder     def forward(self, src, trg):        hidden = self.encoder(src)        output, hidden = self.decoder(trg, hidden)        return output  def train():    model = Seq2Seq(Encoder(10, 16, 32), Decoder(10, 16, 32))    optimizer = optim.Adam(model.parameters())    loss_fn = nn.CrossEntropyLoss()    for epoch in range(50):        src = torch.randint(1, 10, (5, 4))        trg = torch.randint(1, 10, (5, 4))        pred = model(src, trg)        loss = loss_fn(pred.reshape(-1, 10), trg.reshape(-1))        optimizer.zero_grad()        loss.backward()        optimizer.step()        if epoch % 10 == 0:            print(f"epoch {epoch}, loss {loss.item():.3f}")  if __name__ == "__main__":    train()
目的:用 PyTorch 从零搭建一个极简的 GRU 编码器-解码器(Seq2Seq),并跑通一轮完整的训练循环。它不包含注意力,但清晰展示了编码器生成上下文向量、解码器自动回归生成目标序列的核心骨架。
  1. self.rnn = nn.GRU(emb_dim, hid_dim)定义一个 GRU 循环网络,它是编码器的「记忆单元」,相当于阿杰脑中的笔记板。
  2. outputs, hidden = self.rnn(embedded)将整条输入序列一次性送入 GRU,返回每个时刻的隐状态和最终隐状态。
  3. return hidden只把最终的隐状态(也就是上下文向量 c)传给解码器。
  4. output, hidden = self.rnn(embedded, hidden)解码器以编码器传来的 hidden 作为初始状态,逐时间步生成输出。
  5. pred = self.fc(output)通过一个线性层把隐状态映射为词表大小的得分,softmax 后就得到词的概率分布。
  6. loss = loss_fn(pred.reshape(-1, 10), trg.reshape(-1))用交叉熵比较预测分布与真实目标词,得到「翻译错误程度」。
  7. optimizer.zero_grad()` / `loss.backward()` / `optimizer.step()梯度清零、反向传播、参数更新,这就是训练套娃的小三轮。

常见误区

误区我总以为 Seq2Seq 里的编码器和解码器必须是一对孪生兄弟——都用 LSTM 就都用 LSTM,用 GRU 就都用 GRU,否则模型会「不匹配」。

正解编码器与解码器在结构上完全独立,它们只需要通过上下文向量对接即可。编码器可以用双向 LSTM,解码器可以用单向 GRU;甚至在 Transformer 时代,编码器是 Self-Attention 堆叠、解码器是 Masked-Attention 堆叠,结构不同但协作默契。就像阿杰的「听觉系统」和他的「发声系统」本来就是两套不同的器官,只要共享同一个语义接口就行。

为何常见:因为教科书示例中 Encoder 和 Decoder 往往都是同一种 RNN cell,看起来像「配对出场」,让人误以为结构必须对称。

误区我觉得 c 就是 h_T,因为很多入门教程的图里都画着「最后一个 hidden 直接连到解码器」。这是唯一正确的取值方式吧?

正解$c = h_T$ 只是最简单的一种聚合方式。你完全可以用平均池化、最大池化、或者注意力加权求和来聚合所有隐状态。事实上,现代 Seq2Seq 几乎不再使用单一的 $h_T$,而是用注意力机制为每一步生成动态的 $c_{t'}$。固定取最后一位,就像让阿杰只听清句尾就断定全句意思,显然不是最优策略。

为何常见:因为早期经典论文和教学图为了直观,常把「最后一个 hidden」画成唯一的传递箭头,简化成了共识。

误区编码器-解码器不是叫「神经机器翻译」吗?那它应该只能处理一种语言到另一种语言的翻译吧?

正解Seq2Seq 的定位是「序列到序列」的通用框架,翻译只是它最出名的应用。文本摘要(长序列→短序列)、对话生成(用户消息→回复)、语音识别(音频帧序列→文本序列)、甚至代码生成(注释序列→代码序列)都属于序列转换任务,都能套用编码器-解码器骨架。凡是「一堆东西进去、另一堆东西出来」的任务,它都有用武之地。

为何常见:Seq2Seq 最早在 2014 年因机器翻译论文走红,「机器翻译」这个标签被贴得太响,掩盖了它作为通用架构的本质。

误区我训练时解码器输入是上一步生成的结果,那推理时肯定也是同样的,反正模型就是一个 RNN 往前跑,没什么区别。

正解训练时用的是「教师强制」——即便模型输出了错误词,我们仍然把真实目标词喂给下一步;推理时没有老师在场,只能用模型自己上一步生成的词继续。两者的输入分布不一致,这会产生「曝光偏差」:训练时模型没见过自己的错误,推理时一步错就可能导致连环错。这也是为什么很多系统会加入计划采样(Scheduled Sampling)来让训练更贴近推理。

为何常见:因为单向看模型结构确实都是「上一步输出进入下一步输入」,但忽略了训练数据流中「谁来提供上一步输入」这个关键差异。

误区双向编码只是把两个方向的隐状态拼在一起,应该只影响编码器本身吧?反正上下文向量最后都会传给解码器,是否双向无所谓。

正解双向编码让每一个源位置的隐状态同时包含「左侧」和「右侧」的上下文信息,这些更丰富的隐状态正是注意力机制要查询的对象。解码器在做对齐时,会为每个源词计算权重;如果 $h_t$ 只是单向的,模型对位于句子后半段的词就缺乏前文线索,对齐质量会明显下降。阿杰翻译时能准确抓住一个跨越全句的否定词,靠的正是双向理解带来的全局视野。

为何常见:人们容易把编码器看成「一个黑盒压缩器」,忽略隐状态本身是注意力查询的目标,从而低估了双向编码对下游解码的影响。

面试题

Q1. 编码器-解码器架构中,编码器的主要职责是?

单选题 · easy

  • A.对输出序列进行随机采样
  • B.理解输入序列并编码语义← 正确答案
  • C.计算输出词表的概率分布
  • D.负责对序列做束搜索

答案:B。编码器负责把输入序列「听懂」并浓缩成语义表示,对应阿杰的听觉-理解系统。A 是采样策略,C 是解码器的输出层职责,D 是推理阶段的搜索策略,都不属于编码器的核心职责。

Q2. 最简单的上下文向量 c 通常取编码器的哪个值?

单选题 · easy

  • A.编码器的第一个隐状态
  • B.所有隐状态的随机采样
  • C.编码器的最后一个隐状态← 正确答案
  • D.解码器的最后隐状态

答案:C。最简单的聚合方式是 $c = h_T$,即取编码器读完整个源句后的最终隐状态。取第一个隐状态会丢失几乎全部信息,随机采样更不正确,解码器的隐状态则属于生成阶段而非编码阶段的产物。

Q3. 关于「教师强制」(Teacher Forcing)训练策略,正确的理解有?

多选题 · mid

  • A.训练时用真实目标词作为解码器输入← 正确答案
  • B.推理时用模型自生成词作为解码器输入← 正确答案
  • C.教师强制能完全消除训练与推理的差异
  • D.教师强制可提升训练稳定性← 正确答案

答案:ABD。教师强制在训练时用真实词喂给解码器,让学习更稳定;推理时没有真值,只能用自生成词,因此训练与推理必然存在「曝光偏差」,C 正确说法不成立。

Q4. 注意力机制中,Softmax 权重的主要作用是什么?

单选题 · mid

  • A.让所有注意力权重之和为 1← 正确答案
  • B.让权重值变成 0 或 1
  • C.随机打乱源词的排列顺序
  • D.增加解码器模型参数

答案:A。softmax 把匹配分数归一化为概率分布,使所有源位置的权重和为 1,便于做加权求和。它不会把权重变成 0/1 硬选择,也不涉及乱序或加参。

Q5. 解码器逐个生成目标词时,模型需要执行的核心操作是?

单选题 · mid

  • A.计算上下文与源词的距离
  • B.在词表上产生分布并选词← 正确答案
  • C.对源序列进行随机排序
  • D.让编码器重新读一遍

答案:B。解码器每一步通过线性层和 softmax 在词表上产生概率分布,再按策略(贪心或束搜索)选词,然后作为下一步输入。A、C、D 都不是解码器的工作方式。

Q6. 关于 Seq2Seq 的信息瓶颈问题,下列表述正确的有?

多选题 · hard

  • A.固定长度向量难以承载长句信息← 正确答案
  • B.注意力机制缓解了信息瓶颈← 正确答案
  • C.双向编码彻底解决了该问题
  • D.长句中早期信息容易在末尾丢失← 正确答案

答案:ABD。固定长度的上下文向量是容量瓶颈,长句的早期信息经多步传递后容易被覆盖。注意力通过动态加权求和让解码器直接访问所有源位置,显著缓解瓶颈。双向编码只丰富了隐状态,不能彻底解决问题。

Q7. 束搜索(Beam Search)与贪心解码的本质区别是?

单选题 · hard

  • A.束搜索每步只留一条最优路径
  • B.束搜索每步保留 k 条候选路径← 正确答案
  • C.贪心解码会做全局最优搜索
  • D.两种方式数学上完全等价

答案:B。贪心解码每步只取当前概率最高的词,是短视的局部最优;束搜索每步保留得分最高的 k 条候选路径,最终选整体最优的一条。这是解码质量与计算开销之间的权衡。

Q8. 推理阶段解码器每一步的输入中,必须包含?

单选题 · mid

  • A.上一步生成的目标词← 正确答案
  • B.下一个源词的向量
  • C.编码器的全部输出
  • D.预先设定的噪声词

答案:A。推理时没有标准答案,解码器只能把自己上一步生成的词作为下一步输入,形成自回归闭环。B、C、D 都不是推理时解码器输入的必要组成部分。

Q9. 关于编码器-解码器架构与注意力机制,下列表述正确的是?

多选题 · extreme

  • A.编码器可由 Transformer 担任← 正确答案
  • B.解码器必须是循环神经网络
  • C.自注意力可捕捉全序列依赖← 正确答案
  • D.注意力最早成功用于机器翻译← 正确答案

答案:ACD。编码器可以由 RNN、CNN 或 Transformer 担任,解码器同样可以用 Transformer(其内部是自回归生成),因此 B 错误。自注意力一次计算任意词对关联,确实能捕捉全序列依赖;注意力机制最早在 2015 年的中英机器翻译任务上取得突破。

Q10. 下面哪个任务最不适合用编码器-解码器架构建模?

单选题 · easy

  • A.英译中机器翻译
  • B.新闻长文自动摘要
  • C.图像像素值分类← 正确答案
  • D.聊天机器人对话生成

答案:C。图像像素值分类是把每个像素映射到离散标签,输入输出是「一对一」的逐点分类,没有明显的「序列到序列」转换结构。翻译、摘要、对话都是典型的序列转换任务,非常适合 Seq2Seq。