2. 参数调优基础:学习率、批量大小与优化器
各位同学,咱们今天聊点实在的。模型训练里什么最让人头疼?我个人的经验是——调参。尤其是学习率、批量大小和优化器这三个家伙,它们就像三驾马车,配合不好,模型就跑偏。
先别急着上代码,咱们先把底层逻辑理清楚。你想想看,一个模型从随机初始化到收敛,本质上就是在损失函数这个“地形图”上找最低点。而学习率,就是你每一步迈多大。
2.1 学习率:步子大了容易扯着蛋
学习率(Learning Rate, LR)控制着参数更新的步长。公式很简单:
θ_new = θ_old - η * ∇L(θ_old)
其中 η 就是学习率。η 太大,参数会在最优解附近震荡,甚至发散;η 太小,训练慢得像蜗牛爬,还容易陷入局部最优。
我在项目中遇到过最典型的案例:有一次训练一个图像分类模型,loss 死活降不下去。我盯着曲线看了半天,发现它在 0.8 到 1.2 之间来回跳。嗯,这就是典型的学习率过大。我把 η 从 0.01 降到 0.001,loss 立马乖乖收敛了。
核心结论:
- 学习率过大 → 震荡、不收敛
- 学习率过小 → 收敛慢、易陷入局部最优
- 学习率适中 → 稳定下降、快速收敛
那怎么选初始学习率?我建议用 学习率范围测试(LR Range Test)。说白了,就是让学习率从小到大地跑几个 epoch,观察 loss 下降最快的那个区间。比如从 1e-6 到 1,画个曲线,找到 loss 下降最陡的地方,那就是你的“黄金学习率”。
我的小技巧: 实际项目中,我通常先用 0.001 作为初始值,然后配合学习率衰减策略。比如每 10 个 epoch 衰减为原来的 0.1 倍。这样既能快速下降,又能精细收敛。
2.2 批量大小:不是越大越好
批量大小(Batch Size)决定了每次更新参数时用多少样本计算梯度。这里有个常见的误区:很多人觉得 batch size 越大越好,因为可以利用 GPU 并行计算。
我曾经踩过这个坑。 有一次我把 batch size 从 32 调到 256,想着训练速度能翻倍。结果呢?速度确实快了,但模型精度掉了 2 个百分点。为什么?因为大 batch 会让梯度估计过于平滑,失去了随机梯度下降的“随机性”,反而容易收敛到尖锐的极小值。
来看个对比表格:
| 批量大小 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 小(16-64) | 泛化性好、内存占用低 | 训练慢、梯度噪声大 | 小数据集、显存受限 |
| 中(64-256) | 平衡速度和精度 | 需要调学习率 | 大多数通用场景 |
| 大(256-1024+) | 训练速度快、GPU利用率高 | 泛化性下降、容易过拟合 | 大数据集、分布式训练 |
你想想看,为什么小 batch 泛化性好?因为每次梯度估计都有噪声,这个噪声反而像正则化一样,帮助模型跳出局部最优。我个人的习惯是:先试 64,不行再调 32 或 128。记住一个原则:batch size 翻倍,学习率也要跟着翻倍,这样才能保持梯度更新的幅度一致。
注意: 如果你的 GPU 显存不够,别硬上大 batch。用梯度累积(Gradient Accumulation)技术,模拟大 batch 的效果。比如 batch size=32,梯度累积步数=4,等效于 batch size=128。
2.3 优化器:各有各的脾气
优化器就是那个决定“怎么走”的算法。SGD、Adam、RMSprop……每个都有自己的一套逻辑。咱们来逐个分析。
SGD(随机梯度下降)
最原始的优化器。每次更新只用一个样本或一个小 batch 的梯度。优点是简单、稳定,缺点是收敛慢、容易震荡。
# PyTorch 示例
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
加上 momentum(动量)后,SGD 会考虑历史梯度的方向,像滚雪球一样加速。我一般把 momentum 设为 0.9,效果不错。
Adam(自适应矩估计)
Adam 是目前最流行的优化器。它结合了 Momentum 和 RMSprop 的优点,能自适应调整每个参数的学习率。说白了,就是给每个参数单独配一个“学习率调节器”。
optimizer = torch.optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999))
我记得有一次做 NLP 任务,用 SGD 训了 50 个 epoch 还没收敛,换成 Adam 后 10 个 epoch 就搞定了。Adam 对超参数不敏感,特别适合新手和快速实验。
RMSprop
RMSprop 是 Adam 的前身,主要解决梯度消失和爆炸问题。它通过指数移动平均来调整学习率,适合处理非平稳目标。
optimizer = torch.optim.RMSprop(model.parameters(), lr=0.001, alpha=0.99)
说实话,现在用 RMSprop 的人不多了,大部分场景都被 Adam 取代。但在某些 RNN 任务中,RMSprop 依然有它的优势。
优化器对比总结
| 优化器 | 收敛速度 | 泛化能力 | 调参难度 | 推荐场景 |
|---|---|---|---|---|
| SGD+Momentum | 慢 | 强 | 中 | CV、需要精细调参 |
| Adam | 快 | 中 | 低 | NLP、快速实验 |
| RMSprop | 中 | 中 | 低 | RNN、序列模型 |
我个人建议:新手先用 Adam,等模型跑通了再换 SGD 精调。Adam 帮你快速找到“好区域”,SGD 帮你找到“最优解”。
2.4 知识体系总览
为了让你更直观地理解这三者的关系,我画了一张图:
这张图把三者的关系说得很清楚了。学习率决定“迈多大步”,批量大小决定“往哪个方向看”,优化器决定“怎么迈出这一步”。三者缺一不可。
2.5 实战建议
最后,给你一套我常用的调参流程:
- 先用 Adam,学习率 0.001,batch size 64,跑 10 个 epoch 看看 loss 下降趋势。
- 如果 loss 下降太慢,尝试增大学习率到 0.01;如果震荡,减小到 0.0001。
- 模型基本收敛后,换成 SGD+Momentum,学习率缩小 10 倍,精调 20-30 个 epoch。
- 如果显存够用,尝试增大 batch size 到 128 或 256,同时按比例增大学习率。
避坑指南: 我曾经在 batch size 从 64 调到 128 时忘了调学习率,结果模型直接炸了。记住:batch size 翻倍,学习率也要翻倍。这是经验之谈。
好了,这一章的内容就到这里。参数调优是个手艺活,多练才能找到感觉。下一章咱们聊聊更高级的调参技巧——学习率调度策略和权重初始化。
公众号:蓝海资料掘金营,微信deep3321