RNN 的模型结构
1 课程概览
本课详细讲解传统 RNN 的内部结构、API 参数和优缺点。每个时间步有两个输入(本次输入 $X_t$ 和上一时刻隐藏状态 $H_{t-1}$)和两个输出(本次隐藏状态 $H_t$ 和本次输出 $Y_t$)。对比学术界和工业界(PyTorch)的实现差异。
2 核心概念与定义
- 神经网络层(Neural Network Layer):进行加权求和和非线性变换的层。
- 逐点运算(Pointwise Operation):逐个元素的运算,如点乘或矩阵乘法。
- 向量传输(Vector Transfer):向量在层之间的传递。
- 连接(Connection):将两个向量合并。
- 复制(Copy):将一个向量复制为两份。
- tanh 激活函数:双曲正切函数,输出范围 $[-1, 1]$。
3 模型与算法详解
RNN 内部结构图解
H(t-1) X(t)
| |
|____[连接]____|
|
[加权求和]
|
[tanh 激活]
|
[复制]
/ \
H(t) Y(t)
每个时间步的输入输出
| 类型 | 输入 | 输出 |
|---|---|---|
| 输入 | $X_t$(本次输入) | $H_t$(本次隐藏状态) |
| 输入 | $H_{t-1}$(上一时刻隐藏状态) | $Y_t$(本次输出) |
结构元素说明
| 元素 | 含义 |
|---|---|
| 黄色方块 | 神经网络层(加权求和 + 激活函数) |
| 粉色圆圈 | 逐点运算(点乘/矩阵乘法) |
| 箭头 | 向量传输 |
| 合并符号 | 连接(合并两个向量) |
| 分叉符号 | 复制(一变二) |
学术界 vs 工业界实现
| 对比项 | 学术界(论文) | 工业界(PyTorch) |
|---|---|---|
| 权重矩阵 | 共用一个 $W$ | 分开:$W_{ih}$(输入)和 $W_{hh}$(隐藏) |
| 公式 | $H_t = \tanh(W [H_{t-1}, X_t])$ | $H_t = \tanh(W_{ih} X_t + W_{hh} H_{t-1})$ |
| 运算量 | 较小 | 较大 |
| 本质 | 相同 | 相同 |
RNN 优缺点
| 优点 | 缺点 |
|---|---|
| 结构简单 | 存在梯度消失/梯度爆炸问题 |
| 适合短序列 | 难以捕捉长距离依赖 |
4 数学原理与推导
学术界公式(共用权重矩阵)
$$H_t = \tanh(W [H_{t-1}, X_t] + b)$$
其中 $[H_{t-1}, X_t]$ 表示两个向量的拼接。
工业界公式(PyTorch 实现)
$$H_t = \tanh(W_{ih} X_t + W_{hh} H_{t-1} + b)$$
其中:
- $W_{ih}$:输入权重矩阵
- $W_{hh}$:隐藏状态权重矩阵
- $b$:偏置
输出公式
$$Y_t = W_{ho} H_t + b_o$$
tanh 激活函数
$$\tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}$$
输出范围:$[-1, 1]$
5 代码示例
import torch
import torch.nn as nn
# 查看 PyTorch RNN 源码
rnn = nn.RNN(input_size=100, hidden_size=20, num_layers=1)
# 按住 Ctrl 点击 nn.RNN 可查看源码
# 源码中的数学公式:
# h_t = tanh(W_ih * x_t + b_ih + W_hh * h_(t-1) + b_hh)
# RNN 基本使用
# 输入:(seq_len, batch, input_size)
# h0:(num_layers, batch, hidden_size)
# 输出:(seq_len, batch, hidden_size)
# hn:(num_layers, batch, hidden_size)
input_size = 100
hidden_size = 20
seq_len = 5
batch_size = 3
rnn = nn.RNN(input_size, hidden_size)
# 随机生成输入
x = torch.randn(seq_len, batch_size, input_size)
h0 = torch.zeros(1, batch_size, hidden_size)
# 前向传播
output, hn = rnn(x, h0)
print("输出形状:", output.shape) # (5, 3, 20)
print("隐藏状态形状:", hn.shape) # (1, 3, 20)
6 重难点与易错提醒
- ❗重点:每个时间步有 2 个输入($X_t$, $H_{t-1}$)和 2 个输出($H_t$, $Y_t$)。
- ❗重点:学术界共用权重矩阵,工业界(PyTorch)分开使用 $W_{ih}$ 和 $W_{hh}$。
- ⚠️易错:RNN 展开后不是多个神经元,而是一个神经元循环工作。
- 💡深入理解:tanh 激活函数增加非线性因素,输出范围 $[-1, 1]$。
- 💡深入理解:RNN 存在梯度消失/梯度爆炸问题,LSTM 和 GRU 是其改进。
7 课堂问答精选
Q1:RNN 每个时间步的输入和输出是什么?
A:输入 2 个:$X_t$(本次输入)和 $H_{t-1}$(上一时刻隐藏状态)。输出 2 个:$H_t$(本次隐藏状态)和 $Y_t$(本次输出)。
Q2:学术界和工业界的 RNN 实现有何区别?
A:学术界共用一个权重矩阵 $W$,公式为 $H_t = \tanh(W [H_{t-1}, X_t])$。工业界(PyTorch)分开使用 $W_{ih}$ 和 $W_{hh}$,公式为 $H_t = \tanh(W_{ih} X_t + W_{hh} H_{t-1})$。本质相同,但工业界运算量更大。
Q3:RNN 内部结构有哪些元素?
A:①神经网络层(加权求和 + 激活函数);②逐点运算(点乘/矩阵乘法);③向量传输;④连接(合并);⑤复制(一变二)。
Q4:RNN 有什么优缺点?
A:优点:结构简单,适合短序列。缺点:存在梯度消失/梯度爆炸问题,难以捕捉长距离依赖。
8 本课小结
- 每个时间步:2 输入($X_t$, $H_{t-1}$)→ 2 输出($H_t$, $Y_t$)。
- 激活函数:tanh,输出范围 $[-1, 1]$。
- 学术界:共用权重矩阵 $W$。
- 工业界(PyTorch):分开 $W_{ih}$ 和 $W_{hh}$。
- 优缺点:结构简单,但有梯度消失/爆炸问题。
9 延伸思考
- 为什么 RNN 会出现梯度消失/梯度爆炸?
- LSTM 如何通过门机制解决梯度消失问题?