第 12 天 · 每次随机丢掉一半神经元,反而学得更好
一句话
Dropout 在训练时以概率 1 − p 临时删除神经元,测试时保留全部神经元并按保留概率缩放权重。这近似于对 2^n 个共享权重的子网络做模型平均,在视觉、语音、文本、生物数据上都显著减少了过拟合。
论文讲了什么
结论先行:训练时让每个神经元以概率 1 − p 临时“消失”,测试时用全部神经元并把权重乘以 p。这个做法近似于训练并平均 2^n 个子网络,几乎不增加成本,却能大幅减少过拟合。
问题。大网络参数多,容易记住训练集。模型集成(ensemble)能缓解过拟合,但大网络训练一个就很贵,推理时再跑多个更贵。作者还指出一个微观原因:神经元之间会形成共适应(co-adaptation),某个神经元只有在特定伙伴存在时才有用,换一批数据就失效。
方法。
- 训练:对每个单元采样一个掩码
r ~ Bernoulli(p),输出变成y = r * a。p 是保留概率。每个样本、每次迭代都重新采样,等于每次从 2^n 个子网络里抽一个来训练,所有子网络共享同一套权重。 - 测试:不再丢弃,而是把权重乘以 p,使每个单元的输出期望和训练时一致。作者称之为权重缩放推断规则。他们用蒙特卡洛方法检验过:随机采样约 50 个子网络取平均,效果和权重缩放相当。
- 推荐设置:隐层 p = 0.5,实数输入层 p = 0.8。配合最大范数(max-norm)约束,限制每个单元输入权重的 L2 范数,再用大学习率和高动量。
- 动机类比:有性繁殖。每个基因都要和随机的其他基因组合,所以单个基因必须自己有用。dropout 迫使每个神经元在随机伙伴下也有用。
- 扩展:把 dropout 用到受限玻尔兹曼机;用乘性高斯噪声替代伯努利掩码;在线性回归里,对 dropout 求期望后等价于一种 L2 正则,每个权重的惩罚按对应输入特征的尺度加权。
关键结果。
- 实验覆盖 4 个领域:视觉(MNIST、SVHN、CIFAR-10、CIFAR-100、ImageNet)、语音(TIMIT)、文本(Reuters RCV1)、计算生物学(可变剪接预测)。加入 dropout 后,几乎所有任务的测试误差都下降,文本任务的提升最小。
- 特征更干净:在 MNIST 自编码器上,加 dropout 后每个隐单元学到独立的笔画片段,激活也更稀疏。
- 代价:梯度噪声变大,训练时间约为普通网络的 2 到 3 倍。
关键概念
- 过拟合(overfitting)
- 模型在训练集上误差很低,在新数据上误差高。参数越多、数据越少,越容易发生。dropout 是专门对付它的正则化方法。
- 共适应(co-adaptation)
- 多个神经元互相依赖,联合起来拟合训练集里的偶然模式。随机删除伙伴后,每个神经元必须独立学到有用特征。
- 保留概率(retention probability, p)
- 论文里 p 指神经元被保留的概率,不是被丢弃的概率。隐层常用 0.5,输入层常用 0.8。
- 权重缩放推断(weight scaling inference rule)
- 测试时不丢弃,把权重乘以 p,使输出期望和训练时一致。它用一次前向计算近似 2^n 个子网络的平均预测。
- 反向 dropout(inverted dropout)
- 论文之后的工程写法:训练时把保留下来的输出除以 p,测试时什么都不做。效果等价,推理代码更简单,今天的框架都这样实现。
- 最大范数约束(max-norm constraint)
- 限制每个单元输入权重向量的 L2 范数不超过常数 c,超过就缩回去。它和 dropout 配合使用,允许更大的学习率而不发散。
历史位置:为什么值得读
它出自同一个实验室、同一年的突破。2012 年 Hinton 团队在 arXiv 上发布了 dropout 的技术报告。同年 AlexNet(第 8 天)在全连接层用了 dropout,并在 ImageNet 上大胜。2014 年的这篇 JMLR 论文是完整版,系统地给出实验、分析和扩展。作者名单里有 Krizhevsky 和 Sutskever,也就是 AlexNet 的两位作者。
它改变了人们对正则化的看法。在此之前,正则化主要靠权重衰减和提前停止。dropout 说明:往训练过程里注入结构化噪声,也是强大的正则化手段。后续出现了一系列变体:DropConnect 随机丢弃权重;空间 dropout 整个丢弃卷积通道;随机深度(stochastic depth)整个跳过残差块。
它和清单里其他天紧密相连。第 3 天 Zaremba 等人解决了 dropout 用在 RNN 上的问题:只在层与层之间丢弃,不在时间步之间丢弃。第 9 天 ResNet 用批归一化代替了 dropout,说明 BN 本身也有正则化效果。2016 年 Gal 和 Ghahramani 证明,测试时保留 dropout 并多次采样,可以近似贝叶斯推断,用来估计模型的不确定性。
学前准备
- 理解过拟合,以及 L2 正则化的作用
- 知道伯努利分布,会算随机变量乘以掩码后的期望
- 能手写一个两层全连接网络的前向和反向传播
- 建议先看第 8 天,了解 dropout 第一次大规模使用的场景
在原仓库怎么学
- 读 README.md 的目录,它依次讲过拟合、原理、两种写法和训练技巧。对照论文第 2 到 4 节读。
- 读 implementation.py。它用 NumPy 实现 dropout 和几种变体,适合逐行对照前向和反向公式。
- 运行 train_minimal.py,在 MNIST 上训练。用
--dropout 0.5指定丢弃率;用--compare-rates比较多个丢弃率;用--mc-dropout做蒙特卡洛采样。 - 用 visualization.py 画 4 类图:有无 dropout 的训练曲线、掩码模式、特征冗余对比、集成解释。spatial_dropout_comparison.png 是空间 dropout 的对比结果图。
- 打开 notebook.ipynb,从过拟合问题走到反向 dropout 的实现。
- 做 exercises/ 的 5 个练习:01 从零实现 dropout 的前向和反向;02 扫描丢弃率;03 实现空间 dropout;04 用蒙特卡洛 dropout 估计不确定性;05 对比 dropout 和其他正则化方法。答案在 exercises/solutions/。
今天再看
dropout 仍是工具箱里的常备件,但用法变了。2017 年的原始 Transformer 在每个子层输出和嵌入上都用了 0.1 的 dropout。可是很多大语言模型在预训练时把 dropout 设为 0。原因是数据量极大,每条数据只看一遍左右,模型处于欠拟合状态,不需要防过拟合。
数据不够时,dropout 又回来了。有研究发现,同一批数据重复训练多轮时,加入 dropout 能缓解性能下降。微调阶段数据少,dropout 也常用,例如 LoRA 的配置里就有专门的 dropout 参数。
“训练时注入噪声”这个思想更加普遍。随机深度、数据增强、标签平滑、扩散模型的加噪训练,都在用随机扰动让模型学到更稳健的表示。蒙特卡洛 dropout 也仍被用来做低成本的不确定性估计。
容易卡住的地方
- 论文的 p 是保留概率,PyTorch 的 nn.Dropout(p) 里 p 是丢弃概率。论文输入层 p = 0.8,换到 PyTorch 要写 0.2。
- 评估前必须调用 model.eval(),否则测试时仍在随机丢弃,准确率会忽高忽低。继续训练前要调回 model.train()。
- 反向 dropout 在训练时除以 p,测试时什么都不做。不要再在测试时乘 p,否则输出被缩放两次,数值整体偏小。
- dropout 放在批归一化之前时,训练和测试的方差不一致,可能降低准确率。建议把 dropout 放在 BN 之后或只用在全连接层。
延伸阅读
- 原论文:Dropout: A Simple Way to Prevent Neural Networks from Overfitting
- 原仓库第 12 天目录:12_dropout/ —— 代码、笔记本、练习与答案(英文)
- Improving neural networks by preventing co-adaptation of feature detectors —— 2012 年的 dropout 技术报告
- Dropout as a Bayesian Approximation —— 蒙特卡洛 dropout 与不确定性估计
- Recurrent Neural Network Regularization —— 第 3 天:dropout 用在 LSTM 上
- Batch Normalization —— BN 也有正则化效果,可减少 dropout