循环神经网络(RNN)入门:从「有记忆」的神经元到 PyTorch 实战
循环神经网络(RNN)入门:从「有记忆」的神经元到 PyTorch 实战
—深度学习、RNN、循环神经网络、PyTorch、NLP、序列模型
一、开头例子:为什么普通神经网络「记不住」上一句话?
你问模型:「小赵在北京大学读书,他喜欢什么?」
人一眼就知道「他」指小赵;但普通全连接网络把每个输入独立看待,上一时刻的信息不会自动传到下一时刻。
序列数据——句子、语音、股票走势、传感器读数——关键不在单个点,而在顺序和前后关系。
循环神经网络(RNN)的核心想法很朴素:加一个「隐藏状态」当短期记忆,每读一个新输入,就结合「刚才记住了什么」再更新。
下面这张脑图里的三块——神经元内部结构 → 代码实现 → 优缺点——就是入门 RNN 最该先搞懂的一条线。
二、神经元内部结构:把时间「展开」来看
2.1 它在干什么?
可以把 RNN 想成同一个神经元在时间轴上反复工作:
- 时刻 (t) 收到输入 (x_t)
- 同时带着上一时刻的隐藏状态 (h_{t-1})(短期记忆)
- 经过激活函数,算出新的隐藏状态 (h_t),再传给下一时刻
脑图里把这条链按时间步展开(unroll),就得到:
x₁ → [A] → h₁ → [A] → h₂ → [A] → h₃
↑ ↑ ↑
h₀ h₁ h₂
绿色方框 A 里通常是 tanh(把值压到合理范围,避免数值乱飞)。
2.2 公式:两种写法,本质一样
深度学习教材版(输入和隐藏状态各有一套权重):
[
h_t = \tanh(W_{ih} x_t + b_{ih} + W_{hh} h_{t-1} + b_{hh})
]
NLP 简化版(把 (x_t) 和 (h_{t-1}) 拼起来再乘一个矩阵):
[
h_t = \tanh(W_t [x_t, h_{t-1}] + b_t)
]
| 符号 | 含义 |
|---|---|
| (x_t) | 当前时刻输入(如一个词向量) |
| (h_{t-1}) | 上一时刻隐藏状态(记忆) |
| (h_t) | 当前隐藏状态(更新后的记忆) |
| (W, b) | 可学习参数 |
人话版:新记忆 = 「当前看到什么」+ 「刚才还记得什么」,再过一个非线性变换。
2.3 图例小抄(读架构图时不迷路)
- 黄色方框:神经网络层 / 激活
- 粉色圆点:逐元素运算(加、乘)
- 箭头:向量传递
- 多条线汇成一条:拼接(concat)
- 一条线分叉:复制同一份张量
三、代码实现:PyTorch 里几行就能跑
3.1 定义 RNN 层
import torch
import torch.nn as nn
# input_size: 每个时间步输入特征维度
# hidden_size: 隐藏状态维度(记忆容量)
# num_layers: 堆叠几层 RNN
# batch_first: True 时输入形状为 (batch, seq, feature)
rnn = nn.RNN(input_size=10, hidden_size=20, num_layers=1, batch_first=True)
3.2 前向传播
batch_size, seq_len, input_size = 3, 5, 10
hidden_size = 20
# 输入:3 个样本,每个 5 个时间步,每步 10 维特征
x = torch.randn(batch_size, seq_len, input_size)
# 初始隐藏状态 h0:形状 (num_layers, batch, hidden_size)
h0 = torch.zeros(1, batch_size, hidden_size)
output, hidden = rnn(x, h0)
| 返回值 | 形状(batch_first=True) | 含义 |
|---|---|---|
output |
(batch, seq, hidden_size) |
每个时间步最后一层的输出 |
hidden |
(num_layers, batch, hidden_size) |
最后一个时间步的隐藏状态 |
小贴士:很多任务只取 output[:, -1, :](序列末尾)或 hidden[-1] 做分类;做序列标注则用每一步的 output。
3.3 和「文本预处理」怎么接?
上一篇把句子变成 词 → 索引 → Embedding 向量。接 RNN 时常见管线:
分词 → 词表索引 → nn.Embedding → nn.RNN → 全连接 → 分类/生成
Embedding 输出 (batch, seq, embed_dim),正好喂给 batch_first=True 的 RNN。
四、优缺点:简单高效,但「记性」有限
4.1 优点
| 点 | 说明 |
|---|---|
| 结构简单 | 比 LSTM、GRU 参数少,原理好懂 |
| 运算效率高 | 训练通常更快,小数据、短序列上很香 |
| 不易过拟合 | 模型相对「瘦」,有时反而更稳 |
4.2 缺点:梯度在时间里「连乘」
反向传播要沿时间步往回传梯度,相当于反复乘同一个权重矩阵:
- 乘积 > 1 → 梯度爆炸(参数更新过猛,训练发散)
- 乘积 < 1 → 梯度消失(早期时间步几乎学不到东西)
人话版:标准 RNN 像只有短期工作记忆的人——离得远的信息,很难真正「记住」。
所以实际工程里:
- 短序列、轻量任务:标准 RNN 仍可用
- 长依赖、复杂 NLP:更常用 LSTM / GRU(下一篇可展开)
- 当下主流:Transformer 用自注意力替代循环,但理解 RNN 仍是读 LSTM、读序列建模的地基
五、小结:RNN 在学什么?
- 核心:用隐藏状态 (h_t) 把过去的信息带到现在,适合序列数据。
- 结构:按时间展开;(h_t = \tanh(Wx_t + Wh_{t-1} + b)) 两种写法等价理解即可。
- 代码:
nn.RNN(input_size, hidden_size, ...)+output, hidden = rnn(x, h0)。 - 取舍:简单快,但长序列上梯度消失/爆炸是硬伤;需要「长记性」时升级 LSTM/GRU 或 Transformer。
六、下一篇预告
可以从本篇接到 「LSTM / GRU:给 RNN 装上遗忘门和更新门」,或做一个 「Embedding + RNN 文本分类」最小 demo,把「能跑」和「能说清楚」对齐。
版权声明与互动
本文为学习整理,脑图思路来自个人课程/读书笔记,公式与代码为通用写法。若有不严谨之处,欢迎在评论区指正,一起改到更对新手友好。
你目前卡在哪一步? 展开图、公式还是 output / hidden 的形状?留言里说说,后面我可以按提问多的方向续写。
更多推荐




所有评论(0)