s15 序列模型:RNN → LSTM → GRU
WARNING
🧪 Beta公测版本提示:教程主体已完成,正在优化细节,欢迎大家提Issue反馈问题或建议。
文本是有顺序的——"我爱你"和"你爱我"是两回事。序列模型专门处理这种时序数据。词向量从哪来见 文本表示;抛弃循环、改用全体互看见 Transformer。本章把 RNN 的连乘梯度账算清楚,再看 LSTM 那条加法公路为什么能让句首主语活到句末。
一、为什么序列需要专门的模型?
传统的全连接网络(MLP)和卷积网络(CNN)在处理序列数据时有根本性的局限:
MLP 的问题:
- 输入维度固定——无法处理变长序列
- 每个输入位置独立处理——"我/爱/你"三个词分别进入三层神经元,没有时序关联
- 参数与位置绑定——第 1 个词的权重只能学第 1 个位置的特征
CNN 的问题:
- 卷积核有固定感受野——只能看到局部上下文
- 虽然可以通过堆叠层增大感受野,但长距离依赖仍然难以建模
- 不是为序列专门设计的,缺乏显式的时序记忆机制
序列模型的核心需求:
- 变长输入处理能力
- 参数跨时间步共享(同一套参数处理不同位置)
- 显式的记忆机制,能捕捉长距离依赖
- 输入顺序敏感
循环神经网络(RNN)通过一个优雅的循环结构同时满足了以上所有需求。
二、RNN:循环的魔力
2.1 一个 cell 是什么
外面看到的「五个蓝块」不是五套网络,是同一台小机器用了五次。这台小机器叫 cell(细胞):每次只吃当前这一个字和上一格留下的记忆,吐出这一格的新记忆(以及可选的输出)。
PyTorch 里 nn.RNNCell 就是这一格;nn.RNN 是把这一格在整段序列上自动循环。后面 LSTM / GRU 同理:LSTMCell / GRUCell 走一步,LSTM / GRU 走整段。世界模型里的 RSSM 之所以用 GRUCell 而不是 GRU,就是每一步还要插先验 / 后验,必须自己控循环。
2.2 核心公式
RNN 细胞内部只有一本账——隐藏状态
:时间步 的隐藏状态(hidden state),是网络此刻的全部记忆 :上一格记忆——已经揉进了 :当前这个字 / 这一帧 :记忆到记忆的权重(循环连接,五个蓝块共用这一套) :当前输入写进记忆的权重 :把每一维压到 ,防止数值炸掉
核心直觉:
是「刚才记住的」和「现在读到的」线性混合,再挤过 。像人读书:每读一个词,旧印象和这个词搅在一起,变成新印象。代价是:旧印象没有原路可走,必须整包过矩阵和非线性。
demo 里对应 MyRNNCell:h = tanh(W_ih(x) + W_hh(h_prev))。完整实现见 code-demo,文件在仓库 docs/applied/nlp/sequence-models/code/demo.py。
2.3 时间展开(Unrolling)
同一个细胞(同一套
x_1 → [RNN] → h_1 → [RNN] → h_2 → [RNN] → h_3 → ... → h_T
↑共享W_h,Wx↑ ↑共享W_h,Wx↑序列多长都是这一套数,模型体积不随句长增长。这就是「能处理变长输入」的来源。

怎么读这张图:五个蓝块是同一个细胞用了五次。从上往下:字
经 进记忆;从左往右:上一格记忆经 传到这一格;再往下:记忆经 变成输出 。底栏红箭头是训练时从右往左回传,每倒退一步都乘同一个 。
2.4 BPTT:梯度为什么是「乘法」在时间里走
训练时要把最后的损失
要让第
RNN 的前向是
「信息以乘法的方式在时间中传播」说的不是输入里写了个乘号,而是:
旧记忆对更晚记忆的影响,等于一串「
再乘 」连乘。 前向每走一步,旧信息被矩阵打一次折、再被 挤一次;反传要原路回去,折扣就连乘。
| 倒退步数 | 若每步 | 直觉 |
|---|---|---|
| 上一字还在 | ||
| 已经淡了 | ||
| 几乎没了 | ||
| 句首梯度到不了句末 |
这就是梯度消失:不是公式写错了,是这条乘法链太长。若每次
逐步推导:从 到连乘 (点击展开)
LSTM 把「对

怎么读这张图:上半是链式法则拆成「每步一个雅可比」;下半对数坐标里,普通 RNN 的
往回走直线往下掉,LSTM 的细胞状态几乎走平。
三、LSTM:另开一条加法公路,再装三个门
LSTM(Long Short-Term Memory,Hochreiter & Schmidhuber, 1997)没有改 BPTT 这套算法,改的是细胞前向怎么走:不要让长期记忆每一步都过
3.1 一个 cell 上,RNN 和 LSTM 差在哪
| RNN cell | LSTM cell | |
|---|---|---|
| 保管的状态 | 只有 | 两本账: |
| 一步接口 | ||
| 旧记忆怎么变成新的 | 整包: | 公路上加: |
| 有没有开关 | 无 | 三个门 |
| 反传时相邻两步乘什么 | 在 |

怎么读这张图:左栏是 RNN——
和 搅匀过 就变成 。右栏顶上那条粗线是细胞状态 ,旧笔记乘遗忘门、新内容乘输入门,再加在一起;下面四个色块是从 拧出来的旋钮。底栏:训练回传时,RNN 连乘 ,LSTM 在公路上连乘 。
3.2 「乘法传播」对应哪条公式,门要解决什么
上一节 2.4 BPTT 里,RNN 相邻两步乘的是
- 一条可以几乎原样往前加的笔记
(不要每步搅匀) - 一组学出来的 0~1 开关,决定这条笔记「擦掉哪几维、写入哪几维、对外露出哪几维」
门不是 discrete 的 0/1 电闸,是 sigmoid 拧出来的连续旋钮,这样才能对
3.3 细胞状态 怎样引进来
先不管门,只看 LSTM 最狠的那一行——给记忆另开一本账,默认用加法更新:
:上一格的长期笔记(可以一路从句首抬过来) :遗忘门,逐维决定旧笔记留几成( 是逐元素乘,每个记忆槽位自己的开关) :根据当前字新写的候选内容 :输入门,决定新内容写进笔记几成
当某一维
3.4 三个门是怎样从 拧出来的
门不看
遗忘门 — 旧笔记留几成:
输入门 — 新内容写几成:
候选细胞状态 — 新内容本身(仍用
输出门 — 笔记对外露几成(
chunk 成四段(见 MyLSTMCell)。
读「我爱机器学习!」时可以这么想象(一维开关的卡通版):
- 读到「我」:输入门打开,主语写进
的某一维 - 读中间修饰:「爱」「机器」「学习」——遗忘门接近
,主语那一维几乎原样加下去 - 读到「!」:也许拧小某些句法槽;输出门决定这一步的
要不要强调句末语气
3.5 三门公式总表

怎么读这张图:从左进
、 、 。橙色遗忘门乘在公路上;绿色输入门和新候选 相乘后加进公路;紫色输出门从 滤出 。黄框那行 就是加法路径。
demo 里对应的三行就是整章的核心:
c = f * c_prev + i * c_tilde # 公路:留旧 + 写新
o = torch.sigmoid(o_gate)
h = o * torch.tanh(c) # 对外只露一页笔记3.6 门的直觉
| 门 | 作用 | 直觉 |
|---|---|---|
| 遗忘门 | 「读到句号,清空前文句法槽」 | |
| 输入门 | 「遇到主语,记下谁在做事」 | |
| 输出门 | 从 | 「答题时只抄笔记里此刻用得上的几行」 |
LSTM 像一个有条理的学生做笔记:遗忘门决定擦掉哪几行,输入门决定写下新知识点,输出门决定举手发言时念哪几行。笔记本本身是
,发言内容是 。
3.7 为什么这样梯度就不易消失
对公路本身、在某一维上求导(
若遗忘门学会
长期内容可以几乎原样走回句首。这是加法公路,不是每步搅匀。
两点不要推过头:
- 门自己的权重
仍然要经过 sigmoid / 反传,那些旁路还是有非线性。LSTM 减轻的是长期内容 这条主干。 若长期接近 ,这一维照样断。模型要学会「该留的时候把遗忘门拧到 」——这也是为什么常把遗忘门偏置初始化成正数,训练初期先倾向于「多记住」。
一句话:RNN 的 cell 把记忆整包乘进下一步;LSTM 的 cell 把记忆放在
3.8 常见疑问
门是离散的开/关吗? 不是。
LSTM 改了反向传播算法吗? 没有。还是 BPTT。改的是前向递推:多了一条
为什么还要
五个蓝块和 cell 是什么关系? 蓝块 = 同一细胞的五次调用。RNN / LSTM 的差别全部发生在一块内部;展开方式、共享参数、BPTT 的「沿时间连乘」框架是一样的。
四、GRU:LSTM 的精简版
Cho et al. (2014) 提出 GRU(Gated Recurrent Unit),把 LSTM 的三个门收成两个,并且不再单独保管
重置门(reset gate)— 控制忽略多少历史信息:
更新门(update gate)— 控制保留多少旧状态 vs 写入多少新状态:
候选隐藏状态— 用重置门过滤后的历史 + 当前输入:
最终隐藏状态— 更新门做线性插值:
GRU 的核心直觉是
五、RNN vs LSTM vs GRU 对比
| 特性 | RNN | LSTM | GRU |
|---|---|---|---|
| 门数量 | 0 | 3 | 2 |
| 状态变量 | |||
| 梯度传播 | 指数衰减 | 加法路径(稳定) | 加法路径(稳定) |
| 参数量 | |||
| 训练速度 | 快 | 慢 | 中等 |
| 长序列表现 | 差 | 最好 | 好 |
| 典型场景 | 简单时序预测 | 机器翻译、复杂序列 | 当 LSTM 太大时替代 |

六、双向 RNN
标准 RNN/LSTM/GRU 只能从左到右处理序列——
双向 RNN(Bidirectional RNN)同时运行两个独立的循环网络:
- 前向 RNN:从左到右处理,
- 后向 RNN:从右到左处理,
- 拼接输出:
双向 RNN 在序列标注(NER、词性标注)和文本分类中极其有效。但无法用于自回归生成(因为你无法看到"未来"的词)。
七、RNN vs Transformer:时代的交替
2017 年 Transformer 出现后,RNN 系模型在 NLP 中的主导地位逐渐被取代。但这并不意味着 RNN 不再重要:
| 场景 | 选择 |
|---|---|
| 长序列(>2048 tokens)且追求最优效果 | Transformer(全局自注意力) |
| 流式/实时处理、逐时间步推理 | RNN/LSTM(自然支持) |
| 计算资源受限 | GRU(参数少、推理快) |
| 时间序列预测(金融、传感器) | LSTM(仍广泛使用) |
| 学习 RNN 原理、BPTT、门控机制 | 必须掌握(本章重点) |
学习价值:RNN→LSTM→GRU→Transformer 这条技术演进路线的每一步都解决了一个明确的问题。只有理解了每一步"为什么",才能真正理解 Transformer 的注意力机制"好在哪里"。
八、本节小结
| 概念 | 一句话总结 |
|---|---|
| cell | 一步映射;RNN 是 |
| RNN | 同一套参数在时间上循环;记忆整包过 |
| 乘法传播 | |
| BPTT | 仍是链式法则,沿展开后的时间往回传;LSTM 没改这套算法 |
| 细胞状态 | 加法公路 |
| 遗忘 / 输入 / 输出门 | 三个 sigmoid 旋钮:留旧、写新、对外露哪几维 |
| GRU | LSTM 精简版:合并 |
| 双向 RNN | 前向+后向处理,适合标注任务 |
| Transformer | s16 主题,注意力取代循环连接 |
下一节 s16 Attention 与 Transformer 将讨论:序列模型的 seq2seq 架构遇到什么瓶颈,注意力机制如何优雅地解决它,并最终催生了取代 RNN 的全新范式。
📥 Code
| File | View | Download |
|---|---|---|
| demo.py | Open | Download |
| exercise.py | Open | Download |
参考
- Hochreiter, S. & Schmidhuber, J. (1997). Long Short-Term Memory. Neural Computation. (LSTM) [doi:10.1162/neco.1997.9.8.1735]
- Cho, K., et al. (2014). Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation. EMNLP 2014. (GRU) [arXiv:1406.1078]
- Sutskever, I., Vinyals, O., & Le, Q. V. (2014). Sequence to Sequence Learning with Neural Networks. NeurIPS 2014. (Seq2Seq) [arXiv:1409.3215]