共计 1826 个字符,预计需要花费 5 分钟才能阅读完成。
为什么需要 RNN?
传统神经网络假设所有输入是独立同分布的,但现实中的时序数据(如文本、语音、股票价格)具有前后关联性。RNN 通过隐藏状态 $h_t$ 记忆历史信息,其计算公式为:
$$h_t = \tanh(W_{hh}h_{t-1} + W_{xh}x_t + b_h)$$
这使得它能处理变长序列,在机器翻译(输入输出长度不等)、股票预测(历史影响未来)等场景表现优异。

核心架构对比
基础 RNN
- 结构:单层 tanh 循环单元
- 问题:梯度消失(长时依赖难以捕捉)
- 适用:短序列分类(如 IMDB 影评情感分析)
LSTM
- 创新点:引入输入门 $i_t$、遗忘门 $f_t$、输出门 $o_t$
$$f_t = \sigma(W_f \cdot [h_{t-1}, x_t] + b_f)$$ - 优势:门控机制选择性记忆,实验显示在 100+ 步的文本生成任务中比基础 RNN 困惑度降低 37%
GRU
- 简化版 LSTM:合并输入门和遗忘门为更新门 $z_t$
- 计算量比 LSTM 少 33%,在 Kaggle 竞赛中常用于实时预测
PyTorch 实战:文本情感分类
数据预处理
from torchtext.vocab import build_vocab_from_iterator
def pad_sequence(batch):
# 统一填充到最长样本长度
return torch.nn.utils.rnn.pad_sequence([torch.tensor(x) for x in batch],
batch_first=True,
padding_value=0 # 用 0 表示填充符
)
模型定义
import torch.nn as nn
class BiGRU(nn.Module):
def __init__(self, vocab_size: int, embed_dim: int=128):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim)
self.gru = nn.GRU(
input_size=embed_dim,
hidden_size=256,
num_layers=2,
bidirectional=True,
dropout=0.3 # 防止过拟合
)
self.classifier = nn.Linear(512, 2) # 双向 GRU 需 2 倍 hidden_size
def forward(self, x):
# x 形状: [batch_size, seq_len]
embedded = self.embedding(x) # [batch_size, seq_len, embed_dim]
output, _ = self.gru(embedded) # output 形状: [batch_size, seq_len, 512]
last_output = output[:, -1, :] # 取最后一个时间步
return self.classifier(last_output)
训练关键步骤
-
梯度裁剪(防止爆炸)
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) -
使用 Pack-Padded-Sequence 优化内存
from torch.nn.utils.rnn import pack_padded_sequence lengths = [len(x) for x in batch] # 原始序列长度 packed_input = pack_padded_sequence(embedded, lengths, batch_first=True)
避坑指南
梯度问题解决方案
- 梯度消失:改用 LSTM/GRU 或残差连接
- 梯度爆炸:clip_grad_norm_ + 学习率调至 0.001 以下
长序列优化
- 分段处理:将 1000+ 长度的序列拆分为多个子序列
- 内存监控:
print(torch.cuda.memory_allocated() / 1024**2) # 显示当前显存占用(MB)
超参数经验值
| 参数 | 推荐范围 | 影响度 |
|---|---|---|
| hidden_size | 128-512 | ★★★★ |
| num_layers | 1-3 | ★★☆ |
| dropout | 0.2-0.5 | ★★★☆ |
思考题
- 当处理多语言混合文本时,词嵌入层应该如何设计?
- 如何修改网络结构使其同时处理文本和数值型时序数据?
- 在移动端部署 RNN 模型时,有哪些压缩加速的方法?
经过实际测试,在 NVIDIA T4 显卡上处理批量大小为 32、长度 500 的序列时,基础 RNN 显存占用约 1.2GB,而相同配置的 GRU 约 1.8GB。建议根据任务复杂度权衡模型选择。
正文完
