
RNN & BPTT —— 循环神经网络与随时间反向传播
系统讲解循环神经网络(RNN)的数学原理与随时间反向传播(BPTT)算法。从RNN的循环结构与共享参数出发,推导BPTT的梯度表达式,揭示梯度消失与梯度爆炸的数学根源,并介绍梯度裁剪作为应对梯度爆炸的工程解法。附带讨论LSTM如何通过门控机制缓解梯度消失。
阅读文章ZHY's Blog
A UNIVERSE OF IDEAS · BY ZHANG HAOYI
让好奇心 点亮知识宇宙
在代码、模型与思想之间自由漫游。这里持续记录人工智能、机器学习、软件工程与成长实践,让每次阅读都成为一次新的发现。
ARTICLE NOTE
在上一篇博客中,我们直面了循环神经网络最致命的数学困境:∂ht/∂hk 是一个从 k+1 到 t 的矩阵连乘——当谱范数小于1时,梯度指数级衰减,10步前的信息几乎归零;当大于1时,梯度指数级爆炸,训练瞬间崩溃。这一“连乘诅咒”将RNN的有效记忆范围锁死在10-20个时间步以内,使其在面对长文本、长语音或长时间序列时力不从心。
本篇博客正是破解这一“记忆牢笼”的关键章节。我们从LSTM的双轨架构——细胞状态(ct,长时记忆“传送带”)与隐藏状态(ht,短时输出)出发,揭示其核心设计哲学:将信息传递路径从矩阵乘法改为按元素加法。您将看到,细胞状态更新公式 ct=ft⊙ct−1+it⊙c~t 中,∂ct/∂ct−1=diag(ft) 是对角矩阵而非满矩阵——这意味着梯度不再经受矩阵连乘的指数级衰减,而是可以沿细胞状态的“高速公路”几乎无损地流回早期时间步,其代价仅是由遗忘门 ft 控制的逐元素缩放。
随后,我们将深入剖析GRU的两大简化 —— 三门变两门(重置门+更新门)、双状态变单状态 —— 及其约25%的参数量缩减如何在实际训练中带来更快的收敛速度与相近的性能表现,并讨论双向LSTM与深层堆叠LSTM在自然语言处理、语音识别等任务中的典型应用场景。
值得注意的是,本篇是“时序架构”的收官之篇——至此,我们完整走过了从数据表示(张量)→优化目标(概率论)→梯度保真(激活+初始化)→梯度计算(自动微分)→完整训练闭环(MLP+优化器)→空间建模(CNN)→深度跨越(ResNet)→时序建模(RNN/BPTT)→门控记忆(LSTM/GRU) 的全部脉络。您已拥有构建、训练并理解现代深度学习模型的全栈底层认知。现在,请带着“如何让网络记住100步前的信息”的疑问进入正文——理解了LSTM与GRU,您就掌握了序列建模的终极钥匙,也为理解Transformer的自注意力机制铺平了道路。
常规RNN的问题是它内部状态的更新方式是“粗暴”的——每一步的新信息都会与旧信息无差别地混合。LSTM的设计哲学是赋予网络自行决定信息取舍的能力。
与RNN只有一个隐藏状态 ht 在时间步之间传递不同,LSTM引入了两个独立的状态向量在时间轴上并行传递:
细胞状态(Cell State, ct) :这是LSTM的核心,原始论文中称之为 “恒定误差旋转木马”(Constant Error Carousel, CEC) 。可以把它想象成一条“信息高速公路”或“传送带”,负责在整个序列中传递长期记忆。
隐藏状态(Hidden State, ht) :与RNN中的隐藏状态类似,代表了当前时间步的短期记忆和最终输出。
💡 关键洞察:在普通RNN中,信息在时间步之间传递必须经过矩阵乘法(Whhht−1)。而在LSTM中,细胞状态的传递路径是按元素的加法和乘法(ct=ft⊙ct−1+it⊙c~t),没有额外的矩阵连乘,信息可以直接在这条传送带上流动。
LSTM中引入了3个门,即输入门(input gate)、遗忘门(forget gate)和输出门(output gate) 。
LSTM中的“门”是一种让信息选择性通过的结构,设计灵感来源于数字电路中的逻辑门。它的实现非常简单:一个以Sigmoid为激活函数的全连接层,输入通常是当前时间步的输入 xt 和上一个时间步的隐藏状态 ht−1 的拼接向量。
Sigmoid函数将元素值映射到 (0, 1) 区间内:
三个门的分工如下:
| 门 | 符号 | 作用 |
|---|---|---|
| 遗忘门 | ft | 决定是否让上一时刻学到的信息通过或部分通过 |
| 输入门 | it | 计算出候选值,决定哪些新信息写入细胞状态 |
| 输出门 | ot | 决定哪些信息输出到隐藏状态 |
假设隐藏单元个数为 h,给定时间步 t 的小批量输入 Xt∈Rn×d 和上一时间步隐藏状态 Ht−1∈Rn×h。
Step 1:三个门的计算
It=σ(XtWxi+Ht−1Whi+bi)Ft=σ(XtWxf+Ht−1Whf+bf)Ot=σ(XtWxo+Ht−1Who+bo)其中 Wxi,Wxf,Wxo∈Rd×h 和 Whi,Whf,Who∈Rh×h 是权重参数,bi,bf,bo∈R1×h 是偏差参数。
Step 2:候选记忆细胞
C~t=tanh(XtWxc+Ht−1Whc+bc)这里使用值域在 [−1,1] 的 tanh 函数作为激活函数。
Step 3:细胞状态更新(核心!)
Ct=Ft⊙Ct−1+It⊙C~t其中 ⊙ 表示按元素乘法。
这个公式是LSTM的灵魂:
Step 4:隐藏状态计算
Ht=Ot⊙tanh(Ct)输出门控制从细胞状态中读取多少信息到隐藏状态。
这是理解LSTM最核心的部分。让我们从梯度传播的角度来看。
在普通RNN中,隐藏状态的更新是:
ht=ϕ(Wxhxt+Whhht−1+bh)梯度传播的关键项是:
∂ht−1∂ht=Whh⊤⋅diag(ϕ′(ht−1))这是矩阵乘法——谱范数决定了梯度是指数衰减还是爆炸。
而在LSTM中,细胞状态的更新是:
Ct=Ft⊙Ct−1+It⊙C~t关键差异:∂Ct/∂Ct−1 是什么?
∂Ct−1∂Ct=diag(Ft)这是一个对角矩阵,而不是满矩阵!
这意味着:
🔑 核心结论:LSTM通过将信息传递路径从矩阵乘法改为按元素加法,从根本上改变了梯度传播的数学性质。梯度不再需要经过一连串的矩阵相乘,而是可以通过细胞状态的“高速公路”直接流回早期时间步。
从另一个角度看,门控机制也是为了解决权重冲突问题——输入门保护细胞状态不受无关输入的干扰,输出门则保护其他单元不受当前细胞状态中无关记忆的干扰。
LSTM成功解决了长时依赖问题,但代价是三个门 + 一个细胞状态,结构复杂、参数众多。GRU(门控循环单元)由Cho等人于2014年提出,是LSTM的一个更简单的变体。
GRU的设计目标很明确:在保持LSTM性能的同时,减少参数数量和计算复杂度。
简化一:三门→两门
GRU将LSTM中的三个门(遗忘门、输入门、输出门)合并为两个门——重置门(Reset Gate)和更新门(Update Gate) 。
具体来说,GRU把LSTM的输入门和遗忘门组合在一起,少了一个门。更新门 z 的角色相当于LSTM里的遗忘门,而 1−z 相当于LSTM中的输入门。
简化二:双状态→单状态
LSTM有两个状态向量在时间轴上传递——细胞状态 ct(长期记忆)和隐藏状态 ht(短期记忆)。
GRU将细胞状态和隐藏状态合并,只传递一个隐藏状态 ht。在GRU里,ht 的角色比较像LSTM中的 ct,可以保留得比较久。
💡 设计哲学:GRU中遗忘门和输入门是联动的——如果有新的信息进来,才会忘掉之前的信息;如果没有新信息进来,就不会忘记信息。这个逻辑比LSTM的独立三门更简洁。
Step 1:重置门和更新门
Rt=σ(XtWxr+Ht−1Whr+br)Zt=σ(XtWxz+Ht−1Whz+bz)其中 Wxr,Wxz∈Rd×h 和 Whr,Whz∈Rh×h 是权重参数。
Step 2:候选隐藏状态
H~t=tanh(XtWxh+(Rt⊙Ht−1)Whh+bh)重置门 Rt 控制着过去信息的丢弃程度:
Step 3:最终隐藏状态
Ht=Zt⊙Ht−1+(1−Zt)⊙H~t最终的隐藏状态是候选隐藏状态和前一隐藏状态的加权组合,权重由更新门控制:
LSTM的参数由3个门 + 1个候选细胞状态组成,每个都需要独立的权重矩阵:
LSTM参数量=4×(d×h+h×h+h)GRU只有2个门 + 1个候选隐藏状态:
GRU参数量=3×(d×h+h×h+h)GRU的参数量约为LSTM的 43 。
📌 实际表现:在很多时候,人们更愿意使用GRU来替换LSTM,因为GRU比LSTM少一个门,参数更少,相对容易训练且可以防止过拟合(尤其是在训练样本少的时候)。而且,GRU的性能和LSTM几乎一样。
不过需要注意的是,虽然GRU参数更少,但由于重置门的计算中并行性较低,某些情况下LSTM的执行时间反而更短。
标准的LSTM是单向的——信息只能从过去流向未来。但在很多任务中(如机器翻译、文本分类),未来的上下文同样重要。
双向LSTM(Bidirectional LSTM) 使用两个独立的LSTM层:
然后将两个方向的隐藏状态拼接起来作为最终的表示。
💡 直观理解:就像我们在做阅读理解时,不仅看前面的词,也会看后面的词来确定当前词的含义。双向LSTM让模型同时拥有了“回顾过去”和“展望未来”的能力。
典型应用场景:
堆叠LSTM(Stacked LSTM / Deep LSTM) 将多个LSTM层垂直堆叠在一起:
每一层LSTM都在不同的时间抽象层次上学习特征:
📌 实践建议:堆叠的层数足够大时,多层RNN的效果可能会比单层好。但堆叠层数增加会带来更高的计算负荷,且需要更多数据来避免过拟合。
1import torch2import torch.nn as nn3
4# ============ LSTM ============5# 单层LSTM6lstm = nn.LSTM(input_size=10, hidden_size=20, num_layers=1, batch_first=True)7
8# 双层堆叠LSTM9stacked_lstm = nn.LSTM(input_size=10, hidden_size=20, num_layers=2, batch_first=True)10
11# 双向LSTM12bidirectional_lstm = nn.LSTM(13 input_size=10,14 hidden_size=20,15 num_layers=2,16 bidirectional=True, # 开启双向17 batch_first=True18)19
20# ============ GRU ============21# 单层GRU22gru = nn.GRU(input_size=10, hidden_size=20, num_layers=1, batch_first=True)23
24# 双层堆叠GRU25stacked_gru = nn.GRU(input_size=10, hidden_size=20, num_layers=2, batch_first=True)26
27# 双向GRU28bidirectional_gru = nn.GRU(29 input_size=10,30 hidden_size=20,31 num_layers=2,32 bidirectional=True,33 batch_first=True34)35
36# ============ 前向传播示例 ============37batch_size, seq_len, input_size = 32, 50, 1038x = torch.randn(batch_size, seq_len, input_size)39
40# 双向双层LSTM41output, (h_n, c_n) = bidirectional_lstm(x)42# output: (batch_size, seq_len, hidden_size * 2) # 双向 → 2倍43# h_n: (num_layers * 2, batch_size, hidden_size)44# c_n: (num_layers * 2, batch_size, hidden_size)45
46print(f"输出形状: {output.shape}") # (32, 50, 40)47print(f"最终隐藏状态形状: {h_n.shape}") # (4, 32, 20)| 特性 | 标准RNN | LSTM | GRU |
|---|---|---|---|
| 状态数量 | 1个(ht) | 2个(ct,ht) | 1个(ht) |
| 门控数量 | 0 | 3(输入/遗忘/输出) | 2(重置/更新) |
| 参数量 | 基准 | ~4倍于RNN | ~3倍于RNN(LSTM的3/4) |
| 梯度消失 | 严重 | ✅ 极大缓解 | ✅ 极大缓解 |
| 长时依赖 | 差 | ✅ 优秀 | ✅ 优秀 |
| 计算效率 | 高 | 低 | 中等 |
| 适用场景 | 短序列 | 长序列、复杂任务 | 长序列、资源受限 |
选择建议:
LSTM和GRU的门控机制,是深度学习历史上最重要的架构创新之一。它们不仅让循环神经网络真正具备了处理长序列的能力,其设计哲学——用可学习的“门”来控制信息流动——也深刻地影响了后来的Transformer、扩散模型等现代架构。
延伸阅读:
按顺序完成这组文章,循序渐进地掌握主题
发现错误、内容过时或有改进想法?欢迎告诉我
根据本文分类与标签,为你推荐可能感兴趣的内容

系统讲解循环神经网络(RNN)的数学原理与随时间反向传播(BPTT)算法。从RNN的循环结构与共享参数出发,推导BPTT的梯度表达式,揭示梯度消失与梯度爆炸的数学根源,并介绍梯度裁剪作为应对梯度爆炸的工程解法。附带讨论LSTM如何通过门控机制缓解梯度消失。
阅读文章
系统讲解ResNet残差网络的设计哲学与数学原理:从退化问题的本质出发,推导残差块F(x)+x如何通过恒等映射直通路径缓解梯度消失,详解Bottleneck块如何将参数量减少约94%,并对比ResNet(加法融合)与DenseNet(拼接融合)的梯度流动差异。
阅读文章
系统讲解激活函数与权重初始化的协同演进关系。从Sigmoid/Tanh的梯度饱和问题出发,推导ReLU及其变体(LeakyReLU、PReLU、ELU、GELU、Swish)如何解决梯度消失,并深入推导Xavier初始化(适用于Sigmoid/Tanh)和Kaiming初始化(适用于ReLU)的方差守恒数学原理。
阅读文章请使用微信扫描二维码分享
当前文章会保持在原页面