共计 2319 个字符,预计需要花费 6 分钟才能阅读完成。
序列数据建模的挑战
时序数据(如文本、语音、传感器读数)具有两个核心特性:
1. 动态长度:序列长度可变,需要模型能处理任意长度的输入
2. 前后依赖:当前时刻的数据与历史状态密切相关

传统全连接网络无法满足这些需求,而循环神经网络(RNN)通过隐藏状态 $h_t$ 传递历史信息:
$$h_t = \tanh(W_{xh}x_t + W_{hh}h_{t-1} + b_h)$$
RNN 的固有缺陷
梯度消失问题
通过链式法则展开参数梯度:
$$\frac{\partial h_t}{\partial h_{t-1}} = W_{hh}^T \cdot \text{diag}(1 – \tanh^2(z_{t-1}))$$
当 $W_{hh}$ 的特征值小于 1 时,梯度会指数级衰减,导致长程依赖难以学习。
实验验证
在 MNIST 像素序列分类任务中(将 28×28 图像视为 28 个时间步的 28 维向量):
# 基础 RNN 实现
class VanillaRNN(nn.Module):
def __init__(self, input_size, hidden_size, num_classes):
super().__init__()
self.rnn = nn.RNN(input_size, hidden_size, batch_first=True)
self.fc = nn.Linear(hidden_size, num_classes)
def forward(self, x):
# x shape: (batch, seq_len, input_size)
out, _ = self.rnn(x) # 取最后一个时间步输出
return self.fc(out[:, -1, :])
测试结果显示,RNN 在测试集准确率仅达到 85.3%,远低于 CNN 的 99%+ 表现。
LSTM 的结构创新
长短期记忆网络(LSTM)通过三个门控单元解决梯度问题:
核心组件数学表达
-
遗忘门 控制历史信息保留程度:
$$f_t = \sigma(W_f \cdot [h_{t-1}, x_t] + b_f)$$ -
输入门 调节新信息存储:
$$
\begin{aligned}
i_t &= \sigma(W_i \cdot [h_{t-1}, x_t] + b_i) \
\tilde{C}t &= \tanh(W_C \cdot [h, x_t] + b_C)
\end{aligned}
$$ -
细胞状态更新:
$$C_t = f_t \odot C_{t-1} + i_t \odot \tilde{C}_t$$ -
输出门 决定最终输出:
$$
\begin{aligned}
o_t &= \sigma(W_o \cdot [h_{t-1}, x_t] + b_o) \
h_t &= o_t \odot \tanh(C_t)
\end{aligned}
$$
PyTorch 实现关键
class LSTMModel(nn.Module):
def __init__(self, input_size, hidden_size, num_classes):
super().__init__()
self.lstm = nn.LSTM(input_size, hidden_size, batch_first=True)
self.fc = nn.Linear(hidden_size, num_classes)
def forward(self, x):
# 初始化隐藏状态(PyTorch 会自动处理)out, (h_n, c_n) = self.lstm(x)
return self.fc(out[:, -1, :])
实战优化策略
梯度裁剪
防止梯度爆炸的必备操作:
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
序列填充处理
变长序列需统一长度:
from torch.nn.utils.rnn import pad_sequence
padded_sequences = pad_sequence(sequences, batch_first=True)
参数初始化
LSTM 的 forget gate 偏置建议初始化为 1:
for name, param in model.named_parameters():
if 'bias' in name and 'lstm' in name:
nn.init.constant_(param[:hidden_size], 1.0)
性能对比实验
| 模型 | 测试准确率 | 训练时间(epoch=10) |
|---|---|---|
| Vanilla RNN | 85.3% | 2m13s |
| LSTM | 98.7% | 3m47s |
延伸思考:注意力机制融合
可将 LSTM 的隐藏状态序列作为 Key 和 Value,通过以下方式增强模型:
1. 时间步注意力:计算每个时间步的重要性权重
2. 多头注意力:并行多个注意力头捕获不同特征
3. 位置编码:弥补 LSTM 在绝对位置感知上的不足
实现框架建议:
class AttnLSTM(nn.Module):
def __init__(self, input_size, hidden_size):
super().__init__()
self.lstm = nn.LSTM(input_size, hidden_size, bidirectional=True)
self.attn = nn.MultiheadAttention(2*hidden_size, num_heads=4)
def forward(self, x):
lstm_out, _ = self.lstm(x) # (seq_len, batch, 2*hidden)
attn_out, _ = self.attn(lstm_out, lstm_out, lstm_out)
return attn_out
总结建议
- 短序列任务可使用 GRU(LSTM 的轻量版)
- 超长序列(>1000 步)建议尝试 Transformer
- 工业级应用需结合量化剪枝优化推理速度
