13 课 · 泛化与过拟合
LESSON 13 · 卷十三 学会了吗

它的 loss 已经低到千分之二
可考卷只有 66.5%

第 12 课的机器装好了,可以真开训了。训完你会看到一个非常漂亮的数字: 训练 loss 掉到 0.002。 而你把同一份训练攒出来的考卷递过去,它只答对 66.5% —— 加减题 99.0%,乘除题 34.0%。 这两个数之间那道缝,就是这一课的全部内容。 「训练 loss 掉得越低越好吗」—— 这一课要给你的答案是:训练 loss 根本就不是那个该盯的数字。

STAGE 01
那道缝
训练 0.00 · 验证 55.09
STAGE 02
诊断地图
能力 × 数据量
STAGE 03
我们那个模型
两种病同时得
STAGE 04
三个刹车
数据 · 容量 · 早停

先造一个能亲眼看完的例子。真的训练一个模型太慢、也太难看清;但「过拟合」这件事跟模型大小无关 —— 我们用最老实的东西复现它:24 道题,真规则是 y = x²(一个 2 次的规律),每道题的答案上叠一点 ±3 的观测噪声(同一道题问两次答案会差一点,这是题目本身的属性, 谁也消不掉)。然后拿多项式去拟合它:多项式几次, 就有几个可调参数。

招牌实验24 道题、两个旋钮 —— 看训练误差和验证误差什么时候分手
多项式几次:
给它几个训练点:(灰色按钮 = 参数个数已经 ≥ 点数,方程解不唯一,不给算)
020040060014812162024x(第几道题)y← 真规则 y = x²(虚线)2 次多项式拟合曲线
训练点 · 18 个里取了 12验证点 · 钉死的 6 道(2 / 6 / 10 / 14 / 18 / 22),一个都没拿来训练竖线 = 预测错多远
现在这一档:2,用了 12 个训练点。 训练误差 1.37,验证误差 1.62, 差了 1.2
它错得最离谱的那道验证题是 x = 22: 真值 486、它报 484,差 2。 验证误差已经贴着噪声地板 1.58 了 —— 剩下那点差是题目本身的噪声,再好的模型也消不掉, 因为同一道题问两次、答案本来就会差一点。
参数一个一个加固定 12 个训练点,看训练误差和验证误差什么时候分手
次数
参数
训练 RMSE
验证 RMSE
验证 ÷ 训练
0
1
179.87
170.05
0.9
1
2
46.47
40.36
0.9
2
3
1.37
1.62
1.2
3
4
1.29
1.44
1.1
4
5
1.26
1.55
1.2
5
6
1.26
1.54
1.2
6
7
0.90
2.33
2.6
7
8
0.79
2.25
2.8
9
10
0.26
4.89
19.1
11
12
0.00
55.09
∞(训练误差 0)
👆 图怎么读:横轴是第几道题(x),纵轴是答案(y)。蓝色虚线是真规则 y = x², 黄色实线是当前这一档拟合出来的曲线,点是 24 道题的观测答案(真值叠了 ±3 的噪声)。 实心点是喂给它的训练点,空心点是钉死的验证点 ——练完之后才拿验证点去问它,这才是「没见过」的意思。 点上的竖线是「预测错了多远」,训练点的竖线几乎为零(它当然背得下来), 验证点的竖线就是那道缝。 把次数往上加、数据量往下调,看黄色曲线怎么穿过每一个训练点、 却在验证点上甩出去 —— 表的最后那一列就是这事有多严重。
这一课所有吓人的数字都从这 24 道题里长出来,而且全都能按计算器复现: 噪声一共 24 个、平方和 60、方差 2.5, 于是验证误差有一条地板2.5 = 1.581139
图 13-1 · 同一个模型,训练误差一路降、验证误差先降后升 —— 中间那个拐点就是「该停下了」
训练 loss 是成绩单
验证 loss 才是考试

三句话讲完这一课

  • 过拟合 = 一道缝:训练误差和验证误差之间的差距。 在见过的题上越来越好、在没见过的题上越来越差,就是它的全部含义。
  • 参数 vs 数据是个比例:能力(参数)不能超过数据撑得起的量。 我们这个模型 798,720 个参数配 4,000 条语料 —— 每条样本摊 199.68 个参数。
  • 三个刹车:给更多数据、把容量降下来、在考卷不涨时停手。 三个都是「别让它有余力去背题」,而不是「把训练 loss 再压低一点」。
第 1 站

那道缝:训练 0.00,验证 55.09

上面那个实验里最该盯着看的,是同一档配置下的两个数。 把数据量钉在 12 个点,然后把次数一路往上加: 训练误差从 1.37 一路降到 0.00, 而验证误差先贴着地板(这一列最好的一格是 1.44),然后掉头冲到 55.09

这两个数分别是怎么算出来的
训练误差 = √( Σ(拟合值 − 观测值)² ÷ 训练点个数 )
验证误差 = √( Σ(拟合值 − 观测值)² ÷ 验证点个数 )
两个都是 RMSE(均方根误差),单位跟答案一样,不是平方过的量

计算方式一模一样,唯一的区别是用哪些点算: 训练误差只用喂给它的点,验证误差只用那 6它一个都没见过的点(2 / 6 / 10 / 14 / 18 / 22)。 所以两个数的差距不是算法差异造成的,它恰好就是 「背下来的题」和「没见过的题」之间的差距。

为什么 12 个点配 12 个参数就能精确穿孔? 因为这是个线性方程组:12 个未知数、12 个方程, 一般恰好有唯一解。曲线必须从每个点上穿过 —— 所以训练误差必然是 0,跟模型好不好没有任何关系。 这就是「训练 loss 低」最不值钱的样子。

面试常问 · 「过拟合」这一题的标准答法
  • 定义:模型把训练集里的噪声也当成规律学了进去, 于是在训练集上表现继续变好、在新数据上反而变差。观察指标是训练/验证误差那道缝。
  • 和「模型太大」的关系:不是「参数多就一定过拟合」,而是参数相对于数据太多。同样的模型,数据从 12 个加到 18 个, 验证误差就从 55.09 掉到 4.78(降了 11.5 倍)。
  • 和「欠拟合」的区别:欠拟合是训练误差本身就高(连训练集都没学好, 能力不够或没练够);过拟合是训练误差很低而验证误差高。 我们那个模型两种病同时得,第 3 站细说。
  • 别忘了第三种可能:训练集和验证集分布不一样(比如验证集里 题目更难),那道缝也可能是出题造成的 —— 第 9 课那个「换张考卷差 28 分」说的就是这件事。
现在给你两个模型:A 的训练误差 0.00、验证误差 55.09;B 的训练误差 1.30、验证误差 1.44。你选哪个上线?为什么 A 看起来更「准」?
第 2 站

诊断地图:能力和数据是一对

那道缝不是随便裂开的,它由两个旋钮共同决定: 模型有多大的能力(几次多项式 = 几个参数)、 手里有多少数据(喂它几个点)。把这两件事铺成一张表, 每一格都是当场解一次最小二乘算出来的验证误差:

核心实验能力 × 数据量 = 验证误差 —— 点任意一格,看它是怎么得的病
6 个点
8 个点
12 个点
18 个点
0 次 · 1 参数
1 次 · 2 参数
2 次 · 3 参数
3 次 · 4 参数
4 次 · 5 参数
5 次 · 6 参数
6 次 · 7 参数
7 次 · 8 参数
9 次 · 10 参数
11 次 · 12 参数
横着读一行 = 固定数据量,把能力往上加;竖着读一列 = 固定能力,把数据往上加。 ★ = 那一档数据量下的最佳次数(验证误差最小)。虚线格 = 参数个数 ≥ 点数, 方程解不唯一,不给算 —— 这正是「参数比数据多」的字面意思。
贴着噪声地板(< 1.58 × 1.15)已经偏高飞了(噪声地板的 20 倍以上)
选中的这一格:11 次多项式12 个训练点 —— 训练误差 0.00,验证误差 55.09
看点上面那几个格子的颜色:能力加得越多,右下角越红。 同样的 12 个点,2 次多项式验证误差 1.62, 11 次多项式 55.09 —— 能力涨了,在没见过的题上反而崩了
但也别把绿色看太细:验证集只有 6 道,运气好时验证误差能压到地板1.58 以下(比如 3 次配 12 点的 1.44)—— 所以 1.44 和 1.62 的差别不用太当真,要警惕的是它有没有冲到几十上百
👆 图怎么读:每一格都是「用这一档能力、这一份数据,解一次最小二乘, 再拿钉死的 6 道验证题去问它」。颜色只看相对噪声地板的倍数, 不按表里最大值归一化 —— 那样换个数据量颜色就全变了,没法比。 下面三件事请在这张图上亲手确认: 竖着看每一列,★ 都落在 2~3 次 上(真规则本来就是 2 次的, 能力加过头只会开始拟合噪声); 数据从 6 个加到 18 个,红色区域整体往右下退 ——数据越多,越撑得起大能力 左下角那几格是虚线:参数比数据还多,那时候谈「泛化」已经没有意义了。
别把这张图当成「越大越好」或「越小越好」的单向标尺:同样 11 次的多项式,配 12 个点是灾难(55.09), 配 18 个点就还能用(4.78。 能力和数据必须匹配,这是这一课最实用的一条。
图 13-2 · 行 = 能力(参数个数),列 = 数据量;★ 是那一档数据量下的最佳能力

请注意你刚刚看到了什么:每一列的 ★ 都落在 2~3 次上,没有一列是次数越高越好。这不是巧合 —— 数据里的真规则本来就是 2 次的。能力低于它就是「装不下」(欠拟合),高过它就是「拿多余的自由度去描噪声」(过拟合), 而多出来的那些自由度正好够它把 12 个点一个一个记住。

面试常问 · 为什么不干脆「把模型做大一点」

「大模型一定更好」这句话要配一个前提:数据也要跟着大。 看地图上 12 个点那一列:能力从 3 个参数加到 12 个参数, 验证误差是 1.6255.09涨了差不多 34。 把同样这 12 个参数放到 18 个点那一列,它才回到 4.78

参数个数 ÷ 训练点个数:12 ÷ 12 = 1 ← 最危险的比例
12 ÷ 18 = 0.6712 ÷ 6 = 2.00

所以真实世界里那句话不是「做大模型」,而是「在数据允许的范围内尽量做大」 —— 规模定律(scaling law)说的正是「模型、数据、算力要一起长」, 只长一头就是在给过拟合发邀请函。

第 3 站

我们那个模型:两种病同时得

现在把尺子转回第 7 阶段那个真模型。它两笔账都很清楚:训练 loss 0.002(低到几乎为零),考卷 66.5%(不高)。 只看这两个数,你会以为它是典型的过拟合。可是拆开看题型呢: 加减 99.0%、乘除 34.0% —— 差了 65.0 个百分点

核心实验同一个整体分,两份方向完全相反的体检报告
预设病例 
加减组平均99.0%
乘除组平均34.0%
模型 A · 分题型差得远你拧的这一档
整体分66.5%
加法加减组 · 组内偏高
99.3%
减法加减组 · 组内偏低
98.7%
乘法乘除组 · 组内偏低
30.7%
除法乘除组 · 组内偏高
37.3%
训练 loss 0.002 | 考卷换算 −ln(66.5 ÷ 100) = 0.408 | 相差 204
诊断:装不下(欠拟合) → 药 = 加容量
模型 B · 样样都及格同一个整体分,摊得齐平
整体分66.5%
加法与整体分齐平
66.5%
减法与整体分齐平
66.5%
乘法与整体分齐平
66.5%
除法与整体分齐平
66.5%
训练 loss 0.002 | 考卷换算 −ln(66.5 ÷ 100) = 0.408 | 相差 204
诊断:样样都及格(过拟合) → 药 = 加数据
模型 A(你拧的这一档)加减 99.0% 说明这两类它表示得出来、也学明白了; 乘除只有 34.0%,而训练 loss 已经贴在 0.002,再练也爬不动 —— 这不是没练够,是它根本表示不出这类规律。 药是加容量(或换输入表示,第 14 课补的就是这件事),不是加数据
模型 B(同一个整体分,四类摊平):四类齐刷刷 66.5%,没有一类突出, 可训练 loss 只有 0.002 —— 它在背题,不是在学规律。 这是过拟合(缝裂开),药是加数据
两张报告摆在一起看:整体分都是 66.5%,训练 loss 都是 0.002, 考卷换算出来都是 0.408 —— 相差 204 倍,一个字都不差。 光看这几个数,你分不出哪张是「装不下」、哪张是「样样都及格」; 唯一把它们分开的是那四根分题型条:左边最好和最差差 68.6 个百分点,右边四根齐平。 ——「整体 66.5%」这一个数,既可能是「一半满分、一半空白」,也可能是「样样都及格」, 而这两件事的药完全相反(一个要加容量,一个要加数据)。所以评估必须分题型看。
👆 先拖那两根滑块:一根调「加减组平均」、一根调「乘除组平均」。 两张报告的整体分永远相等 —— 卡 B 就是照着卡 A 那个整体分、把四类摊平的「样样都及格」版。 整体分一动,训练 loss 与考卷换算 loss 的倍数就跟着动;可只要整体分相同, 两张报告上能看到的数就一模一样,只有四根条分得开。 再点三个预设病例:① 一半满分、一半空白(装不下,药是加容量); ② 样样都及格(过拟合,药是加数据);③ 本课真模型。
这一档的数字全来自实测记录(每 500 步考一遍,一共 4 档;考卷最高的是第 600067.3%):本课真模型整体 66.5%、加减 99.0% / 乘除 34.0%(差 65.0 个百分点、 四类最大差 68.6 个百分点),训练 loss 0.002 vs 考卷换算 0.408 —— 204 倍。
先拖那两根滑块:一根调「加减组平均」、一根调「乘除组平均」—— 两张报告的整体分永远相等(右边的卡就是照这个整体分把四类摊平的「样样都及格」版)。 再点三个预设病例直接对比:① 一半满分、一半空白(装不下,药是加容量)和 ② 样样都及格(过拟合,药是加数据)—— 整体分一模一样,药却完全相反。
图 13-3 · 整体分相同的两张体检报告:整体分、训练 loss、考卷换算倍数都一模一样,只有分题型那四根条分得开
病一 · 缝裂开了
训练 loss 0.002 vs 考卷换算过来的 0.408 —— 204。 它确实在训练集那一侧「越来越好」,在新题上跟不上。
病二 · 装不下(更主要)
乘除卡在 34.0% 而且爬不动 —— 训练 loss 都贴在 0.002 了,这不是没练够, 是它根本表示不出这类规律。这是欠拟合,不是过拟合。
面试常问 · 诊断先分病,再开药
  • 不看分题型,你会开错药:「整体 66.5%」这一个数, 既可能是「一半满分、一半空白」,也可能是「样样都及格」——这两件事的药完全相反(一个要加容量,一个要加数据)。
  • 加减 99.0% 说明它真的会了:这两类规律它表示得出来、 也学明白了。这部分不是问题。
  • 乘除 34.0% 说明它表示不出来:乘法需要「把两个数 当成有序的一对数」来看,而它的输入只是单个字符的向量 —— 第 14 课就是去补这个。
  • 「参数量 vs 数据量」这个比例只是体检指标,不是诊断书 798,720 ÷ 4,000 = 199.68 个参数/条,比例确实失衡 (地图上那一格是 12/12),但是不是真过拟合, 还得拿没见过的题去问才知道。
你已经知道「训练 loss 0.002」什么都不能证明。那反过来问: 如果训练 loss 掉到 0.002、考卷也是 99%,你会放心吗?还得再问一句什么?
第 4 站

三个刹车:数据、容量、早停

分开病之后,药就好开了。我们的模型两种病都得, 而两种病各有各的刹车 —— 一共三个,前两个上面已经亲手拧过:

起步
11 次 × 12
55.09
刹车① 后
11 次 × 18 点
4.78
刹车② 后
2 次 × 12
1.62
三根长条都是验证误差,共用一个刻度:满格 = 60。 所以长短可以直接对比,不是各自按本行最大值放大 —— 「起步那根快撑满了」和「刹车后只剩一小截」是同一把尺子量出来的。
刹车① 更多数据:同样是 11 次多项式,训练点从 12 个加到 18 个, 验证误差 55.094.78(降了 11.5 倍)。 代价是训练误差从 0.00 涨回 0.84 —— 它不再「全背下来」了,这正是我们要的。注意最离谱那道题的改善: x = 22 上误差 131 11
刹车② 减小容量:参数从 12 个砍到 3 个, 验证误差 55.091.62(降了 34 倍), 训练误差只从 0.00 回到 1.37少给点自由度,是这三个刹车里最便宜的一个。

第三个刹车是我们在真实训练里唯一还用得上的(因为数据是有限的、 模型大小也常常不能随便改):早停。 下面这张表就是第 7 阶段那次训练的实测记录,训练 loss 和考卷分数并排放着 —— 请你自己选一个停手的时机。

核心实验训练 loss 一路在降,考卷分数却在第 6000 步见顶
训练 loss 一路在降 —— 你会在第几步收手?
2000
训练 loss 0.038
57.5%
4000
训练 loss 0.030
63.5%
6000
训练 loss 0.004
67.3%
8000
训练 loss 0.002
66.5%
长条 = 那一档的整体考卷分数(满格 100%,没有按本列最大值放大)。 绿色那行是考卷的最高分,红色那行是训练的最后一步 —— 它比绿灯那行低了 0.8, 可它的训练 loss 反而更低(0.002 < 0.004)。
你选了8000收手:这一档的考卷分数是 66.5% —— 这正是「一路练到底」的结果。你比最高分那档少了 0.8, 而训练 loss 明明还在往下走。
为什么训练 loss 靠不住?它的分母是「训练集里的每一个字」, 模型把训练集背得越熟它就越低 —— 它是在训练集上的成绩单, 不是「学会了」的证明。真正该盯的是那张没进过训练集的考卷: 考卷分数连着两轮不涨了,就该停。早停的前提是你手里有一张考卷(第 9 课那件事在这里结了账)。
8000 步的考卷,拆开看是什么样 ↓
加减加法 99.3% · 减法 98.7% · 两类都到 95% 以上
99.0%
乘除乘法 30.7% · 除法 37.3% · 一直爬不上去
34.0%
这两条差 65.0 个百分点。早停能治的是「训练 loss 还在降、 考卷却往下走」那一种;它治不了这一条 —— 因为乘除不是被练坏了, 是从头到尾就没学会(下一课的事)。
最后对一下两个量级:训练 loss 从 0.038 一路降到 0.002(降了 19 倍), 可考卷分数是 66.5%。
66.5% 粗算成 loss(一道题对错的平均惊讶 ≈ −ln(正确率)): −ln(0.665) = 0.408。 两个数是 204 的差距 —— 这就是开头那道缝。
注意这个换算只是个量级对照:真实 loss 是逐个字算的, 考卷是逐道题判对错的,两者不是同一把尺子。 它能说清的只有一件事:训练 loss 低到这个程度,和「考卷上真会做」之间还隔着很远。
这张表是实测记录(第 7 阶段的真实训练),页面上不重算 —— 训练结果没法「当场算」。它和第 9 课那张评估表是同一份数据。
图 13-4 · 训练 loss 单调降到 0.002,考卷分数 67.3% → 最后 66.5% —— 再练下去是反作用
为什么早停是「最省钱」的刹车

它不需要更多数据、也不需要改模型结构,只是在正确的时候停手。 代价只有一个,而且是必须付的:

早停的前提 = 手里有一张没进过训练集的考卷
没有它,只有训练 loss 可看 —— 而它从 0.002 那一段 一直在降、一次没回头,你没有任何理由在第 6000 步停手

这就是「验证集」在工程上的真正用处:它不是为了写论文好看, 它是一个你必须留出来的刹车信号。 我们那 4,000 条语料里, 最后真拿来出考卷的是 1000 × 4 = 4000 道题,剩下的才是训练集 —— 第 14 课会把这笔账一条一条算清楚。

还有一类刹车统称正则化:权重衰减(第 12 课那个超参)就是其中之一 —— 在更新参数时顺手把它往 0 拽一点,等于给「参数长得很大」加罚金, 让它不敢拿自由度去描噪声。它们和上面三个是同一个目的,只是从损失函数那一侧下手,而不是从数据、容量、时机那一侧下手

第 5 站 · 收官

把这一课钉在墙上

本课核心 · TAKEAWAY

训练 loss 是成绩单,验证 loss 才是考试。模型把训练集背得越熟,训练 loss 就越低 —— 所以它降得越低越不能证明什么12 个参数配 12 个点, 训练误差必然精确为 0,可验证误差是 55.09, 噪声地板的 35 倍。 真正该盯的是两个数之间那道缝:训练误差和验证误差一起降,那是在学习; 训练误差还在降、验证误差掉头向上,那是在背题。 缝的成因是能力超过了数据撑得起的量 —— 我们那个模型 798,720 参数配 4,000 条语料(199.68 个参数/条),这个比例失衡; 但比例只是体检指标,诊断还得靠分题型看考卷: 它加减 99.0%、乘除 34.0%, 差 65.0 个百分点 ——前半是过拟合的口味,后半是容量装不下的病,两种病同时得。药一共三副:更多数据55.09 4.78)、减小容量55.09 1.62)、早停(考卷不涨了就停, 从第 6000 步硬练到 8000 步那 2000 步是白练的)。

这一课你亲手做完了

  • 造了一批能算清的题24 道,真规则 y = x², 噪声平方和 60、方差 2.5, 于是验证误差有一条手算得出的地板 1.581139
  • 拧出了那道缝12 个训练点下,2 次多项式验证误差 1.62,11 次多项式 0.00 / 55.09 ——训练误差为 0 的那一档,恰恰是最没用的那个
  • 看过诊断地图10 行 × 4 列, 每一列的 ★ 都落在 2~3 次上 —— 没有一列是次数越高越好
  • 给真模型做了体检:训练 loss 0.002 vs 考卷 66.5%(粗算 204 倍), 拆开是加减 99.0% / 乘除 34.0%。
  • 拧过三个刹车:更多数据(降 11.5 倍)、 减小容量(降 34 倍)、 早停(第 600067.3% 是最高的, 一路练到 8000 步反而掉到 66.5%)。

学习小测验

已完成 0 / 60.0%答对 0
还没提交过 —— 每题先选一个选项,再点「提交」,答完就能看到诊断。
Q1训练 loss 掉到很低,能说明模型「学会了」吗?
Q2「过拟合」最准确的意思是什么?
Q3第 2 站那张地图上,为什么每一列的 ★ 都落在 2~3 次,而不是次数越高越好?
Q4我们这个模型 798,720 个参数、4,000 条语料。这个比例危险在哪?
Q5下面哪个不是治过拟合的刹车?
Q6早停听起来很省事:那为什么不能说「练到训练 loss 不再降就停」?
NEXT · 第 14 课

实战:训练算术小模型

这一课诊断出来的最重那一条是「装不下」—— 乘除卡在 34.0%,训练 loss 都贴到 0.002 了还是爬不动。 下一课不再拿这个小玩具做实验,而是真训一个模型: 把语料从 4,000 条扩到几万道题、 把题目出全(加法 90×90、减法、乘法、除法各自铺满), 然后亲手把它训出来,看乘除那两栏能不能真的动起来。 这一课学会的「分题型看考卷、盯住那道缝」, 到了下一课就是你唯一能相信的仪表盘。

从零手册 —— 下一课:实战:训练算术小模型