正则化:逼模型泛化的税


文档摘要

正则化:逼模型泛化的税 本节摘要:你的模型训练精度 99%、测试精度 60%——它在背书而非学习。正则化(Regularization)就是你强加在复杂度上的税,逼模型去泛化。参数足够多的神经网络能记住任何数据集——Zhang 等人 2017 年用标准网络在带随机标签的 ImageNet 上训练,达到接近零的训练损失,把一百万对毫无规律的输入输出背得一字不差,训练损失完美,测试精度为零。这就是过拟合,而且模型越大越严重:GPT-3 有 1750 亿参数、约 5000 亿 token 训练集,这容量足以逐字背下大量训练数据。没有正则化,它只会原样复述训练样本,学不到可泛化的模式。

正则化:逼模型泛化的税

本节摘要:你的模型训练精度 99%、测试精度 60%——它在背书而非学习。正则化(Regularization)就是你强加在复杂度上的税,逼模型去泛化。参数足够多的神经网络能记住任何数据集——Zhang 等人 2017 年用标准网络在带随机标签的 ImageNet 上训练,达到接近零的训练损失,把一百万对毫无规律的输入输出背得一字不差,训练损失完美,测试精度为零。这就是过拟合,而且模型越大越严重:GPT-3 有 1750 亿参数、约 5000 亿 token 训练集,这容量足以逐字背下大量训练数据。没有正则化,它只会原样复述训练样本,学不到可泛化的模式。训练与测试表现之间的鸿沟就是过拟合缝隙,本节的每一招都从不同角度攻击它:Dropout 强迫网络不依赖单个神经元,权重衰减防止单个权重过大,BatchNorm 平滑损失面让优化器找到更平、更泛化的最小,LayerNorm 在 BatchNorm 失效处(小 batch、变长序列)顶上,RMSNorm 省掉均值计算快 10%。每招都简单,合在一起就是「背书的模型」与「泛化的模型」之间的分野。本节从零实现 dropout、L2 权重衰减、BatchNorm、LayerNorm、RMSNorm,讲清 train/eval 模式切换的玄机,给出按过拟合严重度选正则策略的决策图。

学习目标

阅读完本节,你应当能够:

  1. 从零实现带反向缩放的 dropout、L2 权重衰减、BatchNorm、LayerNorm、RMSNorm。
  2. 测量训练-测试精度缝隙,用正则化实验诊断过拟合
  3. 解释 Transformer 为何用 LayerNorm 而非 BatchNorm,以及现代 LLM 为何偏爱 RMSNorm
  4. 根据过拟合严重度应用正确的正则化组合

一、问题与直觉

参数够多的神经网络能记住任何数据集。这不是假设——Zhang 等人(2017)用标准网络在带随机标签的 ImageNet 上训练,网络在完全随机的标签分配上达到接近零的训练损失,把一百万对毫无规律的输入输出背得一字不差。训练损失完美,测试精度为零。

这就是过拟合,而且模型越大越糟。GPT-3 有 1750 亿参数、训练集约 5000 亿 token,这容量足以逐字背下大量训练数据,没有正则化它只会原样复述,学不到可泛化的模式。

训练表现与测试表现之间的缝隙就是过拟合缝隙。本节的每一招都从不同角度攻击它:Dropout 强迫网络不依赖单个神经元,权重衰减防止单个权重过大,BatchNorm 平滑损失面让优化器找到更平、更泛化的最小,LayerNorm 在 BatchNorm 失效处顶上,RMSNorm 省掉均值计算快 10%。每招都简单,合在一起就是「背书的模型」与「泛化的模型」之间的分野。

过拟合谱

每个模型都处在从欠拟合(太简单抓不住模式)到过拟合(太复杂连噪声都抓)的谱上,甜蜜点在中间,正则化把模型从过拟合一侧推向中间。

Dropout

最简单且解释最优雅的正则化。训练时,以概率 p 把每个神经元的输出置零。

output = activation(z) * mask 其中 mask[i] ~ Bernoulli(1 - p)

p = 0.5 时每次前向传播一半神经元被置零,网络必须学冗余表示,因为它无法预测哪些神经元可用。这防止「协同适应」——神经元学会依赖特定其它神经元在场。

集成解释:N 个神经元的网络配 dropout 会产生 2^N 个可能的子网络(每个神经元开关的组合),训练时近似同时训练所有 2^N 个子网络、各看不同小批量。测试时用全部神经元(不 dropout)并把输出乘 (1 − p) 以匹配训练期望值,这等价于对 2^N 个子网络的预测取平均——用一个模型得到一个巨型集成。

实践中缩放在训练时而非测试时做(反向 dropout):

训练时: output = activation(z) * mask / (1 - p) 测试时: output = activation(z) (无需改动)

更干净,因为测试代码完全不用知道 dropout。默认比率:Transformer p = 0.1,MLP p = 0.5,CNN p = 0.2~0.3。dropout 越强 = 正则越强 = 欠拟合风险越大。

权重衰减(L2 正则化)

把所有权重的平方和加进损失:

total_loss = task_loss + (lambda / 2) * sum(w_i^2)

正则项梯度是 lambda × w,这意味着每步每个权重都按其幅度比例向零收缩,大权重罚得更重,模型被推向没有单个权重主导的解。这有助泛化:过拟合模型往往有大权重放大训练噪声,权重衰减保持小权重,限制有效容量,迫使模型依赖鲁棒、可泛化的特征而非背下的怪癖。lambda 控制强度,典型值:AdamW 训 Transformer 用 0.01,SGD 训 CNN 用 1e-4,严重过拟合模型用 0.1。如第 06 节所述,权重衰减与 L2 在 SGD 中等价、在 Adam 中不等价,用 Adam 时务必用 AdamW(解耦权重衰减)。

批归一化(Batch Normalization)

在每层输出送入下一层前,按小批量做归一化。

mu = (1/B) * sum(x_i) (批均值) sigma^2 = (1/B) * sum((x_i - mu)^2) (批方差) x_hat = (x_i - mu) / sqrt(sigma^2 + eps) (归一化) y = gamma * x_hat + beta (缩放平移)

gamma、beta 是可学习参数,允许网络在最优时撤销归一化。没有它们,你就强迫每层输出零均值单位方差,未必是网络想要的。

训练 vs 推理的分裂:训练时 mu、sigma 来自当前小批量;推理时用训练期间累积的滑动平均(动量 0.1,即 90% 旧 + 10% 新)。BatchNorm 为何有效至今仍有争议:原论文说它减少「内部协变量偏移」(层输入分布随早期层更新而变),Santurkar 等人(2018)证明这个解释错了。真实原因是 BatchNorm 让损失面更光滑——梯度更可预测、Lipschitz 常数更小,优化器能安全地迈更大步,这就是 BatchNorm 让你能用更高学习率、更快收敛的缘由。

BatchNorm 有根本限制:它依赖批统计。batch=1 时均值方差无意义;batch 小(< 32)时统计噪声大、伤性能。这对目标检测(显存限制 batch)和语言建模(序列长度可变)很要命。

层归一化(Layer Normalization)

按特征而非按批归一化。对单个样本:

mu = (1/D) * sum(x_j) (特征均值) sigma^2 = (1/D) * sum((x_j - mu)^2) (特征方差) x_hat = (x_j - mu) / sqrt(sigma^2 + eps) y = gamma * x_hat + beta

D 是特征维。每个样本独立归一化,不依赖 batch 大小,这正是 Transformer 用 LayerNorm 而非 BatchNorm 的原因:序列长度可变、batch 经常很小(生成时甚至是 1)、训练与推理计算完全一致。Transformer 里 LayerNorm 加在每个自注意力块和每个前馈块之后(Post-LN),或加在它们之前(Pre-LN,训练更稳)。

RMSNorm

去掉均值减法的 LayerNorm,由 Zhang 与 Sennrich(2019)提出。

rms = sqrt((1/D) * sum(x_j^2)) y = gamma * x / rms

仅此而已。没有均值计算、没有 beta 参数。观察发现:LayerNorm 里的再居中(减均值)对模型性能贡献很小,却要算力。去掉它,同等精度、约 10% 更少开销。LLaMA、LLaMA 2/3、Mistral 及多数现代 LLM 用 RMSNorm 取代 LayerNorm——在数十亿参数、数万亿 token 的规模下,这 10% 的节省相当可观。

归一化对比

数据增强也是一种正则化

它不改模型而改数据:保持标签的同时变换训练输入——图像(随机裁剪、翻转、旋转、颜色抖动、cutout)、文本(同义词替换、回译、随机删除)、音频(时间拉伸、音高平移、加噪)。效果与正则化相同:增大训练集有效规模,让模型更难背具体样本。只见过一次原图的模型能背下它,见过 50 种增强版的模型被迫学不变结构。

早停

最简正则器:验证损失开始上升就停训,那时模型还没过拟合。实践中每轮记验证损失、存最佳模型、继续训一个「耐心」窗口(典型 5~20 轮),窗口内验证损失不改善就停,加载存的最好模型。

何时用哪招

二、从零实现

完整代码见原课程 phases/03-deep-learning-core/07-regularization/code/ 相应文件。

Step 1:Dropout(训练与评估模式)

import random class Dropout: def __init__(self, p=0.5): self.p = p self.training = True self.mask = None def forward(self, x): if not self.training: return list(x) self.mask = [] output = [] for val in x: if random.random() < self.p: self.mask.append(0) output.append(0.0) else: self.mask.append(1) output.append(val / (1 - self.p)) # 反向 dropout 缩放 return output def backward(self, grad_output): return [g / (1 - self.p) if m else 0.0 for g, m in zip(grad_output, self.mask)]

反向 dropout 的精髓:训练时除以 (1 − p),测试时原样输出,测试代码无需感知 dropout。

Step 2:L2 权重衰减

def l2_regularization(weights, lambda_reg): penalty = sum(w * w for w in weights) return lambda_reg * 0.5 * penalty def l2_gradient(weights, lambda_reg): return [lambda_reg * w for w in weights]

Step 3:批归一化

维护批统计与推理用的滑动统计,带可学习 gamma/beta。训练时按当前批归一化并更新滑动均值/方差,推理时用滑动统计。

Step 4:层归一化

按样本特征维归一化,带可学习 gamma/beta,与 batch 大小无关,训练推理一致。

Step 5:RMSNorm

class RMSNorm: def __init__(self, num_features, eps=1e-6): self.gamma = [1.0] * num_features self.eps = eps self.num_features = num_features def forward(self, x): rms = math.sqrt(sum(xi * xi for xi in x) / len(x) + self.eps) return [self.gamma[j] * x[j] / rms for j in range(self.num_features)]

Step 6:有/无正则的训练对比

在圆形数据上分训练/测试集,比较无正则 vs dropout vs dropout+权重衰减时,训练-测试精度缝隙如何变化。正则越强,缝隙越小,但训练精度也会降——找到甜蜜点是工程的核心。

三、框架对比

PyTorch 把全部归一化与正则化做成模块:

import torch import torch.nn as nn model = nn.Sequential( nn.Linear(784, 256), nn.BatchNorm1d(256), nn.ReLU(), nn.Dropout(0.3), nn.Linear(256, 128), nn.BatchNorm1d(128), nn.ReLU(), nn.Dropout(0.3), nn.Linear(128, 10), ) model.train() out_train = model(torch.randn(32, 784)) model.eval() out_test = model(torch.randn(1, 784))

model.train() / model.eval() 切换至关重要:它开关 dropout,并告诉 BatchNorm 用批统计还是滑动统计。推理前忘了 model.eval() 是深度学习里最常见的 bug 之一——测试精度会随机波动,因为 dropout 还开着、BatchNorm 还在用小批量统计。

Transformer 的模式则不同:用 LayerNorm 而非 BatchNorm,dropout p=0.1 而非 0.5,这是 Transformer 的默认值。

四、可复用产物

本节产出(位于原课程 outputs/):

  • prompt-regularization-advisor.md:一个提示,诊断过拟合并推荐正确的正则化策略。

五、练习

  1. Easy:实现 2D 数据的空间 dropout——不丢单个神经元,丢整条特征通道(把连续特征组视为通道,整组丢)。在 hidden_size=32 的圆形数据上与标准 dropout 比较训练-测试缝隙。
  2. Medium:把第 05 节的标签平滑与本节的 dropout 组合。四种配置(都不用、只用 dropout、只用标签平滑、两者都用)各测最终训练-测试精度缝隙,哪种组合缝隙最小?
  3. Hard:在圆形数据网络的隐藏层与激活之间加 BatchNorm,分别在 lr=0.01、0.05、0.1 训练。BatchNorm 应当能在原始网络发散的高学习率下稳定训练。

本节要点回顾

  1. 参数够多就能背任何数据集:Zhang 等人证明网络能把随机标签背到零训练损失、零测试精度,过拟合随模型变大而加重。
  2. 正则化是强加在复杂度上的税:每招从不同角度攻击训练-测试缝隙。
  3. Dropout 等价于巨型集成:N 个神经元产生 2^N 个子网络,反向 dropout 让测试代码无需感知它。
  4. 权重衰减保持小权重:限制有效容量,逼模型依赖鲁棒特征而非背下的怪癖;用 Adam 时务必用 AdamW(解耦衰减)。
  5. BatchNorm 让损失面更光滑:真实原因不是「减少内部协变量偏移」,而是梯度更可预测、可用更高学习率;但依赖批统计,batch 小就失效。
  6. LayerNorm 按特征归一化、与 batch 无关:这正是 Transformer 用它的原因——序列长度可变、batch 经常是 1、训练推理一致。
  7. RMSNorm 去掉均值减法:同等精度、快 10%,LLaMA/Mistral 等现代 LLM 的标配。
  8. 数据增强与早停也是正则:前者增大有效训练集,后者最简单——验证损失不降就停。
  9. 推理前必须 model.eval():忘了它是测试精度随机波动的头号原因。

下一节,我们讲权重初始化——初始化错了训练压根起不来,初始化对了 50 层能像 3 层一样顺。


发布者: 作者: Rohit Gupta 转发
评论区 (0)
U