序列建模与循环神经网络 RNN
循环神经网络(Recurrent Neural Network, RNN)用一个跨时间步共享参数的隐状态 h_t 压缩历史信息——h_t = φ(W_h h_{t-1} + W_x x_t + b)——使同一套权重能处理任意长度的序列。
一句话定义
循环神经网络(Recurrent Neural Network, RNN)用一个跨时间步共享参数的隐状态 h_t 压缩历史信息——h_t = φ(W_h h_{t-1} + W_x x_t + b)——使同一套权重能处理任意长度的序列。
直觉
RNN 像「读长文做摘要的人」:每读一个词,脑子(隐状态)就更新一次对全文的理解;读到句尾时,脑子里的状态已浓缩了整段历史——只是这个「脑子」容量有限(固定维向量),词一多就记不住开头的伏笔。
为什么重要
文本、语音、股价、传感器读数都是变长序列,CNN 的固定结构先验不适用,需要「参数共享沿时间轴」的新机制。RNN 是这条路线的原点:kp-023 的 LSTM/GRU、kp-025 的截断训练、乃至 kp-026 的注意力(最初为改进 RNN 编码器而生),全部是围绕它缺陷的修补史。理解 RNN 的机制与病根,才能理解后续每一步「为什么要改」。
前置知识
- kp-007(梯度回传——RNN 是它沿时间的展开)、kp-005(共享权重的层结构)。
核心概念
- 隐状态(hidden state) h_t:序列到当前步为止的信息压缩摘要。
- 时间展开(unrolling):把循环按时间步展开成深网络,参数跨层共享。
- 共享参数:W_h、W_x 在所有时间步复用——「同一套语法规则用于任何位置」。
- 序列到序列形态:一对多(图像描述)、多对一(情感分类)、多对多(词性标注、翻译)。
- BPTT(沿时间反向传播):展开图上做普通反向传播(细节在 kp-025)。
原理与机制
单步方程:h_t = φ(W_h h_{t-1} + W_x x_t + b)。三个机制要点。其一,参数共享与变长能力:无论序列 10 步还是 1000 步,权重只有一份——这与 CNN 的空间共享(kp-017)同构,是「时间轴上的参数共享」。其二,隐状态的马尔可夫式压缩:h_t 只直接依赖 h_{t-1} 与 x_t,全部历史经递归链隐式传递;信息要活过 T 步就得在递归链上「存活」T 次——这正是 kp-023 长程依赖难题的结构根源。其三,沿时间展开后,RNN 就是一张很深的共享权重网络:梯度既沿层回传也沿时间回传,梯度消失/爆炸在时间维度上被指数放大(T 步链式相乘),50 步以外梯度常衰减到 1e−5 量级以下——模型「记不住」的本质是「学不到」(梯度到不了远方)。展开视角还解释了输入/输出的多种对齐形态:只要在对应时间步接入输入或读出输出,同一套方程即可支持分类(末步读出)、生成(输出作下一步输入)等任务。RNN 的现代地位:在自然语言的生成主干上已被注意力架构(kp-026 之后的发展,指路 Transformer 站点)取代,但它仍是时序传感器、轻量嵌入式序列任务与「理解注意力为何胜出」的必修对照组。
公式或模型
RNN 单步方程与多对一分类读出:
h_t = φ( W_h h_{t-1} + W_x x_t + b ) h_0 初始化为零向量
ŷ = softmax( W_o h_T + b_o ) (多对一:末状态读出)变量说明:x_t 为 t 步输入向量,h_t ∈ R^d 为隐状态,W_h 为跨步转移矩阵(重复使用 T 次),W_x 为输入映射。梯度沿时间的连乘因子正是 W_h 的幂:W_h^T——其谱半径决定记忆寿命(kp-023 展开)。
图示
y_1 y_2 y_3 y_4 (按需读出)
▲ ▲ ▲ ▲
[O] [O] [O] [O]
▲ ▲ ▲ ▲
h_0 ►[A]──► [A]──► [A]──► [A]──► h_4 (同一个 A:参数共享)
▲ ▲ ▲ ▲
x_1 x_2 x_3 x_4 (时间展开图)
[A] = h_t = φ(W_h h_{t-1} + W_x x_t + b)直观类比
隐状态像「游戏中角色的内存条」:每帧(时间步)用最新事件覆盖更新一次——近期事件清晰、久远事件不断被冲淡;W_h^T 的谱半径就是「内存条的保质期」。
实例或案例
字符级语言模型的最小实现(kp-024 将给出其损失与评估口径):
class TinyRNN(nn.Module):
def __init__(self, vocab, d=64):
super().__init__()
self.emb = nn.Embedding(vocab, d)
self.rnn = nn.RNN(d, d, batch_first=True)
self.out = nn.Linear(d, vocab)
def forward(self, x, h=None):
e, h = self.rnn(self.emb(x), h) # 循环内部即本节方程
return self.out(e), h在莎士比亚文本上训练后采样文本:前 30 个字符连贯、越往后越语无伦次——「短期像样、长期失忆」正是朴素 RNN 的签名症状,也是 kp-023 门控改进的出发点。
常见误区
- 「RNN 每个时间步有一套独立参数」:恰恰相反,全程共享一份 W_h/W_x,这正是它能处理变长序列的原因。
- 「隐状态存储了完整历史」:它是固定维压缩,本质有损;长程信息能否保留取决于梯度能否教会它(kp-023)。
- 「RNN 已完全无用」:作为概念基线与轻量时序方案仍有价值;学习它的最大意义是理解注意力改良的对象。
- 混淆 h_t 的「深度」(层间)与「时间」(步间):展开图上二者都是回传方向,但参数只有一份。
与其他知识点的关系
kp-023 治其梯度病、kp-025 讲其训练工程(截断与裁剪)、kp-024 提供其文本任务的表示层与损失;kp-026 的注意力最初作为 RNN 编码-解码的补充出现;kp-007 的时间展开版本就是本节。
自测题
- 写出 RNN 单步方程,指出哪部分实现了「参数共享」。
答案要点:W_h/W_x/b 全时间步复用;h_t=φ(W_h h_{t-1}+W_x x_t+b)。
- 为什么朴素 RNN 难以记住 100 步之前的信息?
答案要点:梯度沿时间连乘 W_h 与 φ',谱半径偏离 1 时指数消失/爆炸,远方梯度到不了(kp-023 量化)。
- 多对一分类在 RNN 中如何实现读出?
答案要点:取末时间步 h_T 经线性层+softmax 输出类别。
延伸阅读
- Elman《Finding Structure in Time» Cognitive Science 1990(RNN 作为认知模型的开山作)。
- Goodfellow 等《Deep Learning》第 10 章「序列建模:循环和递归网络」。
学习状态
状态保存在浏览器本地,用于首页与路径页的进度统计。