Dropout 是深度学习中最经典、最有效的正则化技术之一。它的核心思想非常巧妙:在训练时随机"丢弃"一部分神经元,迫使网络不过度依赖某些特定的神经元组合,从而学习到更鲁棒、更通用的特征。
要理解 Dropout 的正则化效果,可以从以下几个角度来剖析:
这是 Dropout 最直观的动机(来自 Hinton 的原始论文)。
在标准的全连接网络中,神经元之间可能会形成一种"共谋"关系:某个神经元专门负责修正另一个神经元的错误,两者高度依赖,只对训练集有效,对测试集无效。
引入 Dropout 后,每次前向传播都相当于从一个大的网络中随机采样出一个子网络。由于每个神经元在训练时都有可能被随机丢掉,它们就不能依赖特定的"搭档",而必须学会独立地从输入中提取有用的特征。这迫使每个神经元都变得更"全能"。
这是目前解释 Dropout 效果最主流的理论视角。
假设网络有 $n$ 个神经元,加上 Dropout 后,每一次训练迭代实际上都在训练一个不同的、更稀疏的子网络(相当于训练了 $2^n$ 个可能的子模型)。
Dropout 可以看作是一种在特征层面注入乘性噪声的方式。每次训练时,输入经过该层后,某些值会被强制设为 0。
这迫使网络学会如何在信息不完整、有缺失的情况下仍然做出正确的判断,从而提高模型的鲁棒性。这类似于数据增强,只不过 Dropout 是在特征空间(隐层)而不是输入空间做增强。
这是使用 Dropout 时最容易出错、也最需要理解的地方。Dropout 是一种只在训练阶段激活的技术。
| 阶段 | Dropout 状态 | 操作 | 目的 |
|---|---|---|---|
| 训练阶段 | 开启 | 以概率 $p$ 随机将神经元输出设为 0;剩余神经元的输出除以 $(1-p)$(详见下文缩放规则)。 | 随机采样子网络,注入噪声,强制学习鲁棒特征,防止过拟合。 |
| 推理/测试阶段 | 关闭 | 所有神经元都参与计算,不需要随机丢弃,也不需要缩放。 | 使用完整的训练好的网络,利用所有特征进行预测,保证结果的确定性和精度。 |
在推理时,我们必须对权重进行缩放(Scale),以弥补训练时部分神经元被丢弃导致的输出期望变化。业界通常有两种实现方式,不能混淆:
原因:训练时由于做了除以 $(1-p)$,使得该层输出的总体期望值(Magnitude)与没有 Dropout 时保持一致。因此,推理时无需任何额外操作,权重可以直接复用。
Vanilla Dropout(原始实现)
总结:现代框架(如 PyTorch 的
nn.Dropout)默认使用 Inverted Dropout。因此,你只需在模型定义中加上 Dropout 层,框架会自动处理训练和推理的切换,不需要在model.eval()时手动修改权重。
在 PyTorch 中,切换模式由 model.train() 和 model.eval() 控制。
import torch
import torch.nn as nn
# 定义:丢弃概率为 50%(p=0.5)
dropout = nn.Dropout(p=0.5)
# 输入示例
x = torch.ones(10) # 全 1 向量
# 1. 训练阶段(默认是 train 模式)
dropout.train()
y_train = dropout(x)
print("训练阶段输出:\n", y_train)
# 预期现象:
# 一部分值变为 0(被丢弃),
# 另一部分值变为 2(因为 Inverted Dropout 除以了 1-p=0.5)
# 2. 推理阶段(切换为 eval 模式)
dropout.eval()
y_eval = dropout(x)
print("推理阶段输出:\n", y_eval)
# 预期现象:
# 输出全部为原来的 1,不做任何改变
ReLU -> Dropout)。SpatialDropout 或 DropBlock。Transformer 架构(如 BERT、GPT)中,Dropout 被广泛应用于注意力权重、残差连接和 FFN 层。
概率 $p$ 的选择:
大模型欠拟合时:如果模型本身还不够拟合训练集(欠拟合),建议先调小 Dropout(如 0.1)或不使用;如果是过拟合,再调大。
训练时间: Dropout 会导致网络收敛变慢(因为每次只更新了部分神经元,且噪声大)。通常需要增加 epoch 数来弥补。
评论专区
评论加载中...登录后即可发表评论