模型评估与泛化:指标、过拟合与正则化
混淆矩阵计算器、四大指标、不平衡数据陷阱、L2、Dropout(经典 ML 评估,LLM 评测见第 23 章)。
对应课件:1-2 模型评估和数值稳定
本章对应课件:《1-2 模型评估和数值稳定》。核心内容:训练/泛化误差、数据划分、混淆矩阵、Accuracy/Precision/Recall/F1、欠拟合与过拟合、L2 正则化、Dropout。
3.1 训练误差与泛化误差
先懂直觉
训练集上做得好不代表真的学会了——可能只是把答案背下来了。真正重要的是模型在没见过的数据上的表现,这就是泛化。
- Training error:模型在训练集上的表现;
- Generalization error:模型在没见过的数据上的表现。
一个模型可能训练集准确率 100%、测试集准确率 60%——这不是优秀模型,而是过拟合。
两个学生备考:
- 学生 A 把练习册答案全背下来(训练误差 0),考试遇到新题就懵(泛化误差高);
- 学生 B 理解了方法,练习册上有几道错题(训练误差 > 0),但新题基本都会(泛化误差低)。
我们要的是学生 B。这也是为什么「训练 loss 降到 0」不是目标。
3.2 数据划分
| 数据集 | 用途 | 典型比例 |
|---|---|---|
| Training set | 训练参数 | 80% |
| Validation set | 调超参数、选模型 | 10% |
| Test set | 最终评估(只测一次) | 10% |
测试集不应该反复拿来调模型。如果你根据测试集分数反复调整超参数,测试集的信息就「泄漏」进了模型选择过程,最终报告的成绩不再客观。正确做法:用验证集调参,测试集只在最后评估一次。
3.3 混淆矩阵
先懂直觉
二分类的预测有四种结果:预测对/错 × 实际正/负。把这四种数量放进一个 2×2 表格,就是混淆矩阵——所有分类指标都从它算出来。
| 实际正 | 实际负 | |
|---|---|---|
| 预测正 | TP | FP |
| 预测负 | FN | TN |
- TP (True Positive):真的有病,预测有病 ✅
- FP (False Positive):实际上没病,预测有病 ❌ 俗称误报
- FN (False Negative):真的有病,却预测没病 ❌ 俗称漏报
- TN (True Negative):没病,也预测没病 ✅
3.4 Accuracy、Precision、Recall、F1
先懂直觉
Accuracy 回答「总体对多少」;Precision 回答「你说是正的里面有多少真是正的」(怕误报);Recall 回答「真正的正样本你找出来多少」(怕漏报)。F1 是两者的平衡。
Accuracy(准确率)
问题是类别不平衡时很危险。例如 1000 人只有 10 个患癌,模型全部预测健康:
但这个模型一个癌症都查不出来,完全没用。
Precision(精确率)
回答:我预测为正的人中,有多少真的为正? 强调「别误报」。比如垃圾邮件系统——把正常邮件判成垃圾的代价很高。
Recall(召回率)
回答:所有真正的正样本中,我找出来多少? 强调「别漏掉」。比如癌症筛查——漏掉一个患者代价极大。
F1
它是调和平均数。如果 ,则 。所以只有 Precision 和 Recall 都较好,F1 才高。
修改 TP/FP/FN/TN 四个数字,实时观察 Accuracy、Precision、Recall、F1、Specificity 的变化。试试把 TP 调成 0,看 Accuracy 和 Recall 会发生什么。
1000 人,10 个患癌:
模型 A:全部预测健康
- TP=0, FP=0, FN=10, TN=990
- Accuracy = 99%
- Precision = 0/0(无定义,通常记 0)
- Recall = 0/10 = 0% ← 一个都没查出来
模型 B:查出来 8 个,误报 50 个
- TP=8, FP=50, FN=2, TN=940
- Accuracy = 94.8%(反而更低!)
- Precision = 8/58 ≈ 13.8%
- Recall = 8/10 = 80%
结论:在不平衡数据上,Accuracy 会骗人。医疗场景宁可选 B(高 Recall),垃圾邮件场景则要高 Precision。
Q1:类别不平衡时为什么不能只看 Accuracy?
查看答案
多数类占比高时,模型只要全预测多数类就能拿到很高的 Accuracy(如 99%),但少数类(往往才是关注目标)Recall 为 0。应改用 Precision/Recall/F1、AUC 或按类加权的指标。
Q2:什么时候优化 Precision,什么时候优化 Recall?
查看答案
看错误的代价:误报代价高(垃圾邮件、推荐系统)→ 优先 Precision;漏报代价高(癌症筛查、欺诈检测、安全)→ 优先 Recall。F1 是两者兼顾的折中。
3.5 欠拟合与过拟合
先懂直觉
欠拟合是「学得太少」,过拟合是「学得太死」。前者训练集都做不好,后者训练集接近满分但新数据拉胯。
欠拟合(Underfitting):模型太简单,训练集都学不好,测试集当然也不好。例如真实关系是一条弯曲曲线,你硬用直线拟合。
过拟合(Overfitting):模型复杂得过头,把训练数据每一个噪声都记住了,训练误差很低,但测试误差变高。
课件中的典型曲线:
误差
| \ 训练误差持续下降
| \______________________
|
| ___
| / \___ 测试误差:先下降后上升
| / \_____
+---------------------------→ 模型复杂度
↑ 最佳复杂度
随着模型复杂度增加:
- 训练误差:不断下降;
- 测试误差:先下降,再上升;
- 中间就是比较好的模型复杂度。
工程里怎么用(判断与对策)
| 现象 | 训练误差 | 测试误差 | 对策 |
|---|---|---|---|
| 欠拟合 | 高 | 高 | 增大模型、加特征、减小正则、多训练 |
| 过拟合 | 低 | 高 | 加数据、正则化(L2/Dropout)、早停、减小模型 |
大模型时代过拟合的形态不同:预训练通常还没「训够」(数据量太大),而 SFT 阶段数据少,容易过拟合(表现为背答案、泛化差)。
3.6 L2 正则化 / Weight Decay
先懂直觉
给「参数太大」加一个惩罚。模型为了降低总损失,会尽量用小权重——小权重意味着函数更平滑,更不容易过拟合。
为了防止过拟合,可以惩罚权重太大:
这样模型不仅要拟合训练数据,还要尽量使用比较小的参数。
梯度变成:
SGD 更新:
整理:
所以 每一步都会先被乘上 缩小一点,因此叫 Weight Decay。
原始形式是硬约束:(参数必须在球内)。用拉格朗日乘子把约束转成惩罚项,就得到软约束 ——课件正是用这个过渡说明正则化的本质是在限制模型容量。
3.7 Dropout
先懂直觉
训练时随机「关掉」一部分神经元,逼迫网络不依赖某一条特定路径。就像一个团队里随机有人请假,每个人都必须能独立工作。
训练时随机把部分神经元关掉。例如 表示随机 drop 20%。
直觉:如果一个神经元总能依赖另一个——
A:「反正 B 会解决」
就容易形成过拟合。Dropout 相当于:
B 随机不来上班,所以 A 自己也必须学会工作。
具体行为:
- 训练时:随机 mask(被 drop 的神经元输出置 0);
- 推理时:不 Dropout(使用完整的网络)。
训练时神经元以概率 被保留,输出期望变成原来的 倍。所以:
- 有的实现训练时除以 (inverted dropout);
- 有的实现推理时乘以 。
PyTorch 的 nn.Dropout 采用 inverted dropout(训练时除以保留概率),推理时什么都不做。
- Dropout 只在训练时开启:
model.eval()会自动关闭 Dropout 和 BatchNorm 的训练行为,忘记切换会导致推理结果随机。 - Dropout 与 BatchNorm 可能冲突:两者都影响激活的统计量,同时大量使用要小心(现代 Transformer 常用 dropout=0.1 以下)。
| 概念 | 一句话 |
|---|---|
| 泛化误差 | 真正重要的指标:模型在没见过的数据上的表现 |
| 数据划分 | 训练调参 / 验证选模型 / 测试只测一次 |
| 混淆矩阵 | TP/FP/FN/TN,四个指标的来源 |
| Precision vs Recall | 别误报 vs 别漏报,F1 是调和平均 |
| 过拟合 / 欠拟合 | 太复杂记噪声 / 太简单学不动 |
| L2 / Weight Decay | 惩罚大权重, 每步缩小 |
| Dropout | 训练随机失活,防止神经元互相依赖 |
显示答案与解析
正确答案:B
TP=0, FN=10, TN=990, FP=0。Accuracy = (0+990)/1000 = 99%,但 Recall = TP/(TP+FN) = 0/10 = 0%。这展示了不平衡数据下 Accuracy 的欺骗性。显示答案与解析
正确答案:B
漏掉一个真实患者(FN)的代价远高于一次误报(FP),所以优先提高 Recall。垃圾邮件过滤则相反,优先 Precision。显示答案与解析
正确答案:B
加入 λ‖W‖² 后梯度多出 λW 项,整理后 W ← (1−ηλ)W − η∇L,参数每步都被衰减一点,因此得名。显示答案与解析
正确答案:B
Dropout 只在训练时使用(正则化手段),推理时使用完整网络。PyTorch 中 model.eval() 会自动关闭。