第4题:什么是过拟合,如何解决?
一、什么是过拟合?
过拟合(Overfitting)指模型在训练数据上表现很好,但在新的、未见过的数据上表现明显变差。
机器学习真正关心的是模型的泛化能力,也就是:
模型在训练过程中没有见过的数据上,能否保持良好的预测性能。
假设训练误差为:
Etrain E_{\text{train}} Etrain
验证误差为:
Eval E_{\text{val}} Eval
如果模型继续训练后:
Etrain↓ E_{\text{train}} \downarrow Etrain↓
但:
Eval↑ E_{\text{val}} \uparrow Eval↑
或者训练集与验证集之间的性能差距不断扩大,就需要怀疑出现了过拟合。
可以将泛化差距简单写成:
$$
\text{Generalization Gap}
E_{\text{val}}-E_{\text{train}}
$$
这个差距明显增大,通常意味着模型对训练数据中的特定模式拟合过强。
需要注意:
“训练 loss 继续下降、验证 loss 开始上升”是典型的过拟合现象,但不是唯一的判断方式。
在分类任务中也可能表现为:
- 训练集 Accuracy 很高;
- 验证集 Accuracy 明显较低;
- 训练集 F1 很高;
- 验证集 F1 明显下降。
核心始终是:
训练数据表现与未见数据表现之间出现明显的泛化差距。
二、为什么会发生过拟合?
常见原因主要有以下几类。
1. 模型容量相对于数据过大
例如:
- 网络层数过深;
- 参数数量很多;
- 特征数量很多;
- 决策树过深。
模型具有很强的表达能力时,可能把训练数据中的偶然模式和噪声也学习进去。
因此通常需要在:
拟合能力 \text{拟合能力} 拟合能力
和:
泛化能力 \text{泛化能力} 泛化能力
之间取得平衡。
2. 训练数据太少
如果数据量相对于模型复杂度过小,模型很容易记住训练样本中的细节。
例如一个参数量很大的神经网络,只使用很少的样本训练时,可能获得很低的训练误差,但在新数据上表现较差。
3. 训练数据缺乏代表性
即使训练数据数量很多,如果它无法覆盖实际部署环境,也可能产生很大的泛化误差。
例如训练数据全部来自环境 A,而实际部署数据主要来自环境 B。
此时:
Ptrain(X,Y) P_{\text{train}}(X,Y) Ptrain(X,Y)
和真实应用中的:
Preal(X,Y) P_{\text{real}}(X,Y) Preal(X,Y)
存在明显差异。
模型在训练集上表现很好,也不能保证实际效果。
4. 数据中存在噪声或偶然相关性
复杂模型可能学习到与任务目标没有稳定因果关系的模式。
例如:
- 背景颜色;
- 文件路径;
- 数据采集设备;
- 时间戳;
- 特定模板;
- 标签生成过程留下的特征。
这些特征可能在训练数据中与标签高度相关,但换到新的数据后关系消失。
5. 训练时间过长
神经网络训练初期通常先学习较稳定的模式。
继续训练后,模型可能逐渐拟合训练数据中的细节和噪声。
因此可能出现:
Training Loss
持续下降
Validation Loss
先下降
↓
达到最低点
↓
开始上升
这也是 Early Stopping 的主要依据。
三、如何解决过拟合?
处理过拟合时,建议先判断原因,再选择措施。
方法1:先检查数据泄漏
这是实际项目中非常重要的一步。
数据泄漏(Data Leakage)指模型训练过程中使用了预测时本来无法获得的信息。
例如:
- 测试集参与训练;
- 在全部数据上计算归一化参数后再划分训练集和测试集;
- 特征选择时使用了测试集;
- 同一用户的数据同时出现在训练集和测试集;
- 同一项目的高度相似样本同时进入训练集和测试集;
- 时间序列任务中使用未来数据预测过去。
这种情况下可能看到:
Validation Accuracy≈99% \text{Validation Accuracy} \approx 99\% Validation Accuracy≈99%
但上线后性能突然下降。
因此排查顺序应该首先包括:
- 检查训练集、验证集、测试集是否真正隔离;
- 检查重复样本;
- 检查同源样本;
- 检查预处理是否泄漏;
- 检查标签是否能够从输入中的某些异常特征直接推断。
数据泄漏属于评测设计错误,需要与模型本身的过拟合分开诊断。
方法2:增加高质量且具有代表性的数据
如果训练数据不足,可以增加训练样本。
通常:
更多有效数据→更难记忆单个训练样本→更容易学习稳定规律 \text{更多有效数据} \rightarrow \text{更难记忆单个训练样本} \rightarrow \text{更容易学习稳定规律} 更多有效数据→更难记忆单个训练样本→更容易学习稳定规律
这里的关键是“有效”和“具有代表性”。
增加大量重复、错误或分布偏移的数据,可能无法提高泛化能力。
方法3:数据增强
如果无法直接获得更多真实数据,可以使用合理的数据增强。
例如图像任务中:
- Random Crop;
- Flip;
- Rotation;
- Color Jitter。
数据增强希望在保持标签语义不变的条件下增加输入变化。
可以写成:
(x,y)→(T(x),y) (x,y) \rightarrow (T(x),y) (x,y)→(T(x),y)
其中 TTT 是不会改变真实标签的数据变换。
有效的数据增强可以减少模型对单一样本形式的依赖。
方法4:降低模型复杂度
如果模型容量明显超过任务需求,可以减少模型复杂度。
例如:
- 减少网络层数;
- 减少隐藏层维度;
- 减少参数量;
- 减少无效特征;
- 限制决策树深度。
目标是降低模型拟合训练噪声的能力。
方法5:L1 / L2 正则化
正则化通过在原始训练目标中加入复杂度惩罚,限制参数自由度。
原始目标可能是:
minθL(θ) \min_\theta L(\theta) θminL(θ)
加入 L2 正则化后:
minθ[L(θ)+λ∥θ∥22] \min_\theta \left[ L(\theta) + \lambda \|\theta\|_2^2 \right] θmin[L(θ)+λ∥θ∥22]
其中:
- L(θ)L(\theta)L(θ):原始任务损失;
- ∣θ∣22|\theta|_2^2∣θ∣22:参数平方和;
- λ\lambdaλ:正则化强度。
λ\lambdaλ 越大,模型受到的参数约束通常越强。
L1 正则化可以写成:
minθ[L(θ)+λ∥θ∥1] \min_\theta \left[ L(\theta) + \lambda \|\theta\|_1 \right] θmin[L(θ)+λ∥θ∥1]
L1 还具有促进参数稀疏的特点。
方法6:Weight Decay
在深度学习中经常使用 Weight Decay 限制权重增长。
在很多常见优化设置下,它与 L2 正则化具有密切联系。
例如训练时设置:
optimizer = torch.optim.AdamW(
model.parameters(),
lr=1e-4,
weight_decay=1e-2
)
需要注意具体优化器。
AdamW 使用 decoupled weight decay,其更新机制需要与直接在 loss 中添加 L2 penalty 区分理解。
方法7:Dropout
Dropout 是神经网络中常见的正则化方法。
训练过程中随机将部分神经元输出置零:
hi′=mihih'_i=m_i h_ihi′=mihi
其中:
mi∼Bernoulli(1−p) m_i \sim \text{Bernoulli}(1-p) mi∼Bernoulli(1−p)
ppp 是 dropout probability。
例如:
self.dropout = nn.Dropout(p=0.1)
Dropout 会降低神经元之间过强的共同适应,从而提高模型的泛化能力。
需要注意:
Dropout 主要在训练阶段随机丢弃单元。
推理阶段通常使用完整网络,并由框架按照对应规则处理缩放。
方法8:Early Stopping
训练过程中持续监控验证集性能。
例如:
Epoch 1
Validation Loss = 0.50
Epoch 2
Validation Loss = 0.42
Epoch 3
Validation Loss = 0.38 ← 最优
Epoch 4
Validation Loss = 0.40
Epoch 5
Validation Loss = 0.46
此时可以保存 Epoch 3 的模型。
也就是:
t∗=argmintLval(t)t^*=\arg\min_tL_{\text{val}}(t)t∗=argmintLval(t)
Early Stopping 可以避免模型在训练后期继续拟合训练数据中的噪声。
实际使用时通常还会设置 patience,例如:
patience = 5
验证性能连续若干轮没有改善后再停止,减少随机波动导致的过早终止。
方法9:合理使用验证集和交叉验证
需要将数据划分为:
Training Set
Validation Set
Test Set
三者作用分别是:
- Training Set:学习模型参数;
- Validation Set:选择超参数、模型结构和停止时机;
- Test Set:在所有设计完成后评估最终泛化性能。
测试集不能反复用于模型选择。
如果数据量有限,还可以使用 K-fold Cross Validation 更稳定地估计模型泛化性能。
交叉验证主要用于:
- 模型比较;
- 超参数选择;
- 泛化性能估计。
它本身不会直接降低一个固定模型的复杂度。
四、实际项目中建议怎样排查?
如果发现:
训练集:98%
验证集:82%
不要立即开始调 Dropout。
建议按照以下顺序处理。
Step 1:检查评测是否合法
先检查:
- 数据泄漏;
- 数据重复;
- 切分方式;
- 时间泄漏;
- 用户/项目泄漏;
- 预处理泄漏。
Step 2:观察学习曲线
同时画:
Ltrain L_{\text{train}} Ltrain
和:
Lval L_{\text{val}} Lval
判断随着 epoch 增加,两条曲线如何变化。
Step 3:判断数据问题
检查:
- 数据量是否足够;
- 训练集是否具有代表性;
- 标签噪声是否严重;
- train / validation 是否存在分布差异。
Step 4:判断模型容量
如果训练集几乎完全拟合,而验证集明显更差,需要考虑:
- 减小模型;
- 减少特征;
- 增加正则化。
Step 5:加入针对性的正则化
根据模型类型选择:
- L1;
- L2;
- Weight Decay;
- Dropout;
- 数据增强;
- Early Stopping。
Step 6:重新验证
所有超参数都在验证集上确定。
最后固定模型后,再使用测试集进行最终评估。
五、一个常见误区
看到训练集表现明显好于验证集时,需要同时考虑多个原因:
性能差距 \text{性能差距} 性能差距
可能来自:
- 模型过拟合;
- 数据分布变化;
- 数据泄漏导致之前的评测虚高;
- 验证集规模过小;
- 标签质量差异;
- 切分策略错误。
因此,完整的工程判断需要结合数据切分、学习曲线和错误分析。
六、面试时可以这样总结
过拟合指模型在训练数据上表现很好,但在新的未见数据上泛化性能明显下降。典型现象是训练 loss 持续下降,而验证 loss 在下降到一定程度后开始上升,或者训练集和验证集之间出现明显性能差距。
处理时我会先检查数据切分和数据泄漏,因为错误的评测设置会掩盖真实问题。确认评测可靠后,再根据原因处理:数据不足时增加高质量数据或数据增强;模型容量过高时降低复杂度;训练自由度过高时使用 L1/L2、Weight Decay 或 Dropout;训练后期出现过拟合时使用 Early Stopping。所有模型选择都在验证集上完成,测试集只用于最终泛化评估。
来源
[1] Google Machine Learning Crash Course, Overfitting
[2] Google Machine Learning Crash Course, Model Complexity
[3] Google Machine Learning Crash Course, L2 Regularization and Early Stopping
[4] scikit-learn Documentation, Cross-validation: evaluating estimator performance
[5] scikit-learn Documentation, Common pitfalls and recommended practices — Data leakage
[6] Goodfellow, Bengio and Courville, Deep Learning, Chapter 7: Regularization for Deep Learning
[7] Srivastava et al., Dropout: A Simple Way to Prevent Neural Networks from Overfitting, JMLR, 2014

9441

被折叠的 条评论
为什么被折叠?



