DeepLearning---学习率(Pytorch)

学习率的作用

学习率是梯度下降的重要参数,可以直接影响学习效果。
在梯度下降公式中

\[w=w-\alpha\frac{d}{dw}J(w) \]

\(\alpha\)就是学习率,决定了每次更新的“步幅”。 如果学习率太小,权重更新过慢,则需要很多步才能达到损失函数最小值。如果学习率过大,权重会更新的很快,模型在很短的时间内就会接近最小值,但是由于过大的“步幅”,可能会越过最小值,然后下次更新由于同样的原因再次越过,从而导致模型在损失函数最小值周围震荡。
某些损失函数可能存在多个局部最小值,模型在梯度下降时是随机前进的,可能进入某一个局部最小值,这并不是我们希望的结果,但是由于模型已经进入一个局部最小值,这意味着这个点周围的梯度就趋于 0,根据梯度下降公式,模型将很难从其中跳出。

需要注意的一点是,梯度更新的步幅由 \(\alpha\)\(\frac{d}{dw}J(w)\) 两个因子构成,即使我们采用固定的学习率,在梯度下降逼近损失函数最小值的过程中,导数项同样会向零逼近,这也是为什么即使采用固定大小的学习率,更然可以收敛到一个局部最小值,而不是在最小值周围震荡的原因。

如何设置学习率

当损失函数的图像在下降过程中不断出现震荡形状,即虽然总体呈下降趋势,但是中间会出现很多小幅上升,这可能意味着学习率设置过大(或者模型存在问题)。
image
这种情况通常意味着模型在损失函数最小值附近震荡。正常的情况是,损失函数应该在每个学习步中都是下降的。所以当训练损失函数出现上述征兆,可能需要考虑降低学习率再观察模型的表现。例如先采用 1e-3 的学习率,然后不断提高(吴恩达老师使用 3 倍的提高策略,即每次乘以 3)学习率,以找到一个合适的大小。

本文所讨论的损失均指训练损失,请不要和测试损失混淆,测试损失出现小幅波动是正常的。

如何选择初始的学习率有相应的研究,我之后会在 Article 分类中发布相关的论文总结,有兴趣的人可以先拜读一下这篇两千多引用的文章Cyclical Learning Rates for Training Neural Networks

学习率衰减

虽然根据梯度下降公式,即使采用固定学习率,下降步幅也会随着向局部最小值的收敛而不断减小,但是很多人仍然喜欢在训练过程中随 epoch 增加来手动降低学习率,从而使模型收敛的更好。

学习率衰减有以下三种方式:

  1. 轮数衰减:经过 n 个 epoch 后学习率减半
  2. 指数衰减:将学习率乘以一个衰减率 \(\alpha_t=0.95^{epoch}\times\alpha_{t-1}\)
  3. 分数衰减:以分式形式衰减 \(\alpha_i=\frac{\alpha_{t-1}}{1+delay_rate\times epoch}\)

但是学习率不断减小会带来另一个问题,即当模型遇到鞍点时,无法跳出鞍点。

很多文献认为影响模型收敛最大的困难在于存在很多局部最小值,但是 Identifying and attacking the saddle point problem in high-dimensional non-convex optimization 一文指出高维优化问题中并没有很多局部极值,而是存在很多鞍点。

当你的损失图像快速下降之后紧接着很久的持平,那你可能就是遇到了鞍点。你可能需要很长时间的训练才能摆脱鞍点,长到你可能都不知道这到底是鞍点还是最小值。

mini-batch 有助于逃离鞍点,因为这是一种有噪声的梯度估计,每个 mini-batch 都是不同的,相当于增加了随机扰动,导致我们在下降的过程中出现了偏离,从而摔下马鞍。同理,给梯度增加一点噪声也会有同样的效果。

Batch Normalization 也有助于解决这个问题。

Cyclical Learning Rates for Training Neural Networks一文同样研究如何逃离鞍点,其采用了比较复杂的学习率调整方法。

学习率衰减的 Pytorch 实现

pytorch 提供了实现学习率衰减的方法。使用的是 orch.optim.lr_sheduler 接口

等间隔衰减

torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1)

每经过 step_size 个 epoch,将学习率调整为 lr=lr*gamma,该方法类似轮数衰减。

多间隔衰减

torch.optim.lr_sheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1)

该方法传入 milestone(list) 参数用于指定需要衰减的 epoch,例如 milestone=[10,30,80] 表示在 10、30 和 80 轮的时候进行一次衰减。

指数衰减

torch.optim.lr_sheduler.ExponentialLR(optimizer, gamma, last_epoch)

顾名思义,其原理采用指数衰减公式。

余弦退火函数

按照余弦函数的趋势调整学习率

torch.optim.lr_sheduler.CosineAnnealingLR(optimizer, T_max, eta_min=0, last_epoch=-1)

T_max 参数指定余弦函数的半个周期,当 epoch=T_max 时学习率最低,该最低值由 eta_min 指定。

除此之外还有更多的实现方法,不再过多赘述,有兴趣的人可以查阅文档。

posted @ 2024-05-08 20:33  RubySIU  阅读(55)  评论(0编辑  收藏  举报