在 PyTorch 训练中使用学习率调度

训练神经网络或大型深度学习模型是一项困难的优化任务。

训练神经网络的经典算法叫做随机梯度下降。众所周知,通过使用在训练期间变化的学习率,可以在某些问题上提高性能并加快训练速度。

在这篇文章中,您将了解什么是学习率调度,以及如何在 PyTorch 中为神经网络模型使用不同的学习率调度。

阅读本文后,你将了解:

  • 学习率调度在模型训练中的作用
  • 如何在 PyTorch 训练循环中使用学习率调度
  • 如何设置您自己的学习率调度

想开始使用PyTorch进行深度学习吗?

立即参加我的免费电子邮件速成课程(附示例代码)。

点击注册,同时获得该课程的免费PDF电子书版本。


让我们开始吧。

在 PyTorch 训练中使用学习率调度
照片作者:Cheung Yin。部分权利保留。

概述

这篇博文分为三部分;它们是:

  • 用于训练模型的学习率调度
  • 在 PyTorch 训练中应用学习率调度
  • 自定义学习率调度

用于训练模型的学习率调度

梯度下降是一种数值优化算法。它的作用是使用以下公式更新参数:

$$
w := w – \alpha \dfrac{dy}{dw}
$$

在这个公式中,$w$ 是参数,例如神经网络中的权重,而 $y$ 是目标,例如损失函数。它的作用是将 $w$ 移动到可以最小化 $y$ 的方向。方向由微分 $\dfrac{dy}{dw}$ 提供,但 $w$ 的移动量由学习率 $\alpha$ 控制。

一个简单的开始是在梯度下降算法中使用恒定的学习率。但是,通过学习率调度,您可以做得更好。调度是为了使学习率适应梯度下降优化过程,从而提高性能并缩短训练时间。

在神经网络训练过程中,数据以批次的形式输入网络,每个时期(epoch)包含许多批次。每个批次会触发一次训练步骤,梯度下降算法会更新一次参数。然而,通常学习率调度是每个训练时期才更新一次。

您可以每步都更新学习率,但通常每个时期更新一次,因为您需要了解网络的性能才能确定学习率应如何更新。通常,模型会根据验证数据集每时期进行一次评估。

有多种使学习率自适应的方法。在训练开始时,您可能更喜欢较大的学习率,这样可以粗略地改进网络以加快进度。在非常复杂的神经网络模型中,您可能还希望在开始时逐渐增加学习率,因为您需要网络在预测的不同维度上进行探索。然而,在训练结束时,您总是希望学习率更小。因为那时,您即将从模型中获得最佳性能,并且如果学习率较大,很容易发生过拟合。

因此,在训练过程中调整学习率最简单也是也许最常用的方法是随着时间的推移降低学习率的技术。这些技术的好处是在训练过程的开始阶段,当使用较大的学习率值时,可以进行大的改动,并在训练过程的后期将学习率降低,从而对权重进行更小的改动。

这使得在早期可以快速学习到好的权重,并在后期进行微调。

接下来,我们看看如何在 PyTorch 中设置学习率调度。

通过我的《用PyTorch进行深度学习》一书来启动你的项目。它提供了包含可用代码自学教程

在 PyTorch 训练中应用学习率调度

在 PyTorch 中,模型由优化器更新,学习率是优化器的参数。学习率调度是一种用于更新优化器中学习率的算法。

下面是一个创建学习率调度的示例

PyTorch 在 torch.optim.lr_scheduler 子模块中提供了许多学习率调度器。所有调度器都需要优化器作为第一个参数进行更新。根据调度器的不同,您可能需要提供更多参数来设置。

让我们从一个示例模型开始。下面是一个用于解决电离层二分类问题的模型。这是一个小型数据集,您可以从 UCI 机器学习存储库下载。将数据文件放在您的工作目录中,文件名设置为 ionosphere.csv

电离层数据集非常适合练习神经网络,因为所有输入值都是较小的数值,且尺度相同。

构建了一个小型神经网络模型,包含一个具有 34 个神经元的隐藏层,使用 ReLU 激活函数。输出层有一个神经元,并使用 sigmoid 激活函数,以便输出类似概率的值。

使用纯随机梯度下降算法,学习率为固定的 0.1。模型训练 50 个时期。优化器的状态参数可以在 optimizer.param_groups 中找到;学习率是 optimizer.param_groups[0]["lr"] 中的一个浮点数值。在每个时期结束时,会打印出优化器的学习率。

完整的示例如下所示。

运行此模型会产生:

您可以确认在整个训练过程中学习率没有变化。让我们让训练过程以较大的学习率开始,并以较小的学习率结束。要引入学习率调度器,您需要在训练循环中运行其 step() 函数。上面的代码修改如下:

输出结果为:

在上面的代码中,使用了 LinearLR()。它是一个线性学习率调度器,接受三个附加参数:start_factorend_factortotal_iters。您将 start_factor 设置为 1.0,end_factor 设置为 0.5,total_iters 设置为 30,因此它会在 10 个等步长中使乘数因子从 1.0 减少到 0.5。在 10 步之后,因子将保持在 0.5。然后将此因子乘以优化器中的原始学习率。因此,您将看到学习率从 $0.1\times 1.0 = 0.1$ 降低到 $0.1\times 0.5 = 0.05$。

除了 LinearLR(),您还可以使用 ExponentialLR(),其语法为:

如果用这个替换 LinearLR(),您将看到学习率更新如下:

其中学习率通过在每个调度器更新时乘以一个常数因子 gamma 来更新。

自定义学习率调度

没有一般规则说明哪种学习率调度器效果最好。有时,您可能需要一个 PyTorch 未提供的特殊学习率调度器。可以使用自定义函数定义自定义学习率调度。例如,您希望学习率在时期 $n$ 时为

$$
lr_n = \dfrac{lr_0}{1 + \alpha n}
$$

其中 $lr_0$ 是初始学习率(时期 0 时),而 $\alpha$ 是一个常数。您可以实现一个函数,该函数给定时期 $n$ 来计算学习率 $lr_n$。

然后,您可以设置一个 LambdaLR() 来根据此函数更新学习率:

通过修改之前的示例来使用 LambdaLR(),您将得到以下代码:

这会产生:

请注意,尽管提供给 LambdaLR() 的函数假定参数为 epoch,但它并不与训练循环中的时期绑定,而只是计算您调用 scheduler.step() 的次数。

使用学习率调度的技巧

本节列出了一些在使用神经网络学习率调度时需要考虑的技巧。

  • 增加初始学习率。因为学习率很可能会降低,所以从一个较大的值开始以供降低。较大的学习率将在开始时导致权重的变化更大,从而使您能够受益于后期的微调。
  • 使用较大的动量。许多优化器可以考虑动量。使用较大的动量值将有助于优化算法在学习率缩小到较小值时继续朝着正确的方向进行更新。
  • 尝试不同的调度器。目前尚不清楚哪种学习率调度器最好。尝试几种不同的配置选项,看看哪种最适合您的问题。另外,尝试指数变化的调度器,甚至是对模型在训练集或测试集上准确率做出响应的调度器。

进一步阅读

以下是有关在 PyTorch 中使用学习率的更多详细文档:

总结

在这篇文章中,您学习了神经网络模型的学习率调度。

阅读本文后,您将了解:

  • 学习率如何影响您的模型训练
  • 如何在 PyTorch 中设置学习率调度
  • 如何创建自定义学习率调度

开始使用PyTorch进行深度学习!

Deep Learning with PyTorch

学习如何构建深度学习模型

...使用新发布的PyTorch 2.0库

在我的新电子书中探索如何实现
使用 PyTorch进行深度学习

它提供了包含数百个可用代码自学教程,让你从新手变成专家。它将使你掌握:
张量操作训练评估超参数优化等等...

通过动手练习开启你的深度学习之旅


查看内容

8 条回复关于 在 PyTorch 训练中使用学习率调度

  1. Tanner 2023年7月27日晚上11:56 #

    这篇文章写得很好,但语法错误很多,有时让人难以理解。

    • James Carmichael 2023年7月28日早上9:08 #

      感谢 Tanner 的反馈!

  2. FelixHao 2023年12月19日晚上8:22 #

    lr_lambda 不需要最后乘以 base_lr。如果您查看 PyTorch 的源代码,LambdaLR.get_lr 会为您处理这个问题。

    • James Carmichael 2023年12月20日早上9:43 #

      感谢 FelixHao 的澄清!

  3. SuBele 2024年2月9日晚上2:47 #

    这个学习率调度器也可以与 Adam 一起使用吗?

  4. Benjamin 2025年5月19日晚上7:13 #

    关于 LinearLR 中的 ‘total_iter’ 参数,您提到(引自文本):

    您将 start_factor 设置为 1.0,end_factor 设置为 0.5,total_iters 设置为 30,因此它将在 10 个等步长中使乘数因子从
    1.0 减少到 0.5。在 10 步之后,因子将保持在 0.5。

    我认为应该是

    您将 start_factor 设置为 1.0,end_factor 设置为 0.5,total_iters 设置为 30,因此它将在 10 个等步长中使乘数因子从
    1.0 减少到 0.5,在 30 个等步长中。在 30 步之后,因子将保持在 0.5。

    这正确吗?

    • James Carmichael 2025年5月20日凌晨2:06 #

      是的,您完全正确——文本中的引用关于步数是不正确的。

      以下是准确的解释:

      当使用 torch.optim.lr_scheduler.LinearLR 时,学习率在 start_factorend_factor 之间线性插值,持续时间由 total_iters 指定。在这些步数之后,学习率将保持在 end_factor 的恒定值。

      因此,如果您设置:

      * start\_factor = 1.0
      * end\_factor = 0.5
      * total\_iters = 30

      那么 PyTorch 将在 30 步内逐渐将学习率因子从 1.0 降低到 0.5——而不是 10 步。在第 30 步之后,因子将保持在 0.5。

      总结

      * 正确:学习率在 30 步内降低
      * 错误:说它在 10 步内降低

      感谢您指出这一点——您的修正完全正确。

留下回复

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。