学习目标
- 根据训练误差和验证误差区分欠拟合、适当拟合与过拟合。
- 解读学习曲线以及训练损失与验证损失之间的差距。
- 解释模型容量与系统性误差、结果波动之间的关系。
- 选择合理的方法缓解欠拟合或过拟合。
- 说明模型开发过程中验证集和测试集的正确用途。
1. 不只看一种误差
训练集反映模型对用于估计参数的样本拟合得如何。验证集帮助判断学到的规律能否迁移到没有参与参数更新的数据。比较时应使用相同的指标或损失,并确保测量条件具有可比性。
训练误差低并不足够。我们需要同时观察训练集和验证集的表现。测试集应留给最终的独立评估,不应反复用于选择模型。
2. 欠拟合:模型没有捕捉到规律
欠拟合(underfitting)是指模型对于任务过于简单、特征不足、约束过强,或优化尚未找到合适参数。此时模型在训练样本上已经存在较大误差,验证集表现通常也不会明显更好。
典型信号是训练损失和验证损失都较高。可以检查特征和任务定义,选择表达能力更强的模型,减弱过度正则化,或确认优化是否收敛。单纯延长训练并不总能解决问题,应先找出真正的限制。
3. 适当拟合:规律能够迁移
具有良好泛化能力时,训练误差较低,验证误差与其接近且没有明显恶化。两者存在小幅差异是正常的,因为样本不同且存在抽样波动。关键在于结果是否稳定,以及指标是否满足任务要求。
验证损失不一定低于训练损失。正则化、dropout 等方法可能有意增加训练难度,因此训练损失有时更高。应结合具体算法和指标理解数值。
4. 过拟合:模型过度贴合样本
过拟合(overfitting)是指模型过于精确地拟合训练样本,包括噪声和样本特有的细节。训练误差持续下降,但验证误差停止改善或开始上升。模型能很好描述熟悉的样本,却难以稳定迁移到新数据。
原因可能同时存在:模型容量过大、数据缺少多样性、标签噪声、信息泄漏、调参次数过多,或反复依赖同一个验证集。较大的训练与验证损失差距是有用信号,但并非单独的证明;还应检查数据划分、分布和测量方式。
5. 学习曲线与提前停止
训练过程中,训练损失通常持续下降。验证损失可能先下降,随后停止改善并开始上升,这是过拟合的一种典型表现。提前停止(early stopping)会选择验证指标最佳的时刻,并恢复该时刻对应的模型参数。
不要使用测试集选择训练轮次。提前停止应使用验证集或内部验证机制。实际中可以设置 patience,即在停止前允许若干轮没有改善,以免对单次波动过度反应。应观察趋势,而不是单个噪声点。
6. 模型容量:权衡而不是竞赛
提高模型容量通常会改善对训练数据的拟合,因此训练误差往往下降。但验证误差可能先下降、随后上升,因为模型开始描述样本特有的噪声。这体现了偏差—方差权衡,但并不是适用于每个模型和数据集的普遍定律。
高偏差意味着模型家族无法充分表达相关关系;高方差意味着训练样本变化时,拟合结果也会显著变化。这些概念有助于诊断,但实际决策仍需实验、正确的数据划分和数据分析。
7. 先诊断,再选择方法
如果训练损失和验证损失都高,应检查模型表达能力、特征、正则化和优化收敛。如果训练损失低而验证损失明显更高或持续上升,应检查信息泄漏、噪声和分布差异,再考虑简化模型、正则化、增加多样化数据、数据增强或提前停止。
不要同时应用所有方法。一次改变一个因素,固定验证流程并比较结果。更多数据只有在相关且能代表未来条件时才有帮助。正则化过强也可能让模型重新陷入欠拟合。
8. 一个多项式模型小实验
在同一个合成任务上比较不同复杂度的模型。线性模型可能过于简单,无法表达波动关系;中等阶数的多项式可能拟合得更好;高阶多项式则可能对噪声和个别点过度敏感。具体数值取决于随机划分,因此应比较训练和验证结果,而不是宣称某个阶数永远最好。
本例使用验证集选择复杂度。选择方案后,应在没有参与调参的独立测试集上进行最终评估。在实际工作中,如果数据量允许,也可以使用多次划分或交叉验证。
示例:比较不同复杂度的多项式模型
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
rng = np.random.default_rng(7)
X = np.sort(rng.uniform(0, 1, 36)).reshape(-1, 1)
y = np.sin(2 * np.pi * X[:, 0]) + rng.normal(0, 0.18, len(X))
X_train, X_val, y_train, y_val = train_test_split(
X, y, test_size=0.25, random_state=7
)
for degree in (1, 4, 12):
model = make_pipeline(
PolynomialFeatures(degree=degree, include_bias=False),
LinearRegression()
)
model.fit(X_train, y_train)
train_mse = mean_squared_error(y_train, model.predict(X_train))
val_mse = mean_squared_error(y_val, model.predict(X_val))
print(degree, round(train_mse, 3), round(val_mse, 3))输出列依次为多项式阶数、训练 MSE 和验证 MSE。阶数增加时,训练误差可能下降,但验证误差不一定同步下降。可以更换 random_state 再运行,观察结果是否稳定。不要把验证集当作最终测试集。
实践任务
比较两个实验:第一个 train loss = 0.42、validation loss = 0.45;第二个 train loss = 0.08、validation loss = 0.91。在指标相同且数据集可比时,第二种情况值得检查是否过拟合。但在修改模型结构之前,应先确认划分正确、没有信息泄漏,并且验证集能代表预期使用条件。
参考资料与延伸阅读
课程术语表
模型即使在训练数据上也无法捕捉重要规律。
模型过度贴合训练样本中的细节和噪声,损害对新数据的表现。
模型在目标应用领域的新样本上保持有效表现的能力。
在用于估计模型参数的数据上计算的损失。
在独立数据集上计算、用于模型选择和调参的损失。
在可比测量条件下,验证误差与训练误差之间的差值。
模型家族表达不同关系的能力。
由模型假设或限制导致的系统性误差。
模型拟合结果对训练样本变化的敏感程度。
根据验证表现停止训练,并恢复最佳检查点。
自我检测
问题 1
如果训练损失和验证损失都很高,首先应检查什么?
问题 2
哪种现象通常提示过拟合?
问题 3
验证集的主要用途是什么?
问题 4
为什么不应反复使用测试集调参?
问题 5
哪些方法可能缓解过拟合?
问题 6
较大的泛化差距意味着什么?
问题 7
哪种做法可能帮助解决欠拟合?
问题 8
训练损失很低,是否能证明模型在新数据上表现良好?