正则化与防过拟合
过拟合(Overfitting)是深度学习最常见的敌人——模型在训练集上表现极好,却无法泛化到新数据。正则化(Regularization)是一切抑制过拟合手段的统称。本页系统讲解 L1/L2 正则、Dropout、各种归一化方法、Early Stopping,以及近年来在 LLM 和视觉模型中涌现的新正则化手段。前置阅读:梯度下降与优化器、损失函数、模型评估。
把过拟合想象成”学生背答案”——模型不是在学规律,而是在死记训练集的每个细节。正则化就是各种”防止死记”的手段:
- L1 / L2 正则= 给权重加”节俭税”。L2(权重衰减)让权重普遍偏小、不依赖少数特征;L1 更激进,直接把不重要的权重压到零(特征选择)。像要求学生用简洁的规则答题,而不是逐题硬背。
- Dropout= 随机让一部分神经元”闭嘴”。每次训练只用部分神经元,迫使网络不过度依赖任何单个神经元——像团队里随机缺人,逼每个人都掌握全流程。
- Batch Normalization= 每层之间把激活值”拉回标准范围”。让每层面对的数据分布稳定,可以使用更大的学习率、加速收敛,同时有轻微正则化效果。
- Layer Normalization / RMSNorm= Transformer 的标配。沿特征维度归一化(每个样本独立),不依赖 batch 大小,适合序列模型。RMSNorm 是 LN 的简化版,去掉均值减法、只做方差归一化,在 LLaMA / Mistral / Qwen 等现代 LLM 中已基本取代了标准 LN。
- DropPath(Stochastic Depth)= 训练时随机跳过整个残差块——可以理解为”层次化 Dropout”。在 ResNet、EfficientNet、ViT 及现代 LLM 深度扩展中广泛使用。
- Early Stopping= 见好就收。验证集性能不再提升就停训,防止训练过头开始”背答案”。
过拟合的数学刻画
Section titled “过拟合的数学刻画”在正式介绍各方法之前,先用一段简单的数学刻画”过拟合”到底是什么。设模型有 个参数 ,训练数据集 上经验风险(empirical risk,即平均损失)为:
我们真正关心的是期望风险 ,但无法直接计算。当模型容量(capacity,即拟合复杂函数的能力)过大时,优化器可以把 压到极低、但 却很高——这就是过拟合。正则化的本质就是在 上加一个”偏好项”,阻止 走向那些只在训练集上好使的极端值。
L1 / L2 正则化
Section titled “L1 / L2 正则化”在损失函数上额外加一个对权重的惩罚项:
是正则强度超参数(hyperparameter,即需要人为设定、模型不自己学习的参数)。L2 使所有权重趋于较小值(但不会精确为零),防止单个权重过大;L1 产生稀疏解(部分权重精确为零),可用于特征选择。
为什么 L1 产生稀疏解?一个直观推导
Section titled “为什么 L1 产生稀疏解?一个直观推导”L2 的梯度是 ,权重离零越近、梯度越小,因此权重会”温柔地”逼近零但几乎不会精确为零。L1 的次梯度(subgradient,不可导点处导数的推广)是 ,这是一个与 大小无关的常数推力——不管 是 0.01 还是 100,它都以同样大小的力被推向零,所以很容易精确越过零点停在那里。用图理解:L2 罚项的等值线是圆,L1 是菱形,菱形的尖角正好卡在坐标轴上,优化轨迹更容易在尖角处与数据损失相切,从而让某些权重精确为零。
权重衰减与 AdamW 的关系
Section titled “权重衰减与 AdamW 的关系”在深度学习中,L2 正则通常以”权重衰减”(weight decay)的形式实现——在每次参数更新后额外乘以 :
# 原始 SGD + L2 正则的等价形式w <- w - lr * (∂L/∂w + λ * w) = w - lr * ∂L/∂w - lr * λ * w = (1 - lr * λ) * w - lr * ∂L/∂w但当优化器是 Adam(自适应方法)时,把 加到梯度里会被分母的自适应缩放”扭曲”,导致正则强度不稳定。AdamW 与 Adam 的关键区别就是将权重衰减从梯度中解耦:先按 Adam 更新参数,再独立执行 。研究表明这一解耦在 LLM 预训练中能显著改善泛化(详见梯度下降与优化器)。
Dropout
Section titled “Dropout”训练时以概率 (如 0.5)随机将部分神经元的输出置零,推理时不 dropout 但将输出乘以 (PyTorch 的 nn.Dropout 内部自动处理这个缩放):
从贝叶斯视角看,Dropout 等价于训练一个指数级数量的子网络的集成(ensemble,把多个模型的预测取平均),每个子网络只看到部分神经元。它打断了神经元的”共适应”(co-adaptation,即多个神经元相互依赖才能工作),迫使每个神经元独立学到有用的特征。Dropout 在全连接层中效果最显著,CNN 中通常用更小的 (如 0.1)或改用空间 Dropout(整张特征图一起丢)。
DropPath / Stochastic Depth
Section titled “DropPath / Stochastic Depth”DropPath(又称 Stochastic Depth)是 Dropout 的”残差块版本”:训练时以概率 整个跳过第 个残差块,直接走捷径(shortcut)连接。浅层 小、深层 大(线性递增)。它本质上训练了一个”随机深度的网络”,推理时用完整深度。DropPath 在 ResNet-152、EfficientNet、ViT(Vision Transformer)和现代 LLM 中已成为标配正则化手段,让训练更深的网络而不严重过拟合成为可能。
Batch Normalization(BN)
Section titled “Batch Normalization(BN)”对每个 mini-batch 内的每个通道,沿 batch 和空间维度计算均值和方差,然后用学习参数 (缩放)和 (平移)做归一化:
训练时使用当前 batch 的统计量,同时用指数移动平均(EMA,Exponential Moving Average——一种用衰减系数累积历史值的滑动平均方法)累积全局的 running mean / running var。推理时使用累积的 running statistics 而非当前 batch 统计量——这一点极其重要,否则在 batch=1 的推理场景下 BN 会崩溃。BN 的正则化效果来自 batch 内统计量的随机性(每个 batch 的均值方差略有不同,相当于注入噪声)。BN 使得可以使用更大的学习率、加速 2-10 倍收敛。
关于”内部协变量偏移”的重新认识
Section titled “关于”内部协变量偏移”的重新认识”BN 原论文标题中的”Internal Covariate Shift”(内部协变量偏移——训练中每层输入分布随参数更新而漂移)曾被认为就是 BN 奏效的原因。但 2018 年 Santurkar 等人的研究「How Does Batch Normalization Help Optimization?」指出:BN 有效的真正原因是它让损失曲面(loss landscape)更平滑、优化轨迹更稳定,而与是否消除分布漂移关系不大。这一认知修正也解释了为什么即使不做归一化、只用类似 BN 的噪声注入也能获得部分收益。
Layer Normalization(LN)
Section titled “Layer Normalization(LN)”与 BN 不同,LN 对单个样本的所有特征维度做归一化,不涉及 batch 维度:
LN 不依赖 batch 大小,在 batch=1(在线推理、RNN 时间步)时也能正常工作。Transformer 必须用 LN:序列长度可变、batch 内不同样本的语义维度需要统一归一化。LN 没有 running statistics,训练和推理行为一致。
RMSNorm:现代 LLM 的新标配
Section titled “RMSNorm:现代 LLM 的新标配”Root Mean Square Normalization(RMSNorm)是 LN 的简化版本,由 Zhang & Sennrich 在 2019 年提出,近年在 LLM 中几乎全面取代了标准 LN:
相比 LN,RMSNorm 省去了均值减法,计算量减少约 7-64%(取决于实现),而且在经验上泛化效果与 LN 相当甚至更好。LLaMA、Mistral、Qwen、DeepSeek 等主流开源 LLM 全部采用 RMSNorm。直觉上:在 Transformer 的 pre-norm 架构里,激活值基本已居中、减均值的信息量很小,去掉它不仅更便宜、还减少了不必要的偏移。
QK-Norm:稳定大模型注意力
Section titled “QK-Norm:稳定大模型注意力”2024 年以来,随着模型规模扩展到数十乃至数百 B(billion)参数,注意力分数的 logits 数值爆炸导致训练不稳定。QK-Norm 在计算注意力分数前对 Query 和 Key 各做一次 RMSNorm(或 LN):
Google 的 Gemma 2、多家研究型大模型都已引入 QK-Norm。它本质上是一种”对注意力分数的正则化”——把 Q、K 限制在合理的数值范围内,避免 softmax 被极值主导。这是 BN/LN 之外、归一化思想在注意力机制内部的新应用。
Group Normalization / Instance Normalization
Section titled “Group Normalization / Instance Normalization”- Group Normalization(GN):将通道分成 G 组,每组内做归一化(介于 LN 和 IN 之间)。在 batch 极小(如目标检测 batch=1 或 2)时 BN 统计量不稳定,GN 是理想的替代方案。
- Instance Normalization(IN):每个样本的每个通道独立归一化(相当于 GN 中 G = 通道数)。广泛用于风格迁移(AdaIN——Adaptive Instance Normalization,自适应实例归一化),因为它能剥离每个样本的风格信息(均值/方差)而保留内容。
Early Stopping 与数据增强
Section titled “Early Stopping 与数据增强”- Early Stopping:在每个 epoch 结束后评估验证集损失,如果连续 N 个 epoch(patience,耐心值)验证损失不再下降(或开始上升),就停止训练。这是最简单、最安全的正则化手段——几乎无代价。直觉上,训练初期学到的通常是泛化性强的”粗粒度”特征,后期才开始”背答案”,提前打断就保留了这些好的特征。
- 数据增强:通过对训练数据做随机变换(翻转、裁剪、颜色抖动等),等效于扩充数据集、降低过拟合。数据增强本身是一种隐式正则化,详见数据增强。在 LLM 领域,2024 年流行的 Mixup / CutMix(把不同样本的输入或标签做线性插值)也是一种隐式正则。
Sharpness-Aware Minimization(SAM)
Section titled “Sharpness-Aware Minimization(SAM)”SAM(锐度感知最小化)是 2020 年提出、近年在视觉与 LLM 微调中流行的一类通过优化器实现正则化的方法。核心思想:与其找让训练损失最低的最小值,不如找一个”平缓的”最小值——因为越平缓的最小值越能容忍数据分布的小扰动、泛化越好。SAM 在每步先用常规梯度走一步到”邻域点”,再在该点求梯度作为本步真实更新方向:
# SAM 伪代码(First-order Sharpness-Aware Minimization)w_adv = w + rho * normalize(grad_L(w)) # 在当前权重附近找"最坏扰动"grad_sam = grad_L(w_adv) # 在扰动点计算真实更新梯度w <- w - lr * grad_sam # 用该梯度更新代价是每步要算两次前向 + 反向,但经验上泛化提升明显,尤其在数据量有限时。
BN vs LN vs RMSNorm:在 N×C×H×W 张量上的归一化维度
Section titled “BN vs LN vs RMSNorm:在 N×C×H×W 张量上的归一化维度”一个 batch 的图像特征张量形状为 (N, C, H, W):N=batch 大小、C=通道数、H×W=空间分辨率。BN 和 LN 的根本区别在于”沿哪个轴计算均值方差”:
防过拟合手段谱系
Section titled “防过拟合手段谱系”PyTorch 中 BN / LN / Dropout 的用法
Section titled “PyTorch 中 BN / LN / Dropout 的用法”import torchimport torch.nn as nn
# --- BatchNorm2d:用于 CNN,对每个通道归一化 ---bn = nn.BatchNorm2d(num_features=64) # 64 个通道x = torch.randn(16, 64, 32, 32) # batch=16 的特征图out = bn(x) # 训练时用 batch 统计量
# --- LayerNorm:用于 Transformer,对特征维度归一化 ---ln = nn.LayerNorm(normalized_shape=512) # 特征维度为 512x_seq = torch.randn(8, 10, 512) # batch=8, 序列长度=10, 维度=512out = ln(x_seq) # 每个样本独立归一化
# --- Dropout:训练时随机失活,推理时自动关闭 ---dropout = nn.Dropout(p=0.5)x_fc = torch.randn(16, 256)model = nn.Sequential(nn.Linear(256, 128), nn.ReLU(), dropout, nn.Linear(128, 10))model.train() # 训练模式:Dropout 生效,BN 用 batch 统计量model.eval() # 推理模式:Dropout 关闭,BN 用 running statisticsprint("切换到 eval 模式后,BN 使用累积的 running 均值/方差")从零实现 RMSNorm(理解 LLaMA 系列的归一化)
Section titled “从零实现 RMSNorm(理解 LLaMA 系列的归一化)”import torchimport torch.nn as nn
class RMSNorm(nn.Module): """Root Mean Square Normalization —— LLaMA / Mistral / Qwen 等现代 LLM 的标配。 与 LayerNorm 相比省去了均值减法,只做方差归一化,计算更轻、效果相当。"""
def __init__(self, dim: int, eps: float = 1e-6): super().__init__() self.eps = eps # 防止除零的小常数 self.weight = nn.Parameter(torch.ones(dim)) # 可学习的缩放参数 γ
def forward(self, x: torch.Tensor) -> torch.Tensor: # 计算均方根 RMS = sqrt(mean(x²) + eps) # keepdim=True 让广播形状自动对齐 rms = torch.sqrt(x.pow(2).mean(dim=-1, keepdim=True) + self.eps) # 用 RMS 归一化,再用 γ 缩放 return self.weight * x / rms
# 使用示例:对一个 (batch=4, seq=16, dim=512) 的序列做 RMSNormrms_norm = RMSNorm(dim=512)x = torch.randn(4, 16, 512)out = rms_norm(x)print(f"输入 shape={tuple(x.shape)},输出 shape={tuple(out.shape)}")print(f"归一化后每位置的 RMS ≈ 1.0,实际 = {out.pow(2).mean(dim=-1).sqrt().mean().item():.4f}")从零实现 Dropout(理解”反向缩放”技巧)
Section titled “从零实现 Dropout(理解”反向缩放”技巧)”import torch
def dropout(x: torch.Tensor, p: float = 0.5, training: bool = True) -> torch.Tensor: """Dropout 的朴素实现:训练时随机置零、推理时不操作。 关键细节是"反向缩放"——保留的神经元乘以 1/(1-p),使整体期望值不变。""" if not training or p == 0.0: return x # 生成 dropout 掩码:每个位置以 (1-p) 的概率保留 mask = (torch.rand_like(x) > p).float() # 重要:乘以 1/(1-p) 保持期望,使推理时无需再缩放 return x * mask / (1.0 - p)
# 演示torch.manual_seed(0)x = torch.ones(10000) # 一万个 1y_train = dropout(x, p=0.3, training=True)print(f"训练模式均值 ≈ 1.0(反向缩放生效): {y_train.mean().item():.4f}")print(f"训练模式约 30% 被置零: {(y_train == 0).float().mean().item():.4f}")y_eval = dropout(x, p=0.3, training=False)print(f"推理模式原样输出: {y_eval.mean().item():.4f}")L2 正则(权重衰减)的配置
Section titled “L2 正则(权重衰减)的配置”import torch
# 方式一:在优化器中设置 weight_decay(等价于 L2 正则)optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=0.01)
# 方式二:AdamW(推荐)——权重衰减与梯度解耦,比 Adam+weight_decay 更有效# 训练循环中无需额外操作,优化器自动处理
# 查看权重衰减效果:每步后参数被乘以 (1 - lr * wd)for group in optimizer.param_groups: print(f"当前 weight_decay = {group['weight_decay']}") # 0.01DropPath / Stochastic Depth 的实现
Section titled “DropPath / Stochastic Depth 的实现”import torchimport torch.nn as nn
class DropPath(nn.Module): """Stochastic Depth:训练时以概率 drop_prob 整块跳过该残差块。 等价于层次化 Dropout——把"丢神经元"扩展为"丢整层"。"""
def __init__(self, drop_prob: float = 0.0): super().__init__() self.drop_prob = drop_prob
def forward(self, x: torch.Tensor) -> torch.Tensor: if self.drop_prob == 0.0 or not self.training: return x # 推理时不丢弃,用完整深度 keep_prob = 1.0 - self.drop_prob # 对 batch 中每个样本独立决定是否跳过(shape 巧妙广播) shape = (x.shape[0],) + (1,) * (x.ndim - 1) mask = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device) mask = torch.floor(mask) # 0 或 1 return x.div(keep_prob) * mask # 反向缩放,保持期望
# 典型用法:在一个 ResNet 残差块里包裹残差分支class ResBlock(nn.Module): def __init__(self, dim, drop_path_prob=0.1): super().__init__() self.conv1 = nn.Conv2d(dim, dim, 3, padding=1) self.conv2 = nn.Conv2d(dim, dim, 3, padding=1) self.drop_path = DropPath(drop_path_prob)
def forward(self, x): residual = x out = torch.relu(self.conv1(x)) out = self.conv2(out) # 训练时有 drop_path_prob 概率整块跳过,直接走捷径 out = self.drop_path(out) return x + out # 残差连接- BN 推理时务必切换到 eval 模式:
model.eval()让 BN 使用累积的 running statistics。如果推理时还在 train 模式,BN 会用当前 batch 的统计量——batch=1 时方差为零,输出全是 NaN。这是新手最常见的 bug。 - Transformer / LLM 用 LN 或 RMSNorm,不能用 BN:序列长度可变、batch 内不同样本的特征语义不同,LN / RMSNorm 对每个样本独立归一化才合理。GPT/BERT 用 LN,LLaMA/Mistral/Qwen/DeepSeek 用 RMSNorm。
- Dropout 的 p 值视层而定:全连接层常用 0.3-0.5,CNN 中用 0.1 或空间 Dropout,Transformer 注意力权重用 0.1。过高的 p 会欠拟合。现代 LLM 倾向于降低或取消 Dropout,改用更多数据 + 权重衰减来正则。
- DropPath 的率要随深度递增:浅层 p 小(如 0.1),深层 p 大(如 0.5)。ViT-Base 整体平均约 0.1,ViT-Large 约 0.2。
- 权重衰减的典型值:AdamW 用 0.01-0.1,SGD 在图像分类中用 1e-4。大语言模型预训练通常用 0.1,微调时常用 0.01-0.1。
- 小 batch 不要用 BN:batch < 8 时 BN 的统计量噪声太大,改用 Group Normalization(GN)或 Layer Normalization(LN)。目标检测中 batch=1 或 2 时常用 GN。
- Early Stopping 几乎无副作用:设一个 patience(如 5-10 个 epoch),验证集不降就停。配合学习率衰减效果更好。
- 先确保不过拟合再调正则:如果训练集准确率都不高(欠拟合),加正则只会更差。正则化是用来解决”训练好但验证差”的问题。
- 大模型训练关注 QK-Norm:当模型规模扩展到数十 B 参数时,注意力 logits 容易数值爆炸导致训练发散,在 Q、K 上加 RMSNorm(即 QK-Norm)是 2024 年以来验证有效的稳定手段。
- CNN 图像分类:ResNet 等 Standard 架构用 BN + 权重衰减,全连接层加 Dropout。详见CNN 卷积神经网络。
- Transformer / LLM:GPT/BERT 用 LN,LLaMA/Mistral/Qwen/DeepSeek 用 RMSNorm + Dropout(注意力权重 0.1)+ 权重衰减(AdamW 0.1)。超大规模模型还会加 QK-Norm。详见Transformer 架构。
- 目标检测:batch 较小时用 Group Normalization 替代 BN。详见目标检测与 YOLO。
- 风格迁移:Instance Normalization 分离风格信息。详见图像分割。
- 大语言模型预训练:GPT / LLaMA 用 AdamW(weight_decay=0.1)+ Dropout + RMSNorm。详见语言模型演进。
- ViT / 大视觉模型:用 LN + DropPath + 权重衰减。DropPath 是训练百层以上视觉 Transformer 的关键正则手段。
典型类库与工具
Section titled “典型类库与工具”| 类库 | 语言 | 说明 |
|---|---|---|
| torch.nn | Python | PyTorch 归一化与正则化模块:BatchNorm1d/2d/3d、LayerNorm、GroupNorm、InstanceNorm、Dropout、RMSNorm(需自定义或用新版) |
| torch.optim | Python | 优化器中的 weight_decay 参数实现 L2 正则 / AdamW 权重衰减 |
| timm | Python | PyTorch Image Models 库提供 DropPath、RMSNorm 等现代正则化实现 |
| tf.keras.layers | Python | TensorFlow / Keras 的对应层:BatchNormalization、Dropout、ActivityRegularizer、LayerNormalization |
| torchvision | Python | 提供 DropPath(Stochastic Depth)等现代正则化手段 |
| sam-pytorch | Python | Sharpness-Aware Minimization(SAM)优化器的社区实现 |
| 术语 | 英文 | 解释 |
|---|---|---|
| 正则化 | Regularization | 一切抑制过拟合、提升泛化能力的手段的统称 |
| 过拟合 | Overfitting | 模型在训练集上表现好但无法泛化到新数据 |
| 权重衰减 | Weight Decay | L2 正则的实现形式,每次更新后权重乘以略小于 1 的系数 |
| L1 正则 | L1 / Lasso | 损失函数加权重绝对值之和,产生稀疏解,可用于特征选择 |
| Dropout | Dropout | 训练时随机将部分神经元输出置零,防止神经元过度共适应 |
| DropPath | Stochastic Depth | Dropout 的层次化版本,训练时随机跳过整个残差块 |
| 批归一化 | Batch Normalization (BN) | 对每个 batch 内的通道做归一化,加速训练、允许更大学习率 |
| 层归一化 | Layer Normalization (LN) | 对单样本的所有特征维度归一化,不依赖 batch 大小,Transformer 标配 |
| RMS 归一化 | RMSNorm | LN 的简化版,只做方差归一化、不减均值,LLaMA 等 LLM 标配 |
| QK-Norm | Query-Key Normalization | 对注意力中的 Query / Key 做归一化,防止大模型训练数值爆炸 |
| 组归一化 | Group Normalization (GN) | 将通道分组归一化,适用于小 batch 场景(如目标检测) |
| 实例归一化 | Instance Normalization (IN) | 每样本每通道独立归一化,广泛用于风格迁移 |
| 早停 | Early Stopping | 验证集性能不再提升时停止训练,最简单的正则化手段 |
| 内部协变量偏移 | Internal Covariate Shift | 训练中每层输入分布随参数更新而变化,BN 最初旨在缓解此问题(后被重新认识) |
| 锐度感知最小化 | Sharpness-Aware Minimization (SAM) | 通过寻找平缓的最小值来提升泛化的一类优化器正则方法 |
- Srivastava et al.,「Dropout: A Simple Way to Prevent Neural Networks from Overfitting」(JMLR 2014):Dropout 原始论文,随机失活神经元防止共适应,引用量极高。
- Ioffe & Szegedy,「Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift」(ICML 2015):BN 的开创性论文,使训练速度提升数倍,深刻改变了深度网络训练方式。
- Santurkar et al.,「How Does Batch Normalization Help Optimization?」(NeurIPS 2018):重要修正性研究,指出 BN 奏效主因是平滑损失曲面而非消除分布漂移。
- Ba et al.,「Layer Normalization」(2016):Layer Normalization 论文,为 Transformer 的归一化方案奠定基础。
- Zhang & Sennrich,「Root Mean Square Layer Normalization」(NeurIPS 2019):RMSNorm 论文,简化 LN,成为 LLaMA / Mistral / Qwen 等现代 LLM 的事实标准。
- Wu & He,「Group Normalization」(ECCV 2018):GN 论文,解决小 batch 场景下 BN 统计量不稳定的问题。
- Huang et al.,「Deep Networks with Stochastic Depth」(ECCV 2016):Stochastic Depth / DropPath 论文,让训练极深网络成为可能。
- Loshchilov & Hutter,「Decoupled Weight Decay Regularization」(ICLR 2019):AdamW 论文,指出 L2 正则与权重衰减在自适应优化器中不等价并提出解耦方案。
- Foret et al.,「Sharpness-Aware Minimization for Efficiently Improving Generalization」(ICLR 2021):SAM 论文,提出寻找平缓最小值以提升泛化。
- Henry et al.,「Query-Key Normalization for Transformers」(2020/2024 系列实践):QK-Norm 在大规模模型训练中的稳定效果,被 Gemma 2 等模型采用。
- LLaMA Technical Report (Meta, 2023-) / Qwen Technical Report (Alibaba, 2024):现代 LLM 工程报告,可一窥 RMSNorm + 权重衰减 + Dropout 的工业级配置实践。