共计 2365 个字符,预计需要花费 6 分钟才能阅读完成。
问题背景
MNIST 作为经典的图像分类任务,常被用于验证深度学习模型的性能。当使用 5 层卷积神经网络(CNN)处理 MNIST 时,由于网络深度增加,容易出现梯度消失或爆炸的问题。固定学习率在这种场景下往往表现不佳:

- 学习率过大时:模型参数更新幅度过大,导致损失函数在最小值附近震荡,甚至发散。实际案例显示,当固定学习率 >0.01 时,验证集准确率会周期性波动 3%-5%
- 学习率过小时:模型收敛速度极慢,需要更多训练轮次(epoch)才能达到相同精度。实验表明,lr=0.001 时需要 50+ 个 epoch 才能达到 98% 准确率
技术对比
常见的几种学习率策略在 MNIST 任务上的表现差异如下(基于相同 5 层 CNN 结构):
| 策略类型 | 最高验证准确率 | 训练稳定性 | 收敛速度 |
|---|---|---|---|
| 固定学习率 | 98.7% | 低 | 慢 |
| Step Decay | 99.0% | 中 | 中 |
| Cosine 退火 | 99.1% | 高 | 快 |
| Warmup+Cyclical | 99.2% | 最高 | 最快 |
验证曲线图显示,周期性调整策略能使模型更快跳出局部最优,且验证准确率的波动幅度小于±0.3%
核心方案
Warmup 阶段
初始学习率计算公式:
$$ \eta_{init} = 0.1 \times \frac{batch_size}{256} $$
在前 5 个 epoch 采用线性 warmup,逐步从 $\eta_{init}/10$ 增加到 $\eta_{init}$,避免初期梯度不稳定。
Cyclical LR 策略
采用三角循环策略,关键参数设置:
- 基础学习率 (base_lr):$\eta_{init}$
- 最大学习率 (max_lr):$2\times\eta_{init}$
- 周期长度 (step_size):$2 \times \lfloor \frac{iter_per_epoch}{2} \rfloor$
- 幅度缩放模式:triangular2(每个周期峰值减半)
数学表达为:
$$ \eta_t = \eta_{base} + (\eta_{max} – \eta_{base}) \cdot max(0, 1 – |\frac{t}{step_size} – 2\lfloor\frac{t}{step_size}\rfloor + 1|) $$
代码实现
import torch
from torch.optim.lr_scheduler import CyclicLR
# 初始化模型和优化器
model = CNN5Layer()
optimizer = torch.optim.SGD(model.parameters(), lr=0.1*batch_size/256) # 初始 lr 占位
# Warmup 阶段
warmup_epochs = 5
warmup_factor = 1./10
warmup_lr = [base_lr * (warmup_factor + (1. - warmup_factor) * i/warmup_epochs)
for i in range(warmup_epochs)]
# Cyclical LR 配置
base_lr = 0.1 * batch_size / 256
max_lr = 2 * base_lr
step_size = 2 * (len(train_loader) // 2)
scheduler = CyclicLR(optimizer, base_lr=base_lr, max_lr=max_lr,
step_size_up=step_size, mode='triangular2')
# 训练循环
for epoch in range(epochs):
for i, (inputs, labels) in enumerate(train_loader):
# Warmup 阶段手动调整
if epoch < warmup_epochs:
for param_group in optimizer.param_groups:
param_group['lr'] = warmup_lr[epoch]
# 正常训练流程
outputs = model(inputs)
loss = criterion(outputs, labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# Cyclical LR 更新
if epoch >= warmup_epochs:
scheduler.step()
# 记录学习率变化
current_lr = optimizer.param_groups[0]['lr']
lr_history.append(current_lr)
调优技巧
- LR Finder 实践 :
- 设置学习率范围测试(如 1e- 7 到 1e-1)
- 选择损失下降最陡峭区间作为 base_lr
-
选择损失开始回升点作为 max_lr
-
批量归一化处理 :
- 当模型包含 BN 层时,将 base_lr 增大 5 -10 倍
- 对最后一层全连接使用较小的学习率(如其他层的 1 /10)
生产建议
- 分布式训练 :
- 实际学习率 = $base_lr \times \sqrt{num_gpus}$
-
需同步 BN 层统计量
-
NaN 问题排查 :
- 检查梯度范数:
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=5.0) - 验证输入数据归一化(MNIST 像素值需缩放到 [0,1])
- 降低初始 max_lr 并增加 warmup 轮次
延伸思考
该方案可迁移到 CIFAR-10 数据集,但需注意:
- 将初始 base_lr 缩小 3 - 5 倍(因图像复杂度更高)
- 当使用 Adam 优化器时:
- 设置 $\beta_1=0.9, \beta_2=0.99$
- 禁用 Amsgrad 选项
- 周期长度延长 2 倍
实验表明,在 CIFAR-10 上 SGD+Cyclical LR 组合比 Adam 有 0.8%-1.2% 的准确率提升,但需要更精细的超参调整。
通过系统化的学习率策略设计,即使是简单的 5 层 CNN 也能在 MNIST 上达到接近 SOTA 的性能。该方法的核心思想——动态适应优化过程的不同阶段,同样适用于更复杂的网络结构和任务场景。
