学习率(Learning Rate):模型训练的油门踏板
学习率,我习惯叫它「步长」。说白了,就是模型每次更新参数时,往梯度方向迈多大一步。
你想想看,梯度下降就像在山上摸黑往下走。学习率就是你每一步的步幅。步子太小,走到天亮都到不了山脚;步子太大,一脚踩空直接滚下山崖。
这个参数,是调参时第一个要盯住的东西。我见过太多新手上来就调网络结构,结果模型根本不收敛——回头一看,学习率设错了。
学习率到底在控制什么?
公式很简单:
θ_new = θ_old - η * ∇L(θ_old)
其中 η 就是学习率。它控制着参数更新的幅度。
每次迭代,我们计算损失函数对参数的梯度 ∇L。这个梯度告诉模型:「往哪个方向走,损失下降最快」。学习率则决定:「这次走多远」。
核心直觉:学习率 = 信任梯度的程度 × 更新步幅
梯度方向对了,步幅大点没问题。梯度有噪声,步幅就得收一收。
学习率过大:模型在「震荡」中迷失
学习率设太大,模型参数会在最优值附近来回震荡,甚至直接发散。
我记得有一次训练一个图像分类模型,loss 曲线像心电图一样上下乱跳。我盯着屏幕看了半天,心想「这模型怕不是疯了」。后来把学习率从 0.1 降到 0.01,loss 曲线瞬间变得丝滑。
典型症状:
- Loss 曲线不下降,反而上升
- Loss 剧烈震荡,毫无收敛趋势
- 训练初期 loss 就变成 NaN(梯度爆炸了)
- 验证集准确率忽高忽低
我曾经踩过的坑:有一次用 Adam 优化器,默认学习率 0.001,训练一个 NLP 模型。跑了 10 个 epoch,loss 死活不降。我以为是数据问题,折腾了两天。最后发现——学习率设成 0.01 就好了。Adam 虽然自适应,但初始学习率依然敏感。
学习率过小:模型在「龟速」中煎熬
学习率太小,模型确实能收敛,但慢得让人抓狂。
你想想看,本来 100 个 epoch 能解决的问题,因为学习率设小了 10 倍,得跑 1000 个 epoch。算力成本翻 10 倍,时间成本翻 10 倍。
典型症状:
- Loss 缓慢下降,但始终降不到理想值
- 训练几百个 epoch 后 loss 还在缓慢下降
- 模型容易陷入局部最优,跳不出来
- 训练时间异常长
我的经验:如果训练 10 个 epoch 后 loss 下降不到初始值的 50%,大概率是学习率偏小了。可以尝试把学习率翻 3-5 倍看看效果。
固定学习率 vs 动态学习率
固定学习率,就是整个训练过程用一个 η 值。简单粗暴,但问题很明显:
- 初期需要大步子快速下山,后期需要小步子精细调整
- 一个固定值很难同时满足「快」和「稳」
动态学习率,就是让学习率随着训练过程变化。这是目前的主流做法。
| 策略 | 做法 | 适用场景 | 我的评价 |
|---|---|---|---|
| 固定学习率 | 全程不变 | 小数据集、快速实验 | 简单但低效,不推荐 |
| Step Decay | 每 N 个 epoch 乘以一个衰减因子 | CV 任务、经典模型 | 好用,但需要手动调衰减时机 |
| Exponential Decay | η = η₀ * e^(-kt) | 需要平滑衰减的场景 | 衰减太快,容易过早停滞 |
| Cosine Annealing | 按余弦曲线衰减,周期重启 | 需要跳出局部最优 | 我最近很喜欢用这个 |
| ReduceLROnPlateau | 验证 loss 不降时自动衰减 | 不确定衰减策略时 | 省心,但可能错过最佳时机 |
| Warmup + Decay | 先从小 lr 线性增加到目标 lr,再衰减 | 大模型、Transformer | 稳定训练初期的必备技巧 |
为什么动态学习率更有效?
原因其实很直观:
- 训练初期:参数离最优解很远,梯度方向大致正确。大步子快速接近目标区域。
- 训练中期:参数进入最优解附近,梯度方向开始摇摆。步幅需要收窄,避免震荡。
- 训练后期:参数在最优解周围微调。小步幅精细搜索,找到真正的谷底。
动态学习率正好模拟了这个「先快后慢」的过程。
我的习惯:新项目我一般先用 Cosine Annealing + Warmup。Warmup 稳定初期,Cosine 平滑衰减,效果稳定。如果发现模型收敛太快,再换成 ReduceLROnPlateau 做自适应调整。
学习率与优化器的搭配
不同优化器对学习率的敏感度不一样:
- SGD:对学习率最敏感。需要精细调参,建议用 0.01 或 0.1 起步。
- Adam:相对鲁棒。默认 0.001 通常能 work,但未必最优。
- AdamW:和 Adam 类似,但 weight decay 和解耦后,学习率可以稍微大一点。
- RMSprop:适合 RNN,学习率建议 0.001 左右。
注意:不要盲目相信优化器的默认学习率。我见过太多人用 Adam 默认 0.001 训练一个模型,结果效果不好。其实把学习率调到 0.0005 或 0.002,效果可能天差地别。
学习率调参实战建议
这里分享几个我常用的方法:
- 学习率范围测试(LR Range Test):从一个很小的 lr 开始,每个 batch 指数增加 lr,观察 loss 变化。找到 loss 下降最快的 lr 区间。
- 先跑 5-10 个 epoch:观察 loss 曲线。如果 loss 震荡,降低 lr;如果 loss 下降太慢,提高 lr。
- 用 Cosine Annealing 兜底:不确定用什么策略时,Cosine Annealing 是个安全的选择。
- 记录每次实验的 lr:我习惯在实验日志里记下每次的 lr 和对应的收敛速度。时间久了,你会形成直觉。
一个小技巧:如果你用 PyTorch,可以用 torch.optim.lr_scheduler 里的 LambdaLR 自定义学习率曲线。我经常用它实现一些奇奇怪怪的衰减策略,比如先指数衰减再余弦重启。
学习率与损失景观的关系
为什么学习率这么重要?因为损失函数的表面(Loss Landscape)不是平滑的碗状,而是崎岖的山脉。
我画了一张图,帮你理解学习率在损失景观中的作用:
从这张图可以看得很清楚:
- 学习率过大(红色虚线):一步跨过最优区域,在谷底来回震荡
- 学习率过小(绿色虚线):在局部最优里打转,永远出不来
- 合适的学习率(橙色虚线):稳步沿着下坡走,最终到达全局最优
总结一下
学习率是模型训练中最关键的超参数,没有之一。它决定了模型能否收敛、收敛多快、收敛到多好。
我的建议是:
- 新项目先用动态学习率,别用固定的
- Warmup + Cosine Annealing 是个不错的起点
- 多跑几次学习率范围测试,找到合适的区间
- 记录每次实验的学习率,形成自己的经验库
调学习率这件事,说白了就是找平衡。步子太大容易扯着蛋,步子太小走不到头。找到那个「刚刚好」的节奏,模型训练就稳了。