30u30 中文导读 / 30 天目录 / 第 2 天

第 2 天 · 一条加法通道,让 RNN 记得住远处的信息

第 1 单元Understanding LSTM NetworksChristopher Olah博客 · 2015
这是导读,不是翻译。先用 10 分钟拿到这篇论文的思想地图,再去读 原论文 →,去原仓库的 02_Understanding_LSTM/ 目录 → 动手写代码。
给孩子讲:这一天有 10 岁孩子能听懂的讲义,带猜字游戏和动手活动,可打印。打开儿童讲义 → · PDF 简体 · PDF 繁體

一句话

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]:

为什么有效。关键在细胞更新那一行是加法。遗忘门接近 1 时,C_{t-1} 几乎原样传到 C_t,梯度也几乎原样传回去。网络自己学习什么时候保留记忆、什么时候清空记忆。

变体。博文介绍了 3 种常见变体:

哪个变体最好?博文引用了 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 图都沿用了这种画法。

读它的理由:

学前准备

在原仓库怎么学

原仓库第 2 天用 NumPy 从零实现 LSTM,包括手写的反向传播。建议按下面的顺序学:

  1. 先读 Colah 原博文,把 4 个公式抄在纸上。再打开 README.md 看本天的结构。
  2. 读 implementation.py 中的 LSTM 类。先看 forward,对照纸上的公式;再看 backward,找到细胞状态梯度的两个来源。
  3. 运行 train_minimal.py,用 data/input.txt 训练一个字符级 LSTM,和第 1 天的 RNN 比较生成质量。
  4. 打开 notebook.ipynb,配合 visualization.py 看 3 类图:门激活模式、细胞状态演化、LSTM 与普通 RNN 的梯度流对比。
  5. 做 exercises/ 里的 5 个练习:从零搭 LSTM、门激活分析、消融实验、长程依赖测试、LSTM 与 GRU 对比。
  6. 对照 exercises/solutions/ 检查答案,最后用 CHEATSHEET.md 复习。

建议:练习 3 的消融实验最值得做。依次去掉遗忘门、输入门、输出门,在同一份数据上比较损失,可以直接看到每个门的作用。练习 4 用来检验 LSTM 是否真的比第 1 天的 RNN 记得更远。

今天再看

被取代的:2017 年之后,Transformer 在语言任务上取代了 LSTM。LSTM 必须逐步计算,无法在序列方向上并行训练。在 GPU 时代,这是硬伤。

还活着的:门控思想没有消失。

和大语言模型的联系:细胞状态的加法更新和残差连接是同一个思想。大模型里的信息沿残差流(residual stream)逐层传递,每层只读写其中一部分。理解了细胞状态,就容易理解残差流。

容易卡住的地方

延伸阅读