手动调优经验与常见陷阱
参数调优这事,说白了就是手艺活。你不能指望自动搜索一把梭,然后吃顿火锅回来模型就完美了。我自己这些年调参,踩过的坑比调好的参数还多。今天把这部分经验掰开揉碎讲讲,尤其是那些容易翻车的地方。
调优前的准备工作
动手之前,先把几个基础整明白。我习惯先做一次简单训练,看看损失曲线是不是真的在下降。如果不降,后面调啥都白搭。
核心原则:调参顺序不是随机的,先调学习率,再调 batch size,最后调正则化参数。
为什么这么排?因为学习率影响收敛速度和最终精度,是最敏感的旋钮。batch size 影响梯度的方差和稳定性,得等学习率差不多定了才能动它。正则化参数(weight decay、dropout 比例)本质上是在防止过拟合,调太早会把欠拟合的锅背错。
学习率调优——我踩过最深的坑
学习率太大,损失炸了;学习率太小,训练跟蜗牛爬一样。我在一个 NLP 项目里遇到过模型三天不收敛,后来发现是初始学习率设成了 0.00001——太小了,梯度更新几乎为零。
避坑:千万不要用固定学习率从头训到尾。用学习率衰减(step decay、cosine annealing)或者 warmup。
我个人习惯先跑一个 学习率范围测试(LR range test)。比如从 1e-6 到 1.0,画一条损失 vs 学习率的曲线,找到损失下降最快的区间,然后把初始学习率设在那附近。
# 一个简单的学习率调度器示例(PyTorch 风格)
from torch.optim.lr_scheduler import CosineAnnealingLR
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = CosineAnnealingLR(optimizer, T_max=100)
for epoch in range(100):
train()
scheduler.step()
Batch Size:不是越大越好
你以为显卡内存够就拼命塞 batch size?我试过把 batch size 从 32 提高到 512,结果验证集精度反而掉了。原因很简单:batch size 太大,梯度方向太稳定,容易陷入尖锐的局部极小点。
| Batch Size | 梯度方差 | 泛化能力 | 训练速度 |
|---|---|---|---|
| 小 (16-64) | 高 | 好 | 慢(需要更多迭代) |
| 中 (128-256) | 中 | 较好 | 较快 |
| 大 (512+) | 低 | 差(容易过拟合) | 快(每步计算量大但步数少) |
如果你的 batch size 不得不设大(比如为了填满 GPU),请务必配合 学习率 warmup 和 梯度裁剪。我曾经在 1024 batch size 下用 warmup 从 0 线性增加到目标学习率,效果比直接上要大 2 个点。
优化器选择:SGD vs Adam 的偏见
很多人无脑上 Adam,因为不用调学习率。但我在图像分类任务上发现,SGD 配合 momentum 往往最终精度更高。Adam 自适应学习率会在后期导致学习率太小,收敛不彻底。
- SGD + Momentum:适合计算机视觉、需要精调的场景。momentum 建议 0.9,初始 lr 0.1 再衰减。
- Adam:适合 NLP、Transformer 之类的结构,或者刚上手时。默认 lr=1e-3,但记得设 weight decay。
- AdamW:我个人现在基本只用它——把 weight decay 和自适应学习率解耦,效果比 Adam 好一截。
小技巧:如果不确定用哪个优化器,先用 Adam 跑 10 个 epoch 看看损失能不能收敛,再切 SGD 精调。
正则化陷阱——调错了反而更差
Weight decay 设太大,模型欠拟合;dropout 设太大,训练不稳定。我见过一个项目在 ResNet 上加了 0.5 的 dropout,结果验证集准确率比不加还低 3%。
正则化的目的不是让损失降到最低,而是让验证集表现最好。一个简单的判断方法:
训练集 loss 远低于验证集 loss → 过拟合,加正则化或数据增强。
训练集和验证集 loss 都高 → 欠拟合,提升模型容量或减少正则化。
# 常见的 weight decay 设置(PyTorch)
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=1e-2)
# 对于 Transformer,weight_decay 常设为 0.01 ~ 0.1
常见陷阱清单(我用血泪换来的)
- 损失曲线抖动太大:一般是学习率偏大,或者 batch size 太小。先降学习率,不行再增大 batch size。
- 损失爆炸(NaN):梯度爆炸。赶紧加 梯度裁剪(max_norm=1.0)。我曾经在一层 LSTM 里没加裁剪,损失直接飞到 NaN,重训两次才想起来。
- 验证集精度起伏不定:检查是否用了 shuffle。如果每次验证的样本顺序不同,指标可能有波动。我习惯固定验证集 shuffle seed。
- 训练集 loss 降到 0,验证集却很差:典型的过拟合。先加 dropout 或 weight decay,如果不行再减小模型复杂度。
- 学习率衰减太快:模型还没来得及收敛,学习率已经降到接近 0,导致停滞。用余弦衰减或预热后再衰减会更稳。
手动调优流程全景
下面这张图总结了我个人常用的调优决策路径。每次调参就像走迷宫,但有了这个图就不容易迷路。
最后提醒一句:手动调参时,务必记录每次实验的配置和结果。我自己刚开始时经常不记日志,结果调了三天发现最好的参数就是第一次随手设的那些……后来用 CSV 或者实验管理工具(如 MLflow)记下来,效率翻倍。