现代循环神经网络:门控与序列到序列
本章来源:本文整理自《动手学深度学习》(zh.d2l.ai)第 9 章《现代循环神经网络》,原书作者 Aston Zhang、李沐、Zachary C. Lipton、Alexander J. Smola。
本章讲什么
上一章的普通 RNN 有个根本弱点:它对所有输入一视同仁,无法决定何时该记住、何时该跳过、何时该重置信息。而且面对很长的序列,信息在传递中会丢失或变形。
本章介绍 RNN 的现代改进:GRU 和 LSTM 用"门控"机制控制信息的流动;深度和双向 RNN 让网络更强;最后是处理"变长序列到变长序列"问题的编码器-解码器架构(seq2seq),这是机器翻译等任务的基础。
门控循环单元(GRU)
普通 RNN 有三个典型困境:
- 校验和问题:第一个观测影响所有后续预测,需要"记忆元"存储早期重要信息。
- 情感分析中的无关内容:句子里的 HTML 代码不影响情感,需要"跳过"机制。
- 逻辑中断:书的章节之间、牛市和熊市之间,需要"重置"机制。
GRU 用两个可学习的门解决这些问题:
- 重置门 :控制"还想记住多少过去的状态",有助于捕获短期依赖。重置门接近 0 时,旧状态被"重置"为默认值。
- 更新门 :控制"新状态中有多少是旧状态的副本",有助于捕获长期依赖。更新门接近 1 时几乎完全保留旧状态(相当于跳过当前时间步),接近 0 时新状态几乎完全来自新信息。
门的值在 0 到 1 之间(由 sigmoid 算出)。正是因为更新门可以让信息"原样穿过"很多时间步,GRU 能有效缓解梯度消失、捕获超长距离依赖。GRU 是 LSTM 的简化变体,效果相当但计算更快。
长短期记忆网络(LSTM)
LSTM(1997 年,比 GRU 早近 20 年)是解决"长期信息保存"问题的最早方法之一。它的设计灵感来自计算机的逻辑门——用"门"来决定何时读入、何时遗忘、何时输出。
LSTM 在隐状态之外引入一个记忆元(memory cell) ——与隐状态同形状、专门记录附加信息的内部状态——并用三个门控制信息流:
- 输入门:决定读入多少新数据。
- 遗忘门:决定保留多少过去的记忆元内容。
- 输出门:决定把多少记忆元内容输出到隐状态。
核心更新是:新的记忆元 = 遗忘门 × 旧记忆元 + 输入门 × 新候选内容。当遗忘门恒为 1、输入门恒为 0 时,记忆元会原样穿越整个序列——这正是缓解梯度消失、捕获长距离依赖的关键。隐状态是记忆元的门控版本。
值得注意的是:只有隐状态进入输出层,记忆元完全是内部信息。
深度循环神经网络
单层 RNN 的表达能力有限。与多层感知机通过加深增强表达力类似,RNN 也可以堆叠多层:每层的隐状态同时向两个方向传递——传到当前层的下一个时间步,以及作为输入传到下一层的当前时间步。输出层只基于最后一层的隐状态。
不同层可以捕捉不同粒度的信息:比如金融市场的牛熊状态由较深的层维持,短期的动态由较浅的层记录。深度 RNN 训练更困难,需要谨慎调参,速度也明显变慢。
双向循环神经网络
很多任务需要利用"下文"信息。比如填空"我___饿了,我可以吃半头猪"——"半头猪"这个下文强烈暗示答案应是"非常"。普通 RNN 只能看到过去,看不到未来。
双向 RNN 的解决办法:在原有从第一个词元向前运行的 RNN 之外,再增加一个从最后一个词元反向运行的 RNN。每个时间步把前向隐状态和反向隐状态拼接后送入输出层,从而同时利用过去和未来的信息。
但有一个重要警告:双向模型不能用于"预测下一个词元"的语言模型任务——训练时有未来数据可用、测试时没有,精度会严重崩溃。它只适用于序列编码(如翻译)、命名实体识别、填补缺失词等场景。此外双向 RNN 计算很慢。
编码器-解码器架构
处理"变长序列 → 变长序列"问题(如机器翻译)的通用架构由两个组件构成:
- 编码器(encoder):把长度可变的输入序列压缩成固定形状的编码状态。
- 解码器(decoder):把固定形状的编码状态逐步映射回长度可变的输出序列。
以英译法为例:编码器读入 "They are watching ." 编码成一个状态,解码器基于这个状态逐词元生成 "Ils regardent ."。
这一架构是所有现代序列转换模型(seq2seq、注意力、Transformer)的共同骨架。
序列到序列学习(seq2seq)
用两个 RNN 具体实现编码器-解码器,就得到 seq2seq:
- 编码器:先经嵌入层把词元索引变成稠密向量,再喂给多层 GRU/LSTM,把所有时间步的隐状态汇总成一个上下文变量 c(通常取最后时间步的隐状态)。
- 解码器:用编码器最终隐状态初始化自己的隐状态,每个时间步把上下文变量与当前输入拼接后送入自己的 RNN,用全连接层 + softmax 输出下一个词元的概率分布。
训练有两个关键技巧:
- 强制教学(teacher forcing):用真实输出序列作为解码器输入,而不是用模型自己的预测。这样训练更稳定、收敛更快。
- 带遮蔽的损失:把填充词元(
<pad>)对应的损失置零,防止无意义的填充干扰训练。
预测时逐词元取概率最高的词元作为下一步输入,遇到 <eos> 就停止——像"逐词元接龙"。
评估用 BLEU:度量预测与标签序列的 n 元语法匹配程度,给更长的 n 元语法更大权重,并用系数惩罚过短的预测。
束搜索
解码时,目标是从所有可能的输出序列中选出概率乘积最大者,但直接搜索不可行(词表一万、长度 10 时需评估 10^40 个序列)。三种策略对比:
- 贪心搜索:每个时间步只取条件概率最高的词元。计算量最小,但不保证全局最优——某步选次优词元,反而可能让后续各步概率更高,整个序列更优。
- 穷举搜索:列举所有序列找最优,保证最优但计算量是天文数字,几乎不可行。
- 束搜索(beam search):折中方案。每步保留条件概率最高的 k 个候选序列(k 是束宽)。贪心搜索就是束宽 k=1 的特例。评分时会用系数惩罚长序列(长序列概率连乘会天然偏低)。
通过灵活选择束宽,可以在正确率与计算代价之间权衡。
小结
- GRU 用重置门和更新门控制信息流动,缓解梯度消失、捕获长依赖。
- LSTM 引入记忆元和输入/遗忘/输出三个门,是捕获长距离依赖的经典方法。
- 深度 RNN 堆叠多层增强表达力,双向 RNN 同时利用前后信息。
- 编码器-解码器架构把变长序列压缩成固定状态再展开成变长序列。
- seq2seq 用强制教学、带遮蔽损失训练,用 BLEU 评估。
- 束搜索在贪心与穷举之间折中,用束宽控制质量与代价的权衡。
关键术语
| 术语 | 一句话解释 |
|---|---|
| GRU | 带重置门和更新门的 RNN 变体 |
| 重置门 / 更新门 | 控制忘记多少过去 / 保留多少旧状态 |
| LSTM | 带记忆元和三个门的 RNN |
| 记忆元 | 记录附加信息、与隐状态同形状的内部状态 |
| 输入门 / 遗忘门 / 输出门 | 控制读入 / 保留 / 输出 |
| 深度循环网络 | 多层 RNN 堆叠 |
| 双向循环网络 | 前向 + 反向 RNN 拼接,同时利用前后信息 |
| 编码器 / 解码器 | 压缩输入序列 / 展开输出序列 |
| 上下文变量 | 编码器对输入序列的汇总 |
| seq2seq | 用 RNN 编码器-解码器做序列转换 |
| 强制教学 | 训练时用真实输出而非模型预测作为输入 |
| BLEU | 基于 n 元语法匹配的翻译质量指标 |
| 束搜索 / 束宽 | 每步保留 k 个最优候选 / k 的大小 |