查看全课大纲(第 43 / 69 节)
- 1.NLP 的研究领域、应用与学习路径
- 2.自然语言的基本术语
- 3.信息论基础:信息熵与交叉熵
- 4.语言的进化与语义变迁
- 5.主观概率、客观概率与条件概率
- 6.贝叶斯原理与推理
- 7.随机变量:二项式、期望方差与联合概率
- 8.常见概率分布
- 9.辛普森悖论与贝叶斯解题实例
- 10.语言模型:语言概率与词袋模型
- 11.n-gram 语言模型(二元 / 三元 / N-Gram)
- 12.语言模型评价:交叉熵、困惑度与插值
- 13.朴素贝叶斯文本分类:垃圾邮件
- 14.拼写检查
- 15.中文分词:构词法、最大匹配、最优路径与 Jieba
- 16.词表示问题与语义相似度
- 17.TF-IDF 权重处理
- 18.One-Hot 表达与词表示的局限
- 19.Word2Vec 核心思想
- 20.Word2Vec 训练过程
- 21.Skip-gram 模型详解
- 22.词性标注任务与标注方法(规则 + N-Gram)
- 23.EM 算法与混合模型
- 24.高斯混合模型 GMM
- 25.从混合模型到隐马尔可夫模型
- 26.隐马尔可夫模型(HMM)推导与维特比解码
- 27.线性链条件随机场 CRF
- 28.贝叶斯网络与图模型
- 29.隐马尔可夫链与 HMM 推导
- 30.PLSA 主题模型
- 31.LSI 与 SVD 向量表达
- 32.LDA 与狄利克雷分布
- 33.主题模型实验复现(困惑度 / 分类 / 相似度 / 延展)
- 34.上下文无关文法(CFG)与句法分析
- 35.概率上下文无关文法 PCFG
- 36.统计机器翻译:词对齐与翻译模型
- 37.统计机器翻译中的对齐模型与参数估计
- 38.从统计机器翻译到神经机器翻译
- 39.神经元与反向传播速览(指向深度学习课)
- 40.CNN 原理及其在 NLP 中的应用
- 41.循环神经网络的基本原理与 Elman / Jordan 网络
- 42.LSTM:长短期记忆网络的核心思想与分步实现
- 43.Encoder-Decoder 框架
- 44.Seq2Seq 与早期注意力机制
- 45.注意力机制的背景与动机
- 46.注意力模型实现原理与匹配函数
- 47.记忆网络:组成与计算
- 48.注意力机制的应用与历史延展
- 49.Transformer 结构:Encoder-Decoder 栈与 Self-Attention
- 50.Multi-Head Attention、FFNN 与位置编码
- 51.层归一化、损失函数与 Universal Transformer 延展
- 52.预训练范式:从 ELMo 到 BERT
- 53.BERT 与掩码语言模型
- 54.BERT 下游任务微调与 GLUE 口径
- 55.GPT 与自回归语言建模
- 56.GPT-1 到 GPT-4 的演进
- 57.指令微调与 RLHF
- 58.分词器:BPE、WordPiece 与中文词表
- 59.上下文窗口与长文本处理
- 60.能力边界、成本与适用场景
- 61.文本分类实战:从朴素贝叶斯到逻辑回归
- 62.命名实体识别实战
- 63.文本生成与摘要实战
- 64.语义检索与向量库实战
- 65.RAG 知识库问答
- 66.NLP 评估指标:BLEU / ROUGE / BERTScore 与人工评估
- 67.幻觉与事实性问题
- 68.文本与知识结合(知识图谱压缩)
- 69.跨媒体信息检索与未来展望
Encoder-Decoder 框架
小象实战讲义 · 自然语言处理
在自然语言处理中,我们常常需要处理序列到序列(Sequence-to-Sequence, Seq2Seq)的转换任务,例如机器翻译、文本摘要和对话生成。这些任务的核心挑战在于输入和输出序列的长度和结构可能完全不同。本节课,我们将从图像处理中的编码-解码思想入手,逐步引入并深入剖析专为序列转换设计的 Encoder-Decoder 框架。理解这一框架是学习后续注意力机制、Transformer 乃至现代大模型的基础。
💡 核心导读
- 从图像到文本:回顾图像处理中的自编码器(AutoEncoder)和 Pix2Pix 模型,理解“编码-解码”思想如何从固定尺寸的图像转换,迁移到变长序列的文本转换。
- 框架定义:明确 Encoder-Decoder 框架的通用结构,即编码器将输入序列压缩为固定维度的上下文向量,解码器再基于此向量生成输出序列。
- 核心挑战:分析该框架在处理自然语言任务(如机器翻译)时面临的核心挑战——如何将变长的输入信息有效压缩,并指导解码器生成变长的、对齐关系复杂的输出。
- 桥梁作用:认识 Encoder-Decoder 框架作为连接传统神经网络(如 CNN)与序列建模网络(如 RNN/LSTM)的关键桥梁,为后续引入注意力机制埋下伏笔。
从图像处理中的编码-解码思想说起
在深度学习领域,“编码-解码”的思想并非自然语言处理所独有。我们首先回顾在计算机视觉中常见的类似结构,这有助于我们建立直观理解。
自编码器(AutoEncoder) 是一个典型的编码-解码结构。它的目标是学习输入数据的高效表示(编码)。其结构通常是对称的:输入层和输出层维度相同,中间有一个或多个维度更小的隐藏层(瓶颈层)。网络的任务是尽可能准确地重建输入。
# 一个简化的自编码器概念示例(伪代码)
import numpy as np
# 假设输入是4维向量
def simple_autoencoder_forward(X):
# 编码过程:将4维输入压缩为2维
# W_encoder: (4, 2), b_encoder: (2,)
encoded = np.tanh(np.dot(X, W_encoder) + b_encoder) # 形状: (batch_size, 2)
# 解码过程:将2维编码恢复为4维
# W_decoder: (2, 4), b_decoder: (4,)
decoded = np.tanh(np.dot(encoded, W_decoder) + b_decoder) # 形状: (batch_size, 4)
return decoded # 目标是让 decoded 接近原始 X
# 训练目标:最小化重建误差,例如均方误差 (MSE)
# loss = mean((X - decoded)^2)自编码器的变体可以用于学习数据间的变换关系。例如,给定输入向量 [1, 2, 3, 4],我们希望输出 [2, 4, 6, 8](乘以2的关系)。通过提供成对的 (输入,目标输出) 数据,并修改网络结构(输出层不再是重建输入,而是预测目标),同样的编码-解码架构可以逼近任意复杂的函数变换。
将这一思想扩展到图像,就产生了像 Pix2Pix 这样的图像到图像翻译模型。例如,将白天的街景图片(输入 X)转换为夜晚的街景图片(输出 Y)。此时,编码器通常由卷积神经网络(CNN)构成,通过卷积和池化操作逐步提取图像的高层特征(编码)。解码器则由反卷积(转置卷积)层构成,逐步将高层特征上采样,重建出目标尺寸的图像。
一个重要的改进是 U-Net 结构,它在解码过程中,会将编码器对应层的特征图直接“跳跃连接”到解码器的相应层。这样,解码器在生成细节时,不仅能利用高层语义特征,还能利用底层的局部信息(如边缘、纹理),从而生成质量更高的图像。
U-Net 结构示意图(简化):
输入图像 --> [Conv+Pool] --> [Conv+Pool] --> 瓶颈层(编码)
| |
输出图像 <-- [UpConv+Concat] <-- [UpConv+Concat] <-- (解码)
(Concat 即拼接来自编码器对应层的特征)图像处理的成功案例表明,Encoder-Decoder 框架是一种强大的、用于学习两种数据形态间复杂映射关系的通用范式。
当 Encoder-Decoder 遇见自然语言
现在,我们将目光转向自然语言处理。我们能否将图像中的 Encoder-Decoder 框架直接应用于文本序列呢?答案是可以,但面临新的、独特的挑战。
考虑一个简单的语法纠错任务:
- 输入(错误):
I was take photo at that time. - 输出(正确):
I was taking photo at that time.
在这个例子中,输入和输出序列长度相同,词与词之间基本是一一对应的关系(只有 take -> taking 发生了变化)。对于这种“对齐良好”的序列转换,我们可以借鉴处理图像像素的思路,使用一维卷积(对词序列进行卷积)等方法来构建模型,相对容易。
然而,更普遍且重要的任务是像机器翻译这样的序列转换:
- 输入(英文):
I was taking the photo at that time. - 输出(中文):
我那个时候正在照相。
这里出现了根本性的差异:
- 长度可变:输入是8个词,输出是5个词(
我/那个/时候/正在/照相;若把“那个时候”合为一个词则为4个)。输出序列的长度是未知且可变的。 - 对齐复杂:词与词之间并非一一对应。例如,英文的
taking the photo对应中文的照相;at that time对应那个时候;而正在这个表示进行时的副词在英文原句中并没有直接的对应词,其信息蕴含在taking的-ing形式中。 - 顺序可变:不同语言的语序可能不同,信息出现的顺序会发生变化。
回顾我们之前学过的统计机器翻译(SMT),它通过复杂的对齐模型(Alignment Model)来显式地建模源语言词和目标语言词之间的对应关系(哪个生成哪个,位置如何偏移)。而在深度学习的 Encoder-Decoder 框架中,我们需要一种神经网络结构来隐式地学习并处理这种变长、非单调的对齐关系。
神经网络的 Encoder-Decoder 框架
为了处理变长序列,循环神经网络(RNN)及其变体 LSTM/GRU 成为了自然的选择。一个基础的神经 Encoder-Decoder 框架(也称为 Seq2Seq 模型)工作流程如下:
编码器(Encoder):由一个 RNN(如 LSTM)构成。它逐个读取输入序列
(x1, x2, ..., xT)的每个词。在每个时间步,RNN 更新其隐藏状态。读完整个输入序列后,最终的隐藏状态c(或所有隐藏状态的综合)被视为整个输入序列的上下文向量(Context Vector)或语义编码。这个固定维度的向量旨在概括输入序列的全部信息。编码过程: h_t = RNN(h_{t-1}, x_t) c = h_T (或 c = f(h_1, h_2, ..., h_T))解码器(Decoder):由另一个 RNN 构成。它以上下文向量
c作为其初始隐藏状态,并开始生成输出序列(y1, y2, ..., yT')。在每一个解码时间步t,解码器根据当前的隐藏状态s_t和上一个生成的词y_{t-1},预测下一个词y_t的概率分布。生成过程通常持续直到产生一个特殊的结束符(如<EOS>)。解码过程: s_0 = c y_t ~ P(y_t | {y_1, ..., y_{t-1}}, c) = g(s_t, y_{t-1}) s_t = RNN(s_{t-1}, y_{t-1})
# Seq2Seq 模型概念伪代码(基于RNN)
import numpy as np
# 假设词表大小为V,隐藏层维度为H
VOCAB_SIZE = 10000
HIDDEN_DIM = 256
# 编码器伪流程
def encoder_forward(input_sequence):
# input_sequence: 一系列词索引,长度 Tx
h = np.zeros(HIDDEN_DIM) # 初始隐藏状态
for word_idx in input_sequence:
# word_embedding: 将词索引映射为向量
x = get_embedding(word_idx)
# RNN单元更新(例如LSTM cell)
h = rnn_cell(x, h)
context_vector = h # 最终隐藏状态作为上下文
return context_vector
# 解码器伪流程
def decoder_forward(context_vector, max_len=50):
s = context_vector # 解码器初始状态
prev_word = START_TOKEN_ID # 起始符
output_sequence = []
for t in range(max_len):
# 将上一个词嵌入
prev_embedding = get_embedding(prev_word)
# 更新解码器状态
s = rnn_cell(prev_embedding, s)
# 基于当前状态预测下一个词的概率分布
# logits: (VOCAB_SIZE,)
logits = np.dot(s, W_output) + b_output
probs = softmax(logits)
# 选择下一个词(这里用贪婪搜索,取概率最大的)
next_word = np.argmax(probs)
if next_word == END_TOKEN_ID:
break
output_sequence.append(next_word)
prev_word = next_word
return output_sequence
# 训练时,使用"教师强制"(Teacher Forcing):将真实的目标词作为decoder的输入,而非上一时刻的预测结果。框架的局限与改进方向
上述基础的 Encoder-Decoder 框架虽然开创了神经机器翻译的先河,但其存在一个明显的瓶颈:编码器需要将整个输入序列的信息压缩到一个固定长度的上下文向量 c 中。
这带来了两个问题:
- 信息瓶颈:对于长句子,一个固定维度的向量很难无损地保存所有细节信息,尤其是靠前的词的信息可能会被稀释或遗忘。
- 缺乏对齐机制:解码器在生成每一个目标词时,都访问同一个全局上下文向量
c。这意味着无论生成哪个词,模型所依赖的源语言信息是相同的,无法实现类似统计机器翻译中那种细粒度的、动态的词对齐。
例如,在翻译“我那个时候正在照相”中的“照相”时,模型应该更关注源句中的“taking photo”;而在翻译“那个时候”时,则应更关注“at that time”。基础的 Seq2Seq 模型难以做到这一点。
这个瓶颈正是驱动下一个重大创新——注意力机制(Attention Mechanism)——诞生的核心动力。注意力机制允许解码器在生成每一个词时,“动态地”、“有选择地”去关注输入序列的不同部分,而不是死板地使用同一个压缩向量。这极大地提升了模型处理长序列和复杂对齐关系的能力。
因此,Encoder-Decoder 框架是理解现代序列建模的基石,而注意力机制则是使其真正强大的关键升级。在下一节课中,我们将深入探讨注意力机制的原理与实现。
📝 动手练一练
- 概念辨析:自编码器(AutoEncoder)和用于机器翻译的 Encoder-Decoder 框架,在训练目标和输入输出关系上有何本质区别?
👉 点击查看参考答案
- 训练目标:
- 自编码器:无监督学习。目标是最小化输入与重建输出之间的差异(如均方误差),学习输入数据的高效压缩表示。
- 机器翻译的 Encoder-Decoder:有监督学习。目标是最大化目标序列的条件概率(最小化交叉熵损失),学习从源语言序列到目标语言序列的映射函数。
- 输入输出关系:
- 自编码器:输入和输出是同质的(如图像到图像,文本到文本),且通常是相同或相似的数据。
- 机器翻译的 Encoder-Decoder:输入和输出是异质的(如英语句子到汉语句子),是两种不同形态或语言的序列。
- 思考题:假设我们使用一个基础的 RNN Encoder-Decoder 模型(无注意力)翻译一个长句子。如果翻译结果在句子后半段开始出现明显错误或无关内容,可能是什么原因导致的?从上下文向量
c的角度分析。
👉 点击查看参考答案
这很可能是因为信息瓶颈和长程依赖问题。
- 信息瓶颈:编码器需要将整个长句的信息压缩到一个固定维度的上下文向量
c中。对于长句子,c可能无法有效编码所有信息,尤其是句子开头部分的信息在通过许多 RNN 时间步后可能被后续信息覆盖或衰减。 - 长程依赖:即使使用 LSTM,在非常长的序列上,捕捉最早时间步信息的能力也会下降。因此,解码器在生成句子后半部分时,所依赖的
c中关于句子前半部分的关键信息可能已经丢失或变得模糊,导致生成错误。 - 这也解释了为什么注意力机制至关重要,它允许解码器直接“回看”输入序列的任何部分,缓解了固定长度
c带来的信息瓶颈。
本章小结
本节课我们系统学习了 Encoder-Decoder 框架的来龙去脉。我们从图像处理中的自编码器和 U-Net 等模型出发,理解了“编码-解码”作为一种通用学习范式的思想。随后,我们将其引入自然语言处理领域,定义了由 RNN/LSTM 构成的经典 Seq2Seq 模型结构,明确了编码器生成上下文向量、解码器基于该向量生成序列的工作流程。最后,我们重点分析了该框架在处理变长、复杂对齐的序列转换任务(如机器翻译)时的核心局限——固定长度上下文向量造成的信息瓶颈,这为我们学习下一课的关键技术“注意力机制”做好了充分的铺垫。
📋 行动清单
- 理解自编码器与 Seq2Seq 模型在目标和结构上的异同。
- 能够描述基础的 RNN Encoder-Decoder 模型在机器翻译任务上的完整工作流程。
- 清晰阐述固定长度上下文向量所带来的“信息瓶颈”问题,并理解这是引入注意力机制的主要动机。
—— 小象教研组