ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Dropout 和正则化:深度学习如何缓解过拟合?

Dropout 和正则化:深度学习如何缓解过拟合?

🎯 博主简介

你好,我是安逸,CSDN「人工智能技术领域新星创作者」,码龄 6 年。博客总访问量 31万+,博客粉丝 1.2万+。

我长期关注人工智能技术与工程实践,主要研究和分享 AI Agent、RAG 系统、MCP 协议、OpenClaw、AI 编程工具以及大模型工程化落地。同时也持续输出 Java / Spring、Transformer、机器学习、深度学习与计算机视觉等方向的学习笔记和项目经验。

📚 推荐系列合集

目前已经整理了 生产级 RAG 系统实战、Agent 记忆系统、MCP 协议深度解析、OpenClaw 系列、Hermes Agent + Obsidian、图解机器学习、Claude Code 系列和 Agent 经典面试题等系列合集,涵盖 AI 应用开发、智能体实践、知识管理、机器学习与 AI 编程工具。

📱GZH:安逸Ai (科技前沿新闻,Github热门项目,最新免费资料...)

网页观看完整系列合集:🌐 Anyi AI 学习资源站


上篇我们聊了 Batch Normalization 和 Layer Normalization,它们解决的是训练过程中数据分布不稳定的问题。

模型能正常训练了,但还有一个更大的麻烦在等着——过拟合。

你有没有遇到过这种情况:模型在训练集上表现接近满分,准确率99%,但一放到真实环境里,效果断崖式下跌?

这就是过拟合在作祟。

过拟合:模型界的"高分低能"

过拟合(Overfitting)简单说就是:模型在训练数据上表现很好,但泛化到新数据时性能急剧下降。

我把这种情况比喻成学生刷题。

一个学生把题库里的所有题目(包括错题)都背下来了,遇到原题当然对答如流。但换一套新题?完蛋,连最基本的概念都想不起来。

这就是"死记硬背"和"真正理解"的区别。

真正的学霸不是背答案,而是掌握了解题套路,遇到没见过的题目也能举一反三。

放到深度学习里也是一样的道理。

训练集上的图片可能有特定的光照条件、拍摄角度,甚至有水印、噪点这些"无关细节"。模型把这些全记住了。

但考试(测试)的图片可能换个角度、换个背景,模型就不认识了。

泛化能力才是衡量模型价值的真正标尺。

你想想,一个只会做老师出过题目的学生,和一个能解决新问题的学生,哪个更值钱?

"剪刀差":过拟合的视觉信号

怎么一眼看出模型过拟合了?

看训练曲线和验证曲线。

训练初期,两条曲线一起往上升,说明模型在学习。但到某个点之后,情况变了:

训练曲线继续高涨,验证曲线反而掉头向下。

两条曲线像剪刀一样张开,这就是经典的"剪刀差"。

正常模型:两条曲线一起上升,然后趋于平稳,差距不大。

过拟合模型:训练曲线一路狂奔,验证曲线半路趴窝。

差距越大,过拟合越严重。

训练准确率和验证准确率随训练轮次变化的曲线图,形成明显的剪刀差,标识过拟合发生的位置

过拟合的本质原因,是模型"死记硬背"了训练数据的噪声和细节。

什么是噪声?训练图片里的光照变化、角度变化、水印噪点,这些不是本质的东西,但模型把它们全记住了。

真正有价值的规律是:猫有尖耳朵、狗有长鼻子,不管角度怎么变,这些特征都在。

记住无关的,忽略关键的——这就是过拟合。

那怎么办?

接下来介绍两把应对过拟合的利刃:Dropout 和正则化。

Dropout 是什么?神经网络也搞"随机裁员"

第一把利刃叫 Dropout。

它的思路很暴力:训练的时候,随机让一部分神经元"下线"。

具体怎么做?

每个神经元,以概率 p 被"关闭"。

被关闭的神经元不参与前向传播,也不参与后向传播。简单说就是,它在这次训练中不存在。

第二次训练,重新随机选一批神经元关闭。

第三次训练,又是新的随机组合。

就这样,每次训练都像在玩俄罗斯轮盘赌,一批幸运的神经元存活,一批倒霉的神经元被裁掉。

数学上怎么实现?

$y = f(W \cdot mask(x) + b)$

这个 mask 就是掩码函数,它的值是 0 或 1。值为 0 的神经元就被"关闭"了。

有个实现上的小细节需要注意:

# Dropout 的简化实现 def dropout(x, p): mask = (torch.rand(x.shape) > p).float() return x * mask / (1 - p) # Inverted Dropout

为什么要除以 (1-p)?后面会解释。

左图为完整的全连接网络,右图为随机丢弃部分神经元后的子网络,丢弃的神经元用虚线表示

这个随机性带来一个很巧妙的效果:

每个神经元都不能依赖特定的"邻居"。

你想啊,如果 A 神经元一直和 B、C 神经元配合,它们三个形成了固定的小团队。那 A 被裁掉了,B 和 C 怎么办?

B 和 C 必须能够独立扛起任务,A 也必须能够和其他神经元配合。

久而久之,每个神经元都是多面手,能独当一面。

这就像一个公司的项目组,每次开会随机让一部分人"离线"。

剩下的人必须自己搞定所有讨论,不能依赖某几个特定的人。

结果是:每个人都变强了,整个团队的韧性提高了。

Dropout 为什么有效?往下看。

从"随机裁员"到 Bagging 集成

Dropout 的本质,是Bagging 思想的一种廉价实现。

Bagging 是什么?

Bootstrap Aggregating,让多个模型对同一数据进行预测,最后综合所有模型的预测结果。

多个模型的意见取平均,比任何一个单独的模型都稳定。

就像投票表决,一万个人投票永远比一个人投票更可靠。

Dropout 的巧妙之处在于:它把单个网络变成了无数个子网络。

一个有 n 个神经元的层,理论上能采样出 $2^n$ 个不同的子网络。

Dropout 每次训练,其实是在训练一个不同的子网络。

测试的时候,对所有子网络的预测结果做平均,就起到了"集思广益"的效果。

这比训练和保存 $2^n$ 个独立模型要便宜太多了。

所以 Dropout 本质上是一种隐式的集成学习。

训练阶段:每次随机采样一个子网络进行训练,相当于训练了 $2^n$ 个模型中的某一个。

测试阶段:把所有子网络的预测结果汇总,输出平均值。

树状结构图展示从父网络采样出多个子网络的过程,底部汇总表示预测结果的集成

用一个例子来理解:

想象一个万人智囊团,每次开会随机抽 3000 人参与讨论一个问题。

不同的人有不同的背景和视角,讨论的结果也不同。

最后把所有会议的结论综合起来,比任何一个单独专家的意见都稳定可靠。

这就是 Dropout 的思路:用随机性换稳定性。

但有个问题:训练时随机丢弃,测试时怎么办?

Inverted Dropout:让测试结果稳定

最早期的 Dropout 实现(叫 Vanilla Dropout),在测试阶段也需要随机丢弃神经元。

这会导致一个很糟糕的问题:每次预测结果不一样。

你用同一个输入跑两次模型,输出不一样。

这在实际应用中是完全不可接受的。

后来大家发现了一个更聪明的做法,叫 Inverted Dropout。

核心改动在训练阶段:

保留所有神经元,但在输出时乘以 $\frac{1}{1-p}$ 来做缩放。

测试阶段:不做任何修改,所有神经元正常工作。

这样训练和测试的输出期望就保持一致了,而且测试结果完全稳定。

PyTorch 的nn.Dropout(p)默认就是 Inverted Dropout 模式。

# 训练阶段 y = x * mask / (1 - p) # 缩放 # 测试阶段 y = x # 直接用,不用改

为什么叫"Inverted"(反转)?

因为以前是把操作放在测试阶段,现在把操作放在训练阶段。

就像调音师在录音的时候(训练阶段)就把音量调到标准,播放的时候(测试阶段)就不需要再额外调整了。

简单、稳定、好用,这就是 Inverted Dropout 成为主流的原因。

对比表展示 Vanilla Dropout 和 Inverted Dropout 在训练行为、测试行为、结果稳定性三个维度的差异

Dropout 是从网络结构入手解决过拟合。

还有另一种思路:从损失函数入手。这就是正则化。

L1/L2 正则化:给损失函数加"复杂度税"

正则化的思路是:在损失函数里加一个惩罚项。

损失函数原来只关心预测准不准,现在还要关心模型复杂不复杂。

L2 正则化惩罚权重的平方和:
$$L_{new} = L_{old} + \lambda \sum_{i} w_i^2$$

L1 正则化惩罚权重的绝对值和:
$$L_{new} = L_{old} + \lambda \sum_{i} |w_i|$$

这个 $\lambda$ 是正则化强度,由你手动设置。

权重越大,惩罚越重。

权重越小,惩罚越轻。

所以模型被迫保持"简洁",权重不能太大。

这就像给模型的损失函数加了一个"复杂度税"。

越复杂的模型(权重越大),交的税越重。

越简洁的模型,交的税越少。

既然复杂要交税,那模型就倾向于保持简洁,从而降低过拟合风险。

两种正则化有什么不同?

L2 正则化惩罚权重的平方,让权重趋向于小而分散。

L1 正则化惩罚权重的绝对值,能产生稀疏权重——有些权重直接变成 0。

权重变成 0 意味着什么?

意味着对应的特征被模型"忽略"了。

所以 L1 正则化自带特征选择功能。

如果你怀疑输入特征里有很多是无用的,L1 正则化可以帮助你自动找出哪些特征有用、哪些没用。

Weight Decay:L2 正则化的另一个名字

在 SGD 优化器中,L2 正则化等价于 Weight Decay(权重衰减)。

Weight Decay 的更新公式是:
$$w = w - \eta \cdot (\nabla L + \lambda w)$$

拆开看:

  • $\nabla L$ 是普通梯度下降
  • $\lambda w$ 是额外的权重衰减

这在数学上等价于在损失函数里加 $\lambda \sum w^2$ 项。

所以很多人把 L2 正则化和 Weight Decay 混用。

但要注意:在 Adam 等自适应学习率优化器中,L2 正则化和 Weight Decay 并不完全等价。

Adam 对每个参数有自己的学习率调整,L2 正则化的效果会被自适应学习率"吃掉"一部分。

如果你用 Adam 优化器,想做 L2 正则化,需要用 AdamW——一个专门修复了这个问题的变体。

对比图展示未正则化的权重分布呈两极分化,部分值极大;L2 正则化后的权重分布更集中,更接近零

用生活场景来理解正则化:

考试评分通常不仅看答案对不对,还要看解题思路是否简洁优雅。

同样正确的两个答案,一个用了 10 行推导,一个用了 3 行推导,3 行的通常得分更高。

因为简洁的解法更可能是"真正理解了",而不是"碰巧试对了"。

正则化就是那个给复杂解法扣分的机制。

模型如果用很复杂的方式拟合了训练数据,那它的"分数"会被扣掉一部分。

这样模型就不会去死记硬背那些只在训练数据上有效的"小聪明"解法。

实战避坑:代码层面的经验总结

理论说完了,聊聊实际代码里怎么用。

Dropout 概率怎么选?

p 通常在 0.1 到 0.5 之间。

p 太小(比如 0.01),正则化效果不明显,等于没加。

p 太大(比如 0.8),模型学不到足够的信息,严重欠拟合。

一般从 0.2 或 0.3 开始尝试,然后根据效果调整。

Dropout 只在训练阶段生效

这是一个超级容易踩的坑。

# 训练阶段 model.train() # Dropout 生效 output = model(x) # 测试阶段 model.eval() # Dropout 关闭 output = model(x)

如果在测试时忘记切换到model.eval(),Dropout 还在随机丢弃神经元,输出结果会非常不稳定。

很多新手在这个坑里卡了好几天。

PyTorch 代码示例

import torch import torch.nn as nn class Net(nn.Module): def __init__(self): super().__init__() self.fc1 = nn.Linear(784, 256) self.dropout1 = nn.Dropout(0.3) # p=0.3 self.fc2 = nn.Linear(256, 10) def forward(self, x): x = torch.relu(self.fc1(x)) x = self.dropout1(x) # Dropout x = self.fc2(x) return x # 优化器带 L2 正则化(通过 weight_decay) optimizer = torch.optim.Adam(model.parameters(), lr=0.001, weight_decay=0.01)

训练循环里一定要记得模式切换:

for epoch in range(epochs): model.train() # 切换到训练模式 for batch in train_loader: optimizer.zero_grad() output = model(batch) loss = loss_fn(output, labels) loss.backward() optimizer.step() model.eval() # 切换到评估模式 with torch.no_grad(): for batch in val_loader: output = model(batch) # 计算验证集指标

Dropout 放在哪里?

一般放在全连接层(Linear/Dense)的后面。

卷积层后面通常不太用 Dropout,因为卷积层本身就具有参数共享的特性,已经有一定的正则化效果。

放在哪里效果最好?没有标准答案,需要实验。

一般从靠近输出的层开始尝试,因为输出层附近的层最容易过拟合。

PyTorch 代码截图,展示模型定义、Dropout 层使用、model.train() 和 model.eval() 切换,以及 weight_decay 参数配置

把这些配置参数想象成调节"游戏难度"的旋钮:

  • Dropout p 值越大,游戏越难(模型能学到的东西越少)
  • L2 weight_decay 越大,游戏越难
  • 数据量越大、模型越简单,可以把难度调低一点

需要反复摸索才能找到最佳配置。

最后聊两句

Dropout 和正则化看起来是两种完全不同的技巧。

一个是从网络结构入手,一个是从损失函数入手。

但它们在做同一件事:让模型在"记忆训练数据"和"学习通用规律"之间找到平衡。

Dropout 让每个神经元都得学会独立工作,不能依赖特定的"邻居"。

正则化给复杂模型加税,迫使模型保持简洁。

一个是"随机裁员",一个是"加复杂度税"。

都能让模型不再死记硬背,而是真正学会举一反三。

理解了背后的原理,你就能举一反三,根据实际问题灵活选择或组合这些工具。

你的数据量很大、模型很轻量?Dropout 是个好选择。

你的模型很复杂、担心权重太大?L2 正则化更合适。

有时候,两者一起用效果更好。

关键在于:它们都在做同一件事——让模型不要过度拟合训练数据。

下篇预告

Dropout 和正则化解决了"模型太复杂"的问题。

但处理图像这种数据,还有另一个思路:设计更适合图像的网络结构。

这就是下篇要聊的:卷积神经网络 CNN。

CNN 是怎么工作的?为什么它特别适合处理图像?

咱们下回分解。

返回列表