第 2 天 · 一条加法通道,让 RNN 记得住远处的信息
一句话
Colah 用逐步拆解的示意图讲清 LSTM 的内部结构。一条细胞状态贯穿所有时间步,遗忘门、输入门、输出门分别决定删什么、写什么、读什么。细胞状态主要靠加法更新,所以梯度能跨越很多时间步。这篇博文成了学习 LSTM 的标准入门材料。
论文讲了什么
这篇博文不提出新方法。它把 1997 年提出的长短期记忆网络(Long Short-Term Memory, LSTM)画成一组可以逐步看懂的图。
问题:长程依赖。补全“天上飘着白___”,只看前几个字就够了。补全“我在成都长大……所以我最爱吃___”,要回看几十个词。普通 RNN 理论上能做到,实践中做不到。梯度每往回传一步,就要乘一次循环权重和激活函数的导数。几十步之后,梯度趋近 0。这叫梯度消失(vanishing gradient)。Hochreiter 1991 年和 Bengio 等人 1994 年分析过它的根本原因。
方法:细胞状态加 3 个门。LSTM 在隐藏状态之外增加一条细胞状态(cell state)C_t。它沿时间横向贯穿,只经过少量逐元素运算。门(gate)是一个 sigmoid 层,输出 0 到 1 之间的值,作用像阀门。设 z = [h_{t-1}, x_t]:
- 遗忘门:
f_t = σ(W_f · z + b_f),决定旧记忆保留多少。 - 输入门:
i_t = σ(W_i · z + b_i),决定新内容写入多少。候选内容是C̃_t = tanh(W_C · z + b_C)。 - 细胞更新:
C_t = f_t * C_{t-1} + i_t * C̃_t。 - 输出门:
o_t = σ(W_o · z + b_o),输出h_t = o_t * tanh(C_t)。
为什么有效。关键在细胞更新那一行是加法。遗忘门接近 1 时,C_{t-1} 几乎原样传到 C_t,梯度也几乎原样传回去。网络自己学习什么时候保留记忆、什么时候清空记忆。
变体。博文介绍了 3 种常见变体:
- 窥视孔连接(peephole connections):门也能读取细胞状态。Gers 和 Schmidhuber 2000 年提出。
- 耦合门:用
1 - f_t代替输入门。忘掉多少,就写入多少。 - 门控循环单元(Gated Recurrent Unit, GRU):Cho 等人 2014 年提出。它合并细胞状态和隐藏状态,只用 2 个门。
哪个变体最好?博文引用了 2 项研究。Greff 等人 2015 年的对比显示,主流变体效果接近。Jozefowicz 等人 2015 年测试了 1 万多种结构,只在部分任务上找到优于 LSTM 的结构。
结尾展望。Colah 认为下一个大方向是注意力机制:让 RNN 每一步从一大块信息中挑选要看的部分。2 年后,Transformer 把这个方向推到了极致。
关键概念
- 长短期记忆网络(Long Short-Term Memory, LSTM)
- Hochreiter 和 Schmidhuber 1997 年提出的 RNN 结构。它用细胞状态保存长期信息,用门控制读写,专门解决普通 RNN 记不住远处信息的问题。
- 细胞状态(cell state)
- 贯穿所有时间步的记忆通道。它的更新公式以加法为主,信息和梯度都能沿它走很远。可以把它看成 LSTM 的“长期记忆”,隐藏状态是“当前输出”。
- 门(gate)
- 一个 sigmoid 层加一次逐元素乘法。sigmoid 输出 0 表示全部挡住,输出 1 表示全部放行。LSTM 有遗忘门、输入门、输出门 3 个门。
- 梯度消失(vanishing gradient)
- 梯度沿时间反向传播时,每一步都乘一个小于 1 的因子。连乘几十次后梯度接近 0,早期时间步的参数几乎学不到东西。
- 门控循环单元(Gated Recurrent Unit, GRU)
- LSTM 的简化版。它用更新门同时负责“忘记”和“写入”,再用重置门控制历史信息的使用。参数更少,效果在多数任务上与 LSTM 接近。
历史位置:为什么值得读
LSTM 由 Hochreiter 和 Schmidhuber 1997 年提出。最初版本没有遗忘门。Gers、Schmidhuber 和 Cummins 2000 年加上遗忘门,形成今天通用的结构。2013–2015 年,LSTM 在语音识别、机器翻译和图像描述上接连刷新纪录。其中的 seq2seq 机器翻译,出自第 3 天论文的两位作者 Sutskever 和 Vinyals(与 Le 合作)。
LSTM 的问题是原始论文难读。各篇论文的记号不统一,公式之间的数据流看不出来。Colah 这篇博文用统一的配色和逐门拆解的图,把 LSTM 从一组公式变成一张能画出来的数据流图。它被大量转载和翻译,后来很多教材的 LSTM 图都沿用了这种画法。
读它的理由:
- 第 1 天的 char-rnn 实验用的就是 LSTM。
- 第 3 天的 dropout 方案直接作用在 LSTM 上。
- 第 15 天的 Bahdanau 注意力建立在 RNN 编码器上。
- “用加法通道让梯度直通”的思想,后来在 ResNet(第 9–10 天)和 Transformer 的残差连接里再次出现。
学前准备
- 先看第 1 天,理解 RNN 的隐藏状态和 BPTT
- 熟悉 sigmoid 和 tanh 的取值范围与导数
- 理解向量拼接和逐元素乘法
- 能解释为什么很多个小于 1 的数连乘会趋近 0
在原仓库怎么学
原仓库第 2 天用 NumPy 从零实现 LSTM,包括手写的反向传播。建议按下面的顺序学:
- 先读 Colah 原博文,把 4 个公式抄在纸上。再打开 README.md 看本天的结构。
- 读 implementation.py 中的
LSTM类。先看forward,对照纸上的公式;再看backward,找到细胞状态梯度的两个来源。 - 运行 train_minimal.py,用 data/input.txt 训练一个字符级 LSTM,和第 1 天的 RNN 比较生成质量。
- 打开 notebook.ipynb,配合 visualization.py 看 3 类图:门激活模式、细胞状态演化、LSTM 与普通 RNN 的梯度流对比。
- 做 exercises/ 里的 5 个练习:从零搭 LSTM、门激活分析、消融实验、长程依赖测试、LSTM 与 GRU 对比。
- 对照 exercises/solutions/ 检查答案,最后用 CHEATSHEET.md 复习。
建议:练习 3 的消融实验最值得做。依次去掉遗忘门、输入门、输出门,在同一份数据上比较损失,可以直接看到每个门的作用。练习 4 用来检验 LSTM 是否真的比第 1 天的 RNN 记得更远。
今天再看
被取代的:2017 年之后,Transformer 在语言任务上取代了 LSTM。LSTM 必须逐步计算,无法在序列方向上并行训练。在 GPU 时代,这是硬伤。
还活着的:门控思想没有消失。
- Transformer 前馈层常用的 SwiGLU 是一种门控线性单元。
- Mamba 用依赖输入的选择机制决定保留和遗忘,作用和遗忘门相同。
- 2024 年,Hochreiter 团队发表 xLSTM,用指数门和矩阵记忆重新扩展 LSTM。
- 流式语音、时间序列预测和嵌入式设备上,LSTM 和 GRU 仍在生产环境使用。
和大语言模型的联系:细胞状态的加法更新和残差连接是同一个思想。大模型里的信息沿残差流(residual stream)逐层传递,每层只读写其中一部分。理解了细胞状态,就容易理解残差流。
容易卡住的地方
- 4 组门的权重容易混。建议把它们拼成一个形状为 4H × (H + D) 的矩阵,做一次矩阵乘法后再切成 4 份,代码短且不易出错。
- 反向传播时,细胞状态的梯度有 2 个来源:下一步的 C_{t+1} 和本步的 h_t。漏掉任何一个,数值梯度检查都会失败。
- 遗忘门偏置初始化为 0 时,初始遗忘门约为 0.5,记忆衰减很快。建议初始化为 1,Jozefowicz 等人 2015 年验证过这个做法。
- LSTM 不能让梯度“永不消失”。遗忘门长期小于 1 时,梯度仍按遗忘门的连乘衰减。它缓解梯度消失,没有消除它。
延伸阅读
- 原论文:Understanding LSTM Networks
- 原仓库第 2 天目录:02_Understanding_LSTM/ —— 代码、笔记本、练习与答案(英文)
- LSTM: A Search Space Odyssey —— Greff 等人 2015 年,8 种 LSTM 变体的大规模对比
- Learning Phrase Representations using RNN Encoder-Decoder —— Cho 等人 2014 年,提出 GRU 的论文
- xLSTM: Extended Long Short-Term Memory —— 2024 年,LSTM 原作者团队的现代扩展