本节摘要:文本表示解决后,下一个问题是"如何处理变长序列"。本节讲两条技术线:RNN/LSTM 用循环结构处理时序、Transformer 用自注意力并行处理。围绕这两套模型,讲文本分类(TextCNN/BERT)、序列标注(BiLSTM-CRF)、机器翻译(Seq2Seq+Attention)、问答系统四大核心任务的建模方式。重点拆解 Self-Attention 的 Query-Key-Value 机制、多头注意力为什么有效、位置编码的作用,让你能从零推演 Transformer 的设计。
阅读完本节,你应当能够:
NLP 任务的本质都是在处理变长序列——句子长短不一,词数不同。这与 CV 处理固定尺寸图像完全不同。怎么让神经网络处理变长输入,是 NLP 建模的核心难题。
最早的解法是 RNN(循环神经网络)。它维护一个隐状态,在每个时间步用当前输入和上一步隐状态更新自己,于是能处理任意长度序列。但 RNN 有个致命缺陷:梯度消失。反向传播穿过时间步时连乘,长序列的梯度传不回去,长程依赖学不到。LSTM 用门控机制缓解了这个问题,但 RNN 家族还有个根本缺陷:必须串行计算——第 t 步依赖第 t-1 步的隐状态,无法并行,训练慢。
Transformer(2017 年)的革命性在于:它用自注意力(Self-Attention)绕开了串行依赖。每个位置同时看到所有其他位置,整个序列可以并行计算。这不仅让训练快了几倍,还让长程依赖建模能力大幅提升。从那以后,RNN 在大多数 NLP 任务上被 Transformer 取代。
所以本节的组织逻辑是:先讲 RNN/LSTM 这条线的原理和局限,再讲 Transformer 如何突破这些局限,最后把这两套模型落到四大核心任务上。理解了 RNN 的串行痛点和 Transformer 的并行突破,你才能讲清"为什么 attention is all you need"这句话的分量。
朴素 RNN 在每个时间步 t 计算:h_t = \tanh(W_h h_{t-1} + W_x x_t + b)。隐状态 h_t 编码了到 t 为止的所有信息,用于预测输出。
梯度消失的根源:反向传播穿过时间步时,梯度要乘以每步的雅可比矩阵,连乘 T 次后梯度指数衰减。Sigmoid/Tanh 的导数小于 1,加剧了这个问题。
LSTM(长短期记忆网络) 用三个门和一个细胞状态解决这个问题:
| 门 | 作用 | 类比 |
|---|---|---|
| 遗忘门 | 控制丢弃多少旧细胞状态 | 清理过期记忆 |
| 输入门 | 控制写入多少新信息 | 记下新内容 |
| 输出门 | 控制输出多少细胞状态 | 提取相关记忆 |
LSTM 的关键创新是细胞状态 c_t——它有一条"加法直通"的路径,梯度不必经过门的连乘,所以能传得更远。这和 ResNet 的残差连接思想完全一致:让信息有直通路径。
GRU 是 LSTM 的简化版,合并了遗忘门和输入门为"更新门",参数更少、训练更快,效果通常接近。
Seq2Seq 用于机器翻译等"序列到序列"任务。它用编码器把源序列压缩成一个固定长度的上下文向量,再用解码器从这个向量生成目标序列。
Seq2Seq 的瓶颈是:把任意长度的源序列压成一个固定向量,长序列信息必然丢失。Attention 机制 解决了这个问题——解码器在生成每个目标词时,动态地"看"源序列的所有位置,加权聚焦相关信息。
💡 关键直觉:Attention 的本质是"软查找"。给定一个查询(query),在一个键值对集合里,用 query 和每个 key 算相似度作为权重,对 value 加权求和。它让模型不再依赖固定长度的瓶颈向量,而是按需检索信息。这个思想后来被发扬光大成了 Transformer 的 Self-Attention。
Transformer 把 Attention 从"解码器看编码器"推广到"序列里每个位置看所有其他位置",这就是 Self-Attention。
Self-Attention 的 QKV 机制:每个位置 i 生成三个向量——Query Q_i、Key K_i、Value V_i。计算位置 i 对位置 j 的注意力权重:\text{score}_{ij} = \frac{Q_i \cdot K_j}{\sqrt{d_k}},softmax 归一化后用权重对所有 V 加权求和。
def self_attention(Q, K, V): # Q, K, V: (seq_len, d_k) scores = Q @ K.T / np.sqrt(Q.shape[-1]) # 缩放点积 weights = softmax(scores, axis=-1) # 注意力权重 return weights @ V # 加权求和
为什么要除以 \sqrt{d_k}? 当 d_k 大时,点积结果数值大,softmax 会进入饱和区(梯度趋零)。除以 \sqrt{d_k} 把数值压回合理范围,让梯度健康。
多头注意力 是并行跑 h 组 Self-Attention,每组用不同的 QKV 投影矩阵,最后拼接。它的作用是让模型从不同子空间关注不同关系——一个头可能关注语法依赖,另一个关注语义相似。
位置编码 补上 Transformer 缺失的位置信息。Self-Attention 本身是位置无关的(打乱输入顺序结果一样),所以要显式注入位置。原始 Transformer 用正弦余弦函数生成固定位置编码,BERT 用可学习的位置嵌入,现代大模型用 RoPE(旋转位置编码)支持更长上下文。
⚠️ 常见坑:Transformer 用 LayerNorm 不是 BatchNorm。因为 NLP 序列长度可变、batch 里 padding 不同,BatchNorm 对 batch 维度统计会不准。LayerNorm 对单个样本的特征维度归一化,不受 batch 和序列长度影响。
| 任务 | 输入输出 | 经典模型 | 关键设计 |
|---|---|---|---|
| 文本分类 | 句子 → 类别 | TextCNN、BERT | 池化提取句向量 |
| 序列标注(NER) | 句子 → 每词标签 | BiLSTM-CRF | CRF 建模标签依赖 |
| 机器翻译 | 源句 → 目标句 | Transformer | 编码器-解码器 |
| 问答系统 | 问题+文档 → 答案 | BERT、抽取式 | 起止位置预测 |
文本分类:TextCNN 用多尺度一维卷积捕捉不同 n-gram 特征,池化后接分类层。BERT 微调时取 [CLS] 位置的输出接分类层。
NER(命名实体识别) 是序列标注任务,每个词要打标签(人名、地名、组织等)。BiLSTM-CRF 是经典方案:BiLSTM 提取上下文特征,CRF(条件随机场)在标签序列上建模依赖——比如"B-人名"后面不能跟"B-地名"。CRF 让标签序列合法,比纯 BiLSTM 输出独立标签更准。
机器翻译 是 Seq2Seq 的典型应用,现代翻译几乎都用 Transformer 编码器-解码器。BLEU 是翻译的标准评估指标,基于 n-gram 重叠。
问答系统 分抽取式和生成式。抽取式从文档里找答案片段,BERT 微调时预测答案的起止位置;生成式用大模型直接生成答案。
def select_sequence_model(task, sequence_length, compute_budget): if sequence_length < 100 and compute_budget == "edge": return "LSTM 或 GRU(轻量)" elif task == "translation": return "Transformer 编码器-解码器" elif task in ["classification", "ner"] and compute_budget != "edge": return "BERT 微调" elif sequence_length > 4096: return "带 RoPE 的大模型 或 长序列优化 Transformer" return "Transformer 编码器"
💡 关键直觉:RNN 没有完全过时。在资源受限的边缘设备、超长序列(注意力平方复杂度吃不消)、流式处理(必须逐词处理)场景,RNN/LSTM 仍有位置。但绝大多数场景,Transformer 是默认选择。
标准 Self-Attention 的计算复杂度是 O(n^2)(序列长度的平方),长序列吃不消。几种对策:
| 方法 | 思路 | 适用 |
|---|---|---|
| 稀疏注意力 | 只看局部窗口 | 长文档 |
| 线性注意力 | 用核函数近似 | 超长序列 |
| 滑动窗口 | 分块处理 | 流式输入 |
| RoPE 位置编码 | 外推到更长上下文 | 大模型 |
NER 等任务有几个工程坑:
| 任务 | BERT 微调方式 | 关键点 |
|---|---|---|
| 分类 | 取 [CLS] + 线性层 | 学习率 2e-5 到 5e-5 |
| NER | 每个 token 输出 + CRF | 标签依赖用 CRF |
| QA | 预测起止位置 | 滑动窗口处理长文档 |
| 句子对 | [CLS] A [SEP] B [SEP] | 拼接输入 |
⚠️ 常见坑:BERT 微调时学习率不能大。预训练用的学习率(如 1e-4)会破坏预训练知识,典型微调学习率是 2e-5 到 5e-5,且要用 warmup。
下一节进入预训练语言模型时代,看 BERT 和 GPT 两大范式如何重塑 NLP,以及大模型时代的指令微调、RLHF、Prompt 新范式。
补一组快问快答卡片,覆盖本节任务的常见追问。命名实体识别的 BIO 标注是什么:B 表示实体开始、I 表示实体内部、O 表示非实体,配合条件随机场或模型直接序列标注;为什么早期 NER 用 CRF 而不逐词独立分类:因为相邻标签有强依赖(I 不能跟在 O 后面),CRF 在整条序列上建模转移概率。文本分类里类别不平衡怎么办:加权损失、过采样少数类或欠采样多数类、以及直接调整判决阈值,评估用宏平均 F1 而不是准确率。情感分析的否定词怎么处理:"不好"和"好"的词袋表示完全不同,传统方法靠人工否定词典和句法规则,上下文表示模型天然覆盖这类组合语义,这也是词向量到上下文表示最有说服力的对比案例。机器翻译为什么用 BLEU 而不用准确率:译文一意多形,参考答案不唯一,BLEU 用 n 元组重叠度做软匹配;它的局限是不懂同义改写,所以学术论文都要配人工评估。
训练时解码器的每一步输入都是真实前词(teacher forcing),推理时输入的是自己上一步的输出。一旦某一步输出错了,后续输入的分布和训练时完全不同,错误滚雪球。缓解方法:计划采样(训练时按概率混入模型自己的输出)、以及根本性的方案——强化学习直接优化任务指标,或像大模型那样规模化数据让模型自己学纠错。这道题的考点纵深在于它连接了训练目标与推理行为的错位,同类问题在语音识别和推荐系统里都有镜像。
两个:长程依赖的信息衰减(信号要逐步传递,距离越远损耗越大,注意力一步直达任意位置)和训练串行(时序依赖无法并行,注意力对所有位置同时计算)。补一句时间复杂度的变化:自注意力对序列长度是平方,RNN 是线性,所以长文档场景下注意力反而更贵——这个反向细节能体现你不只是在背优点清单。
给一道可以在白板现场推演的小题,面试里出现率不低。设两个词的序列,每个词的向量维度为二,给定 Q、K、V 三个小矩阵,请手算输出。步骤:先算 Q 乘 K 的转置得到二乘二的注意力分数矩阵;除以根号二(维度开根号)做缩放;对每行做 softmax 得到权重;权重乘 V 得到输出。整个过程五分钟内能推完,但每一行都在检验你是否真的理解矩阵形状的流动——多少候选人能背公式却在"这个矩阵乘哪个的转置"上卡壳。建议考前用随机小矩阵亲手推一遍,形状感是练出来的不是读出来的。