优化与训练技巧¶
网络架构决定了模型"能不能学",而优化策略和训练技巧决定了模型"学得好不好"。本文覆盖优化器、正则化、归一化和学习率调度等关键训练技术。
1. 优化器(Optimizer)¶
优化器的任务是根据梯度更新参数,使损失函数最小化。不同的优化器本质上是不同的参数更新策略。
SGD(随机梯度下降)¶
最基础的优化器:
- ✅ 简单,理论性质好
- ❌ 收敛慢,容易在鞍点/平坦区域停滞
- ❌ 对学习率敏感
SGD + Momentum(动量)¶
引入"惯性":梯度不再只看当前方向,还会参考之前的运动趋势。
\(\beta\) 通常取 0.9。
直觉
想象一个球从山上滚下来。没有动量时,球遇到小坑就停了;有动量时,球靠着惯性能冲过小坑,更容易滚到谷底。
AdaGrad¶
自适应调整每个参数的学习率——梯度累积大的参数(更新频繁的),学习率变小;反之变大。
其中 \(G_t\) 是梯度平方的累积和。
- ✅ 不同参数自适应学习率
- ❌ 学习率单调递减,后期可能过小导致停止学习
RMSProp¶
修复 AdaGrad 的问题:用指数移动平均替代累积和,让学习率不会一直衰减。
Adam(Adaptive Moment Estimation)⭐¶
结合了 Momentum(一阶矩估计)和 RMSProp(二阶矩估计),是目前最常用的优化器。
偏差校正:
参数更新:
默认超参数:\(\beta_1 = 0.9\),\(\beta_2 = 0.999\),\(\epsilon = 10^{-8}\)
AdamW¶
Adam 的改进版,将权重衰减(Weight Decay)从梯度计算中解耦出来:
Adam vs AdamW
标准 Adam 中,L2 正则化和自适应学习率会相互干扰(正则化的梯度也会被自适应缩放)。AdamW 直接在参数上做衰减,效果更好,是 Transformer 训练的默认选择。
优化器对比总结¶
| 优化器 | 自适应学习率 | 动量 | 推荐场景 |
|---|---|---|---|
| SGD | ❌ | ❌ | 理论研究 |
| SGD + Momentum | ❌ | ✅ | 计算机视觉(配合调度器) |
| Adam | ✅ | ✅ | ⭐ 通用默认选择 |
| AdamW | ✅ | ✅ | ⭐ Transformer / 大模型 |
2. 学习率调度(Learning Rate Schedule)¶
学习率是最重要的超参数之一。太大会导致震荡发散,太小会收敛过慢。学习率调度让学习率在训练过程中动态变化。
常见调度策略¶
Step Decay¶
每过固定步数,学习率乘以一个衰减因子:
Cosine Annealing(余弦退火)¶
学习率按余弦函数从初始值平滑下降到接近 0:
⭐ 现代训练中非常流行,尤其配合 Warmup。
Warmup + Cosine Decay¶
先用一小段时间线性增大学习率(Warmup),再用余弦退火下降。这是 Transformer 训练的标准范式:
为什么需要 Warmup?
训练初期,参数随机初始化,梯度方向不稳定。如果一开始学习率就很大,容易导致训练不稳定甚至发散。Warmup 让网络先"热身",等梯度方向稳定了再加速。
PyTorch 示例¶
from torch.optim import AdamW
from torch.optim.lr_scheduler import CosineAnnealingLR
optimizer = AdamW(model.parameters(), lr=1e-3, weight_decay=0.01)
scheduler = CosineAnnealingLR(optimizer, T_max=100, eta_min=1e-6)
for epoch in range(100):
train_one_epoch(model, optimizer)
scheduler.step()
3. 正则化技术¶
正则化的目标是防止过拟合,提高模型的泛化能力。
Dropout¶
训练时随机"关闭"一部分神经元(把输出置零),比例为 \(p\)(常见 \(p = 0.1 \sim 0.5\)):
除以 \((1-p)\) 是为了保证期望值不变(Inverted Dropout)。
为什么 Dropout 有效?
- 防止神经元之间的共适应(co-adaptation):每个神经元不能依赖特定的其他神经元
- 等效于训练了指数级多个子网络的集成
- 推理时关闭 Dropout,使用完整网络
注意事项:
- 通常加在全连接层,卷积层效果不显著
- 推理时不用 Dropout(
model.eval()会自动关闭) - Transformer 中通常对 Attention 权重和前馈层都用 Dropout
L2 正则化 / Weight Decay¶
在损失函数中加入参数的平方和:
效果:限制参数不要太大,防止模型太"激进"。
Label Smoothing¶
将 one-hot 硬标签变成软标签,避免模型对训练标签过度自信:
其中 \(\alpha\) 通常取 0.1,\(K\) 是类别数。比如将 \([0, 0, 1, 0]\) 变为 \([0.025, 0.025, 0.925, 0.025]\)。
数据增强(Data Augmentation)¶
通过对训练数据做变换来扩充训练集,是最直接的正则化手段:
| 数据类型 | 常用增强方法 |
|---|---|
| 图像 | 翻转、旋转、裁剪、色彩抖动、Cutout、MixUp |
| 文本 | 同义词替换、回译、随机删除/插入 |
| 音频 | 加噪、变速、SpecAugment |
Early Stopping¶
监控验证集损失,当验证损失不再下降时提前终止训练:
4. 归一化技术¶
归一化层稳定训练过程,加速收敛,是现代深度网络的标配。
Batch Normalization(BN)¶
对一个 mini-batch 内的数据,在每个通道上做归一化:
其中 \(\mu_B\) 和 \(\sigma_B^2\) 是 batch 内的均值和方差,\(\gamma\) 和 \(\beta\) 是可学习的缩放和平移参数。
为什么 BN 有效?
- 缓解内部协变量偏移(Internal Covariate Shift):前一层参数变化导致后一层输入分布变化
- 允许使用更大的学习率
- 有轻微正则化效果(batch 带来的随机性)
注意事项:
- 对 batch size 敏感——batch 太小时统计量不稳定
- 推理时使用训练阶段的移动平均统计量
- 不适合序列模型(序列长度不固定)
Layer Normalization(LN)¶
对单个样本的所有特征做归一化,不依赖 batch:
- ✅ 不依赖 batch size
- ✅ 适合序列模型和 Transformer
- 是 Transformer 的标准归一化方式
归一化方式对比¶
| 方法 | 归一化维度 | 适用场景 | 依赖 batch |
|---|---|---|---|
| Batch Norm | batch 维度 | CNN(图像) | ✅ 是 |
| Layer Norm | 特征维度 | Transformer、RNN | ❌ 否 |
| Instance Norm | 单个样本的空间维度 | 风格迁移 | ❌ 否 |
| Group Norm | 通道分组 | 小 batch CNN | ❌ 否 |
5. 梯度相关问题与对策¶
梯度消失¶
现象:深层网络的浅层梯度极小,参数几乎不更新。
对策:
| 技术 | 原理 |
|---|---|
| ReLU 激活函数 | 正区间梯度恒为 1 |
| 残差连接(ResNet) | 梯度可直接跳过层传递 |
| Batch/Layer Norm | 稳定各层输入分布 |
| 合理的权重初始化 | He / Xavier 初始化 |
梯度爆炸¶
现象:梯度值异常大,参数更新剧烈,loss 变成 NaN。
对策:
- 梯度裁剪(Gradient Clipping):限制梯度范数上界
- 使用更小的学习率
- 使用归一化层
6. 混合精度训练¶
使用 FP16(半精度浮点)代替 FP32 进行前向和反向传播,大幅降低显存占用和计算时间:
| 精度 | 位数 | 范围 | 用途 |
|---|---|---|---|
| FP32 | 32 bit | \(\sim 10^{-38} \sim 10^{38}\) | 参数存储(主副本) |
| FP16 | 16 bit | \(\sim 10^{-8} \sim 65504\) | 前向/反向计算 |
| BF16 | 16 bit | 与 FP32 相同指数范围 | 更稳定的半精度训练 |
Loss Scaling¶
FP16 的精度较低,小梯度可能下溢为 0。解决方案:训练时将 loss 放大(如乘 1024),反向传播后再缩小梯度。
PyTorch 混合精度示例¶
from torch.amp import autocast, GradScaler
scaler = GradScaler()
for data, target in dataloader:
optimizer.zero_grad()
with autocast(device_type='cuda'): # 自动选择 FP16 计算
output = model(data)
loss = criterion(output, target)
scaler.scale(loss).backward() # 缩放后的反向传播
scaler.step(optimizer) # 还原缩放后更新参数
scaler.update()
7. 训练流程 Checklist¶
一个典型的深度学习训练流程:
graph TD
A[准备数据 & 增强] --> B[定义模型架构]
B --> C[选择损失函数]
C --> D[选择优化器 & 学习率调度]
D --> E[训练循环]
E --> F{验证集效果}
F -->|过拟合| G[加正则化 / 减模型 / 加数据]
F -->|欠拟合| H[加模型复杂度 / 减正则化]
F -->|满意| I[测试集评估 & 部署]
G --> E
H --> E
常见训练配置参考¶
| 任务 | 优化器 | 学习率 | 调度器 | 正则化 |
|---|---|---|---|---|
| 图像分类(CNN) | SGD + Momentum | 0.1 | Cosine / Step | BN + 数据增强 |
| NLP(Transformer) | AdamW | 1e-4 ~ 5e-4 | Warmup + Cosine | Dropout + LN |
| 微调预训练模型 | AdamW | 1e-5 ~ 3e-5 | Linear Warmup | Dropout |
| 小数据集 | Adam | 1e-3 | ReduceOnPlateau | Dropout + 数据增强 + Early Stop |