一个能背下所有训练数据的模型,往往一个都没学会。 正则化就是在「拟合数据」和「参数变小」之间拔河:它让模型宁可「差不多对」, 也不要「精确地记住」。
《优化器谱系》说「卡住」多是假象,却没管模型会不会把噪声也记住。这一章接住它。 下面是 12 个带噪声的数据点。拖动「模型复杂度」,看曲线怎么从太钝变成刚刚好, 再变成疯掉。
训练误差在拿来训练的那份数据上算;测试误差在模型从没见过的另一份数据上算。 真实训练时看不见最终那份测试集,所以先从训练数据里切一块出来当验证集。
互动 · 复杂度 vs
| 状态 | 训练误差 | 测试误差 | 曲线长什么样 |
|---|---|---|---|
| 高 | 高 | 一条直线,根本没抓住形状 | |
| 刚刚好 | 低 | 最低 | 平滑地穿过数据中间 |
| 过拟合 | 接近 0 | 非常高 | 精确穿过每个点,点之间疯狂扭动 |
模型把噪声也当成规律记住了。就像学生把答案背下来,题目一换就全错。 判断信号:训练误差还在降,测试误差开始涨。过拟合就是这么开始的。
正则化听起来很数学,其实就是两股力在拔河:
两股力,一根绳
两股力方向相反:橙箭头想把绳结拉向「数据想去的 1」,紫箭头想把它拉向「惩罚想去的 0」。 绳结停在哪儿,由两股力的强弱决定——数学那一节能拖着 λ 亲手拉一遍。
正则化就是在损失函数里加上第二股力,再用一个系数 λ 决定谁说话更响 (数学那一节把这条式子写成公式,还能拖着 λ 看解往 0 挪):
为什么「参数小」就等于「模型简单」?数值大时,各项互相顶牛,曲线在两个点之间大起大落; 把系数一起压小,每一项都缩成零头,叠出来的曲线就被拉平,想扭也扭不动了。
同一个 15 次多项式:系数大,曲线扭成一团;系数压小,曲线被拉平
回到上面的交互,把「模型复杂度」拖到 15,然后慢慢把 λ 拉大。 你会看到那条疯掉的曲线被惩罚那股力一点点拽回平滑。正则化就是这么干活的。
像写作文。第一股力是「把观点表达清楚」,第二股力是「别写太长」。 只有第一股力,你会写出一万字的流水账,把所有细节都塞进去; 只有第二股力,你交白卷。好的 λ 让你写出紧凑又完整的文章。
加惩罚项,效果上等于把参数关进一个大小有限的盒子:λ 越大盒子越小。 两股力拔河的结果就落在盒子的边界上(只要 λ > 0)。 下面图里的蓝圈是等高线——误差相同的点连成的圈,像地图上的等高线; 离最优点越远误差越大,所以它们一圈圈往外扩。而边界长什么形状,决定了参数会不会变成 0。 下面滑块里的 t 就是盒子的大小:t 越小盒子越小,相当于 λ 越大。
互动 · 蓝圈是误差的等高线,绿框是惩罚圈出的盒子,解在它们相碰的地方
| 对比项 | L2(岭回归 / 权重衰减) | L1(Lasso) |
|---|---|---|
| 惩罚项 | λ·Σw² | λ·Σ|w| |
| 约束形状 | 圆(平滑、没有角) | 菱形(尖角在坐标轴上) |
| 解落在哪 | 一般不会正好在轴上 | 经常正好落在轴上 → 该参数变成 0 |
| 效果 | 把所有参数一起压小 | 直接把一部分参数清零 = 自动特征选择 |
| 用在哪 | 绝大多数场景的默认选择 | 想要稀疏、想筛特征时 |
能,叫 Elastic Net:λ₁·Σ|w| + λ₂·Σw²。想要稀疏又嫌 L1 不稳(见第 6 节那张表)时用它。
等高线是一圈一圈往外扩的椭圆,它会从某个方向撞上盒子的边界。 圆是光滑的,撞到哪儿就是哪儿;菱形有四个尖角,而尖角正好在坐标轴上 (也就是某个 w = 0 的地方)。统计上,撞上尖角的概率明显更大。所以 L1 会产生稀疏解。
训练时,每一轮随机把一部分神经元直接关掉(输出置 0)。就这么简单。 一轮 = 把全部训练数据从头到尾过一遍。
互动 · 真跑两个网络:Dropout 到底改变了什么
上面那张图只是画出来的随机失活。下面这一个是真跑:两个网络结构完全一样(2 → 32 → 1),
同一份数据、同一个初始权重、同样 3000 步
正在跑实验…
「Dropout 之所以有用,是因为它打破了神经元之间的共谋」——这句话你几乎能在每一份教程里读到。
它的可检验版本是:开 Dropout 之后,隐藏层神经元
真算一遍(下面那组柱子):平均 |r| 0.668 → 0.677(几乎没变);Σw² 529 → 381(明显变小)
也就是说,那个流传最广的预测,在这套实验里没有兑现。
但 Dropout 本身有效(默认 p = 0.2 时它一路赢),真正同时变小的是 Σw²——
方向和第 3 节的 L2
互动 · 开 Dropout 前后:两个关键量怎么变
正在等上面的实验算出数字…
| 问题 | 答案 |
|---|---|
| 为什么有用? | 大致可以理解成同时训练了很多个子网络再取平均。至于流传最广的那句「打破神经元共谋」——上面真跑了一遍,没量出来。 |
| 关掉多少? | 隐藏层一般 p = 0.1 ~ 0.5(原论文隐藏层取 0.5、输入层 0.2),全连接层用得最多;卷积层(图像模型里常用的一种层,后面的阶段讲)用得少。 |
| 推理时怎么办? | 推理(训练完拿出来用,只算结果、不改参数)时不关任何神经元。补偿有两套方案:现代框架(含 PyTorch)用 inverted dropout——训练时就把输出除以 (1−p),推理时原样输出,所以推理路径没有任何额外开销;原始论文那套正好相反(训练时不动,推理时乘 (1−p))。两者只能选一个,混用会算错。 |
| 什么时候用? | 模型明显过拟合、数据量不够的时候。现代大模型更常用 |
像一支球队训练时随机让几个人下场。剩下的队员必须学会补位, 整个队伍不再依赖某个明星球员。正式比赛时全员上场,配合反而更稳。
注意:这个类比听着很顺,但它对应的那个可测指标(神经元之间的相关性) 在上面那个实验里并没有下降。类比能帮记忆,不能当证据。
第 2 节的「拔河」一句话就能写成公式: 数据想把 w 拉向拟合最好的那个值,惩罚想把 w 拉向 0,λ 决定谁力气大。 下面那张图就是这两股力。橙线是数据力,紫线是惩罚力,亮线是它们拔河的结果。
互动 · 两股力拔河,亮线的谷底就是最优的权重
把 λ 从 0 慢慢拉大:亮线那颗圆点(最优 w)会从 w = 1 一路往 0 靠,但到不了 0—— 它只会越来越小。换到 L1:惩罚变成一条尖 V,圆点会贴着 0 停住,真能到 0, 这正是第 3 节那个尖角的来源。
前面几节讲的是「为什么要拽」。这一节把拽的办法按它动的是谁排开, 每一类里都有好几条,区别只在它改的是数据、是损失,还是训练过程。
总览 · 本章讲的所有招,按它动的是谁分三类
| 手段 | 它做了什么 | 一行公式 | 典型强度 |
|---|---|---|---|
| 更多真数据 | 最有效,没有之一。数据够多,过拟合自然消失 | — | — |
| 把输入变着花样造新的(翻转、裁剪、变色) | x′ ~ T(x) | 看任务 | |
| 把 one-hot 标签软化:不要求模型对到 1,只要求它「最像」 | y′ = (1−ε)·y + ε/K | ε = 0.1 | |
| Mixup / CutMix | 不只变输入,连标签一起插值:两张图各取一部分,标签也按比例取 | x̃ = t·xᵢ + (1−t)·xⱼ | α = 0.2(t 从它控制的分布里抽) |
符号:x′ = 变换后的输入,T = 一种随机变换(翻转 / 裁剪 / 变色), y′ = 软化后的标签,ε = 平滑强度,K = 类别数, t = 两张图的混合比例(从一个由 α 控制的分布里随机抽,别和正则强度 λ 混了)。 one-hot 标签:正确答案那一类是 1、其余是 0。 Label smoothing 是现在几乎所有 ImageNet(一个大型图像数据集)配方的标配,很多大语言模型也在用, 它让模型永远到不了「100% 确定」。CutMix 那篇还发现一件反直觉的事: Cutout 和 label smoothing 单独用都不涨点,一起用才涨。
| 手段 | 它做了什么 | 一行公式 | 典型强度 |
|---|---|---|---|
| 把所有参数一起压小(第 3 节那张圆的图) | λ·Σw² | 经典 1e-4 ~ 1e-2 AdamW 常用 0.01 ~ 0.1(PyTorch 默认 0.01) | |
| L1(Lasso) | 把一部分参数直接清零 = 自动筛特征(第 3 节那张菱形的图) | λ·Σ|w| | 1e-5 ~ 1e-3 |
这一行「典型强度」有一个最容易踩的坑:经典 L2 的 λ 和 AdamW 的 wd 不是一个口径。
λ 直接加在 loss 上,wd 作用在更新步骤里,所以 1e-4 和 0.1 看起来差一千倍,
其实说的是不同的事,两处不要直接比。《优化器谱系》那一章讲的就是这个「解耦」。
第一次上手:把惩罚写进 loss 那一栏(经典 L2)从 1e-4 或 1e-3 试起;
用 PyTorch 的优化器时它叫 weight_decay——AdamW 用上面那一栏 0.01 ~ 0.1(默认 0.01),
普通 SGD 仍接近经典那一栏。
| 手段 | 它做了什么 | 一行公式 | 典型强度 |
|---|---|---|---|
| 早停 | 验证误差一开始涨就停手。最省事的一招,也是性价比最高的 | — | 耐心 5 ~ 20 轮 |
| 训练时随机关掉一部分神经元,其余按 1/(1−p) 放大补回来 | h′ = h ⊙ m / (1−p) | 0.1 ~ 0.5(原论文 0.5) | |
| 随机深度 | 关的不是神经元,是整层。图像模型里的标配(也叫 stochastic depth) | — | 0 → 0.5(线性衰减) |
| 模型变小 | 参数少到背不下训练集,就只能学规律 | — | — |
第三类里只有 Dropout 那一行需要额外记一句:现在的大语言模型基本不用它了, GPT-2(2019 年发布的那个语言模型)之后的大部分模型都去掉了。理由和代价在第 6 节那张表里。这个坑是这一章最值得先知道的。 符号:h′ = 处理后的输出,h = 原来的输出,m = 随机掩码(0 或 1), ⊙ = 逐元素相乘,p = 关掉的比例。
真遇到过拟合,动手顺序是:先加数据 / 数据增强,再早停,最后才轮到权重衰减和 Dropout 这些惩罚项—— 越靠前越不牵动模型本身,试错成本越低。
现代配方通常确实同时开着三四个:数据增强 + 标签平滑 + 权重衰减 + 早停。 它们加起来也就改几行,不是「开得越多越好」——开越多,第 6 节那张表里的代价也一条条累上去。 Dropout 和权重衰减可以一起开:一个随机关神经元,一个把参数往 0 拉,各管一件事,不是重复开了一份。
① 加数据 /
互动 · 早停:什么时候该收手
互动 ·
变换不改变答案,就等于免费多出几倍数据。图像任务里最常用的一招。
上面几节讲的这套东西,是 2012 年前后成型的。它今天仍然管用, 但2017 年之后有两条实验结论,让它的地基松了一角。 不是说它错了,是说它的适用范围比教科书上写的窄。
两条让教科书需要重写一句的结论
| 它不成立的地方 | 什么时候真的会痛 | 怎么办 |
|---|---|---|
| 「参数小 = 更可能对」只是一个先验(动手之前就先认定的偏好),不是定律 | 训练集已经大到能把噪声平均掉时,这个先验帮不上什么忙 | 把 λ 调小或关掉,别默认它一定有用 |
| L1 在特征高度相关时不稳定 | 你想用它筛特征,可手上有几个几乎等价的特征 | 它会把其中的一个留下、其余清零,而留哪个基本是随机的,换个种子结论就变。要稳定的稀疏,考虑 Elastic Net 或先做特征聚类 |
| Dropout 在大模型里已经不划算了 | 你在训大语言模型(数据量远超参数量、基本只跑一轮) | 不加。GPT-2 之后的大部分模型去掉了它;它剩下的位置是小数据集、分类头、微调 |
| 早停要有独立的一份验证数据 | 数据本来就少,还要切一块出来 | 切出来的验证集太小,早停会停得太早或太晚。数据极少时,交叉验证比单次早停可靠 |
| 标签平滑是故意让模型「不敢确定」 | 你要的就是模型输出可信的概率(校准、置信度阈值) | 它会把预测压离 0 和 1。要么别用,要么在之后单独做一次校准 |
该开,结论没变——变的是理由。现在的理由是让训练更稳,不是「防过拟合」。
那这一章还有用吗?有,而且比任何时候都用得着,只是用法变了。
当年的说法是:过拟合 = 模型太复杂,正则化 = 把复杂度压下去。 今天更准的说法是:模型有能力记住任何东西,正则化是在「它想怎么记」这件事上做微调: 让它在众多能完美拟合的解里,挑一个更平稳、更不容易受噪声影响的。
所以这一章的实操结论不变(第 5 节那个顺序照旧), 变的是别再拿「降低容量」当解释。那句话在大模型上是错的。
这一章是整门课里第一条线第一次成为主角的地方。 它做的事很小:往损失函数上再加一项。但它背后的意思很大: 不去限制模型能学什么,只是让它更喜欢简单的解。
回到第 1 节:先把「模型复杂度」拖到 15,看曲线扭成一团、测试误差变高; 再把「正则化强度 λ」从 0 拉到 0.02,曲线被拉平,测试误差反而下降。 模型没有变小,只是选了一个更平稳的解——这就是「软偏好」。
| 线 | 为什么这章不是它 |
|---|---|
| ① 表达力 vs 泛化 | ✅ 这章的位置:模型并没有变小(表达力不变),但它在训练中偏向简单的解(泛化更好)。 这个张力就是这一章的全部主题 |
| ② 没有免费午餐 | 沾边——「参数小的解更可能对」确实是一个先验;但它的主场是后面那些架构章,不是这里的数值惩罚 |
| ④ 学习即压缩 | 沾边——「参数小 = 模型简单」和压缩是同一个直觉;但这里没有提表示或码长,只有一个惩罚项 |
| 暗线 | 这一章的回答 |
|---|---|
| A 信息流动 | 张量形状完全不变——正则项只往损失里加一个标量,不碰数据。
它改的是参数空间里的可行区域: L2 把解限制在一个球里,L1 把解限制在一个菱形里—— 第 3 节那张图上绿线碰到蓝圈的位置,就是这一步「流动」的结果 |
| B 什么被牺牲了 | 训练误差变大(故意让自己在训练集上变差),换来测试集上的误差——全课最早的一次「牺牲换泛化」。 L1 还额外牺牲了一样东西:「所有特征都保留」,因为它会把一部分权重直接清零 |
| C 参数账本 | 正则化自己 0 个参数,只多一个超参 λ;计算量增加极小(L2 要一次 Σw²,L1 要一次 Σ|w|,都是逐元素)。
但它改的是参数最终的取值:λ 从 1e-4 到 1e-2,Σw² 能差十几倍。 这里有个常见陷阱:经典 L2 的 λ(1e-4~1e-2)和 AdamW 的 wd=0.1 不是同一个口径, 一个是加在 loss 上、一个作用在更新步骤里,两处数字不能直接比 |
| D 跑在什么上 | 带宽受限,而且开销小到几乎可以忽略——所以它是全站最“免费”的一招。 贵的是 Dropout:训练时每一次前向都要重新抽一遍随机掩码, 还要多做一次乘除(inverted dropout 要除以 1−p)——在一张卡上,它常常比看起来贵。 完整的算术强度账在 《硬件与算力账本》 |
| E 它假设了什么 | 假设「参数小的解更可能是对的」,也就是「简单的规律更可能重复出现」。 这是最强的先验之一:数据少的时候它帮你,数据多到能把噪声平均掉的时候它帮不上什么忙。 Dropout 额外假设了一件事:「特征之间可以互相替代」——所以拿掉一个,其他的能顶上 |
| F 违背了哪个直觉 | 直觉是「训练时做得越好,测试上就越好」。正则化是故意让自己在训练集上做得更差——
而且这一步是必须的。 反过来那个让人不舒服的事实:训练误差最小的模型(把噪声也背下来)反而是最差的。 这也解释了为什么「训练 loss 还能降」不代表你应该接着训 |
它接住了《优化器谱系》的什么:那一章解决「怎么走下去」, 这一章解决「走到哪该停」。给参数系一根橡皮筋,多出一股把参数拉小的力和拟合数据拔河。
它给下一章留了什么:Dropout 那一节留了个没回答的问题—— 为什么同一个网络,train 和 eval 下的行为会不一样? 《归一化层》中段那两套训练/推理统计量,就是同一种形状的坑。
遇到过拟合,动手顺序是:先加数据,再早停,然后才轮到各种惩罚项。 它们背后在做的,是在众多能完美拟合的解里挑平稳的那个。 所以下次有人告诉你「加惩罚是为了降低模型容量」,你可以回一句: 那是 2012 年的说法——在大模型上,那个因果链已经断了。
上面讲的都是「够用」的版本。想往下挖,这里有三个入口—— 它们不是必修内容,是给想再往前走一步的读者准备的。