模型的训练目标是在训练集上最小化损失,但训练 loss 最低不代表泛化性能最好——当模型容量足够大时,它有能力记住训练集的每个样本包括噪声,导致验证集 loss 反而上升。这种现象称为过拟合。正则化是抑制过拟合、缩小训练误差与泛化误差之间差距的技术手段。


一、过拟合:正则化要解决的问题

1.1 什么是过拟合

模型容量(参数量)足够大时,它有能力"记住"训练集的每个样本——包括其中的噪声。表现为训练 loss 持续下降,但验证 loss 在某个 epoch 后开始上升:

EpochTrain LossVal Loss状态
40.0680.082val loss 最低
50.0560.083val 开始上升
100.0260.094train↓ val↑ = 过拟合

1.2 过拟合的本质

模型在训练集上学到了"只对训练集有效"的模式,而不是数据的通用规律。一个记住了所有考试题答案的学生,换一套题就不会做。

正则化的目标:让模型在训练集上"学个差不多"就行,别学到连噪声都记住了。


二、Dropout:随机丢弃神经元

2.1 原理

训练时,每个 forward 随机将一部分神经元的输出置为零。比例由 p 控制(如 p=0.1 表示丢弃 10%)。被丢弃的神经元在当前步不参与前向传播和反向传播。

正常输出:    [0.7, 0.3, 0.5, 0.8, 0.2]
Dropout(p=0.4): [0.7, 0.0, 0.5, 0.0, 0.0]   ← 随机 40% 置零

每次丢弃的神经元不同,模型不能依赖任何单个神经元,被迫学习冗余表示——同一信息存在多个路径中,任何一个被丢掉也不影响整体。

推理时关闭 Dropout,所有神经元参与计算,输出乘以 1−p1-p1p 补偿训练时的缩放(PyTorch 内部自动处理)。

2.2 代码

import torch.nn as nn

dropout = nn.Dropout(p=0.1)

在模型中的典型位置:Attention 输出之后、FFN 输出之后、Embedding 之后。

# 典型用法:在 Attention / FFN 的输出后各加一层 Dropout
self.attn_dropout = nn.Dropout(p=0.1)
self.resid_dropout = nn.Dropout(p=0.1)

2.3 常见错误

错误后果
验证时忘记 model.eval()Dropout 仍在丢弃,验证结果不稳定
p 设太大(如 0.5)模型欠拟合,训练 loss 降不下来
p 设太小(如 0.01)正则化效果几乎为零
推理时忘了关 Dropout输出不确定,同一输入每次结果不同

model.train()model.eval() 的作用就是切换 Dropout 的开关:

model.train()   # Dropout 开启
model.eval()    # Dropout 关闭

三、Weight Decay(L2 正则化):惩罚大权重

3.1 原理

在损失函数上加一个惩罚项,让模型权重不要太大:

L总=L任务+λ∑iwi2L_{\text{总}} = L_{\text{任务}} + \lambda \sum_i w_i^2L=L任务+λiwi2

λ\lambdaλ 是惩罚系数(即代码里的 weight_decay)。权重越大,惩罚越多。梯度更新时等价于:

wi←wi−η∂L∂wi−ηλwiw_i \leftarrow w_i - \eta \frac{\partial L}{\partial w_i} - \eta \lambda w_iwiwiηwiLηλwi

最后多了一项 −ηλwi-\eta \lambda w_iηλwi,每步把权重往零的方向拉一点。

3.2 为什么大权重 = 过拟合

大权重意味着模型对某些输入极度敏感,容易拟合训练数据中的噪声。小权重让决策边界更平滑,泛化更好。

3.3 代码

# PyTorch 原生
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=0.1)

3.4 哪些参数应该做 weight decay

不是所有参数都应该被惩罚:

参数类型是否 weight decay原因
Linear 的 weight这是需要惩罚的权重矩阵
Embedding 的 weight看情况有的实现会做,有的不做
LayerNorm 的 gamma/beta归一化参数,不该被惩罚
所有 biasbias 是偏移量,不是权重

一种通用做法是按参数维度分组:2D 及以上做 decay,1D 不做:

decay_params = [p for n, p in param_dict.items() if p.dim() >= 2]
nodecay_params = [p for n, p in param_dict.items() if p.dim() < 2]
optim_groups = [
    {'params': decay_params, 'weight_decay': weight_decay},
    {'params': nodecay_params, 'weight_decay': 0.0}
]

3.5 L1 vs L2

L1(Lasso)L2(Ridge)
惩罚项∑∣wi∣\sum \lvert w_i \rvertwi∑wi2\sum w_i^2wi2
梯度sign(w)\text{sign}(w)sign(w)w≠0w\neq 0w=0 时;w=0w=0w=0 处不可导,次梯度 ∈[−1,1]\in[-1,1][1,1]2w2w2w(与权重大小成正比,越大缩得越多)
效果部分权重被精确压到 0(稀疏化)所有权重按比例缩小,趋近 0 但难精确到 0
深度学习少用(稀疏性不利 GPU 并行)主流

一个常见误区:很多人以为 AdamW 的 weight_decay 就是 L2 正则化,两者并不等价。L2 正则化是把 λw2\lambda w^2λw2 加进损失,再由优化器按梯度更新;而 AdamW 采用解耦权重衰减(decoupled weight decay),直接对权重做 w←(1−ηλ)ww \leftarrow (1-\eta\lambda)ww(1ηλ)w,再叠加自适应梯度更新。在 SGD 下两者等价,但在 Adam 这类自适应优化器下,L2 的惩罚会被各参数的自适应学习率放大或缩小,效果不如解耦权重衰减——这正是 AdamW 被提出的动机(Loshchilov & Hutter, 2019)。


四、Early Stopping:训练到该停就停

4.1 原理

训练过程中监控验证集 loss,一旦 loss 不再下降(或开始上升),立即停止训练。在最优的那个 epoch 保存模型。

4.2 代码

best_val_loss = float('inf')

for epoch in range(1, EPOCHS + 1):
    train_loss = train_one_epoch(...)
    val_loss = evaluate(...)

    if val_loss < best_val_loss:
        best_val_loss = val_loss
        torch.save(model.state_dict(), 'best_model.pt')
    else:
        # val loss 连续 N 个 epoch 不降,可以提前停
        pass

4.3 常见错误

错误后果
只保存最后一个 epoch 的模型过拟合后最优权重被覆盖
没有验证集无法判断何时该停
patience 设太短(如 1)正常的 loss 波动就触发了停止
patience 设太长(如 50)白训几十个 epoch

五、Data Augmentation:数据增强

5.1 原理

通过对训练数据做随机变换,"制造"出更多训练样本。模型每次看到的是经过变换的数据,不能死记原始样本,被迫学习变换不变的特征。

5.2 图像任务的典型手段

# PyTorch 图像增强
transform = transforms.Compose([
    transforms.RandomHorizontalFlip(),    # 随机水平翻转
    transforms.RandomCrop(32, padding=4), # 随机裁剪
    transforms.ColorJitter(0.2, 0.2, 0.2), # 颜色抖动
    transforms.ToTensor(),
])

5.3 文本任务的典型手段

手段做法示例
同义词替换随机替换几个词为同义词“我喜欢猫” → “我喜爱猫”
回译翻译成另一种语言再翻回来“I love cats” → “我爱猫”
随机删除随机删掉一些词“我 喜欢 吃 苹果” → “我 吃 苹果”
随机交换交换相邻词的顺序“我 喜欢 苹果” → “喜欢 我 苹果”

文本增强的效果通常不如图像显著,因为文本的词序和语义关系更敏感。


六、Label Smoothing:标签平滑

6.1 原理

把 one-hot 硬标签 [0, 0, 1, 0] 变成软标签 [0.033, 0.033, 0.9, 0.033]。防止模型对自己的预测过于自信——过于自信 = 过拟合。

6.2 公式

ysmooth=(1−ϵ)⋅yonehot+ϵKy_{\text{smooth}} = (1 - \epsilon) \cdot y_{\text{onehot}} + \frac{\epsilon}{K}ysmooth=(1ϵ)yonehot+Kϵ

其中 ϵ\epsilonϵ 是平滑系数(通常 0.1),KKK 是类别数。

6.3 代码

# PyTorch 内置
loss_fn = nn.CrossEntropyLoss(label_smoothing=0.1)  # PyTorch >= 1.10

6.4 直觉

硬标签告诉模型"正确答案概率是 1,其他全是 0"。但世界上没有 100% 确定的事,有些其他类别也有道理。标签平滑让模型承认"其他类别也有一定概率",避免在训练集上过拟合到极端自信。


七、LayerNorm / BatchNorm:归一化也附带正则化

7.1 原理

归一化的主要目的是稳定训练,但会附带正则化效果。BatchNorm 使用 mini-batch 的均值和方差做归一化,引入了 batch 内的统计噪声——每个 batch 的统计量不同,等价于给输入加了一点随机扰动,有轻微的正则化作用。

LayerNorm 使用单个样本的统计量,没有这种噪声,正则化效果更弱。

7.2 定位

归一化不是正则化的主要手段,但附带了一些效果。不要把 BatchNorm 当正则化用——它的首要任务是让训练稳定。


八、总结

技术机制实现难度效果强度大模型使用情况
Dropout随机丢弃神经元一行代码✅ GPT、LLaMA 全用
Weight Decay惩罚大权重优化器参数✅ AdamW 标配
Early Stopping验证 loss 不降就停训练策略✅ 训练必备
Data Augmentation变换数据造更多样本数据预处理强(图像)/弱(文本)图像任务必备
Label Smoothing硬标签变软标签损失函数参数✅ 大模型训练常用
BatchNormbatch 统计噪声模型结构弱(附带)视觉模型用,LLM 不用

实际训练中通常组合使用。大模型训练的标准配置是 Dropout + Weight Decay + Early Stopping

正则化的核心思想只有一个:让模型在训练集上学到"差不多"就行,别学过头。 所有技术都是这个思想的实现手段。

更多推荐