4、循环神经网络(RNN)与序列模型
序列数据,说白了就是有前后顺序的数据。文本、语音、股票价格、视频帧,都属于这一类。我刚开始接触深度学习时,用全连接网络去处理文本,结果一塌糊涂。后来才明白——顺序本身就是信息。
这一章,我们聊聊RNN家族。从最基础的RNN,到LSTM、GRU,再到注意力机制和Seq2Seq。嗯,内容不少,但都是干货。
4.1 RNN:最简单的循环结构
RNN的核心思想很简单:让网络有记忆。每次处理一个输入时,不仅看当前数据,还参考上一个时间步的隐藏状态。
公式其实就两行:
h_t = tanh(W_h * x_t + U_h * h_{t-1} + b_h)
y_t = softmax(W_y * h_t + b_y)
你看,h_t 既依赖当前输入 x_t,也依赖上一个隐藏状态 h_{t-1}。这就是「循环」二字的由来。
关键理解:RNN的隐藏状态相当于一个「信息压缩袋」。它把前面所有时间步的信息压缩成一个向量,传给下一步。但这个袋子容量有限,装太多就会漏。
我在项目中遇到过一个问题:用RNN做情感分类,短句子效果很好,但长文本就崩了。为什么?因为梯度消失了。这就是RNN的硬伤——长距离依赖问题。
避坑指南:我曾经在训练一个50层的RNN时,发现梯度几乎为0。后来改用LSTM,问题才解决。记住:RNN不适合处理超过20步的序列。别硬撑。
4.2 LSTM:长短期记忆网络
LSTM是RNN的升级版。它引入了「门控机制」,说白了就是给网络加了个「记忆管理器」。
LSTM有三个门:
- 遗忘门:决定丢掉哪些旧信息
- 输入门:决定存入哪些新信息
- 输出门:决定输出哪些信息
公式稍微复杂一点,但核心思想就一句话:让网络学会什么时候该记,什么时候该忘。
f_t = sigmoid(W_f * [h_{t-1}, x_t] + b_f) # 遗忘门
i_t = sigmoid(W_i * [h_{t-1}, x_t] + b_i) # 输入门
o_t = sigmoid(W_o * [h_{t-1}, x_t] + b_o) # 输出门
c_t = f_t * c_{t-1} + i_t * tanh(W_c * [h_{t-1}, x_t] + b_c) # 细胞状态
h_t = o_t * tanh(c_t) # 隐藏状态
你想想看,这个结构为什么能解决梯度消失?因为细胞状态 c_t 有一条「高速公路」——遗忘门可以控制信息直接流过,梯度也能顺畅回传。
个人经验:我习惯把LSTM的隐藏状态维度设为128或256。太小了记不住,太大了容易过拟合。当然,具体要看你的数据量。
4.3 GRU:更轻量的选择
GRU是LSTM的简化版。它把遗忘门和输入门合并成一个「更新门」,还去掉了细胞状态。参数更少,训练更快。
公式:
z_t = sigmoid(W_z * [h_{t-1}, x_t]) # 更新门
r_t = sigmoid(W_r * [h_{t-1}, x_t]) # 重置门
h_t = (1 - z_t) * h_{t-1} + z_t * tanh(W_h * [r_t * h_{t-1}, x_t])
我个人觉得,GRU在大多数任务上效果和LSTM差不多,但训练速度快20%左右。如果你的数据量不大,或者计算资源有限,GRU是个好选择。
| 模型 | 参数量 | 训练速度 | 长序列效果 | 适用场景 |
|---|---|---|---|---|
| RNN | 少 | 快 | 差 | 短序列、简单任务 |
| LSTM | 多 | 慢 | 好 | 长序列、复杂任务 |
| GRU | 中 | 中 | 较好 | 中等长度、资源有限 |
4.4 序列预测与文本生成
序列预测,说白了就是「根据历史预测未来」。股票价格预测、天气预测、语言模型,都属于这个范畴。
文本生成是序列预测的一个特例。给定前面的词,预测下一个词。训练时用交叉熵损失,推理时用贪心搜索或束搜索。
我做过一个项目:用LSTM生成古诗。训练数据是唐诗三百首,模型学会了平仄和押韵。但生成的诗嘛……嗯,只能说「形似神不似」。后来加了注意力机制,效果才好一些。
核心要点:文本生成时,temperature 参数很关键。温度越高,生成越随机;温度越低,生成越保守。我一般设0.8,既有创意又不至于胡言乱语。
4.5 注意力机制入门
注意力机制,是近年来深度学习最重要的突破之一。它的核心思想:让模型学会「关注」输入中的关键部分。
举个例子:翻译句子「I love you」时,生成「我」这个字时,模型应该重点关注「I」;生成「爱」时,重点关注「love」。这就是注意力。
注意力计算分三步:
- 计算相似度:用点积或加性注意力,计算查询和键的匹配程度
- 归一化:用softmax把相似度转成概率分布
- 加权求和:用概率分布对值进行加权求和
公式:
Attention(Q, K, V) = softmax(Q * K^T / sqrt(d_k)) * V
这个 sqrt(d_k) 是缩放因子。为什么要缩放?因为点积结果会随着维度增大而变大,softmax会变得很「尖锐」,梯度容易消失。这个小细节,我在调参时踩过坑。
我曾经犯过的错:在实现注意力机制时,忘了加 sqrt(d_k) 缩放。结果训练时loss死活降不下去。查了两天bug才发现。嗯,细节决定成败。
4.6 Seq2Seq模型
Seq2Seq,全称Sequence-to-Sequence,就是「序列到序列」的映射。机器翻译、文本摘要、语音识别,都是它的应用场景。
结构很简单:一个编码器 + 一个解码器。
- 编码器:把输入序列编码成一个上下文向量
- 解码器:根据上下文向量,逐步生成输出序列
早期的Seq2Seq有个问题:编码器必须把整个输入压缩成一个固定长度的向量。输入长了,信息就丢了。后来加入了注意力机制,解码器每一步都能「回头看」编码器的所有隐藏状态,效果大幅提升。
我建议你从最简单的Seq2Seq开始实现:用LSTM做编码器和解码器,不加注意力。跑通之后,再加注意力机制。这样你能清楚感受到注意力带来的提升。
实现建议:训练Seq2Seq时,用Teacher Forcing可以加速收敛。但推理时一定要用自回归方式,否则模型会「学歪」。
知识体系总览
下面这张图,概括了本章的核心内容。我建议你把它存下来,复习时对照着看。
这一章的内容,是后续Transformer和大型语言模型的基础。RNN虽然现在用得少了,但它的思想——循环、记忆、门控——深深影响了后续所有序列模型。理解透彻了,后面学Transformer会轻松很多。
一句话总结:RNN让网络有了记忆,LSTM让记忆更持久,注意力让记忆更精准。三者层层递进,构成了序列建模的基石。
公众号:蓝海资料掘金营,微信deep3321