深度学习经典:如何正确地为 LSTM 加上 Dropout?

37 阅读2分钟

在深度学习的发展史上,Dropout 被认为是解决神经网络过拟合最有效的“神技”之一。然而,早期的研究发现,直接将 Dropout 应用于循环神经网络(RNN)和长短期记忆网络(LSTM)时,模型效果不升反降。

由 Wojciech Zaremba、Ilya Sutskever 和 Oriol Vinyals 撰写的这篇 ICLR 2015 论文,为这一难题提供了一个优雅且极具影响力的解决方案。


1. 论文核心:为什么传统 Dropout 对 RNN 无效?

RNN 的核心能力在于长程依赖(Long-term dependencies) ,即通过时间步传递信息来“记忆”过去的状态。

  • 噪声放大效应:如果在递归连接(即 t1t-1 时刻到 tt 时刻的连接)上应用 Dropout,每一时刻都会随机丢弃信息。
  • 记忆受损:随着时间步的增加,这种随机噪声会被不断放大,最终彻底破坏模型存储长期信息的能力,导致模型无法学习长序列任务。

2. 创新点:非递归连接 Dropout (Non-recurrent Dropout)

论文提出了一个极其简单但深邃的改进:只在非递归连接上应用 Dropout

关键技术逻辑

  • 纵向(Vertical)应用:Dropout 仅应用于多层 LSTM 中层与层之间的信息传递(即从 l1l-1 层到 ll 层)。
  • 横向(Horizontal)保留:在同一层内,随时间流动的递归连接(从 t1t-1 时刻到 tt 时刻)保持完整,不使用 Dropout。
  • 确定性噪声:这样一来,信息被 Dropout 算子“破坏”的次数固定为 L+1L+1 次(LL 为层数),且与序列长度无关 。这让模型在获得正则化收益的同时,能够像往常一样学习长距离信息 。

数学表达

在论文设计的 LSTM 单元中,其门控机制公式如下,注意 Dropout 算子 DD 的位置 :

(ifog)=(sigmsigmsigmtanh)T2n,4n(D(htl1)ht1l)\begin{pmatrix} i \\ f \\ o \\ g \end{pmatrix} = \begin{pmatrix} sigm \\ sigm \\ sigm \\ tanh \end{pmatrix} T_{2n, 4n} \begin{pmatrix} D(h_{t}^{l-1}) \\ h_{t-1}^{l} \end{pmatrix}

其中,htl1h_{t}^{l-1}(来自前一层的输入)被应用了 Dropout,而 ht1lh_{t-1}^{l}(来自前一时间步的状态)则没有。


3. 实际应用场景

该技术在多种涉及序列数据的复杂任务中展现了显著的泛化提升:

  • 语言建模 (Language Modeling) :在 Penn Tree Bank (PTB) 数据集上,大型正则化 LSTM 将测试集困惑度(Perplexity)从 114.5 大幅降至 78.4
  • 机器翻译 (Machine Translation) :在 WMT'14 英法翻译任务中,将 BLEU 分数从 25.9 提升至 29.03
  • 语音识别 (Speech Recognition) :提高了冰岛语小规模数据集的帧准确率,有效缓解了在小数据量上的严重过拟合 。
  • 图像描述生成 (Image Captioning) :利用 Dropout 训练的单个模型,性能即可达到 10 个非正则化模型集成的水平 。

4. 最小可运行 Demo (PyTorch)

在现代 PyTorch 中,nn.LSTMdropout 参数已经默认实现了这篇论文的逻辑:Dropout 仅作用于除最后一层外的层间输出,而不作用于递归连接。

Python

import torch
import torch.nn as nn

# 定义一个符合论文精神的多层递归模型
class RegularizedLSTM(nn.Module):
    def __init__(self, vocab_size, embedding_dim, hidden_dim, n_layers, dropout_prob):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embedding_dim)
        
        # 关键:num_layers > 1 且 dropout > 0 
        # PyTorch 会自动在层间应用 dropout (Non-recurrent)
        self.lstm = nn.LSTM(embedding_dim, hidden_dim, n_layers, 
                            dropout=dropout_prob, batch_first=True)
        
        self.fc = nn.Linear(hidden_dim, vocab_size)

    def forward(self, x, hidden):
        embeds = self.embedding(x)
        # lstm_out 包含了 dropout 后的层间特征
        lstm_out, hidden = self.lstm(embeds, hidden)
        logits = self.fc(lstm_out)
        return logits, hidden

# 参数配置参考论文 Medium 模型 [cite: 185, 186]
model = RegularizedLSTM(vocab_size=10000, embedding_dim=650, 
                        hidden_dim=650, n_layers=2, dropout_prob=0.5)

# 模拟训练模式
model.train() 
inputs = torch.randint(0, 10000, (20, 35)) # Batch=20, Seq_len=35 [cite: 129]
logits, _ = model(inputs, None)

print(f"输出形状: {logits.shape}") # (20, 35, 10000)

结语

Zaremba 等人的这项研究不仅为 RNN 提供了有效的正则化工具,更深刻地揭示了递归结构与噪声干扰之间的平衡 。直到今天,这一原则在设计复杂的序列模型时依然具有参考价值。