Python torch.optim.lr_scheduler学习率调度器使用指南
在看学习率调度器之前,我们先看一下学习率的相关知识:
学习率
学习率的定义
学习率(Learning Rate)是深度学习中一个关键的超参数,它决定了在优化算法(如梯度下降法)更新模型参数时,参数调整的幅度。简单来说,它控制着模型在训练过程中朝着最小化损失函数方向前进的步伐大小。
假设我们使用简单的梯度下降法来更新模型的参数 ,对于损失函数
,其更新规则可以表示为:
其中, 就是学习率。这个公式的意思是,在参数更新时,我们沿着损失函数梯度的反方向(因为梯度方向是函数增长最快的方向,我们要求最小值,所以取反方向)移动,移动的步长由学习率
决定。
学习率的重要性
学习率过大 :
如果学习率设置得太大,在参数更新时可能会 “迈过” 最优解,导致模型在训练过程中不能稳定地收敛。例如,想象你在山上的一个点,想要下山走到山谷最低点。如果每一步都跨得很大,可能会跨过山谷底部,然后在山谷两侧来回震荡,甚至发散到山谷外面,无法到达真正的最低点。
学习率过小 :
相反,学习率太小会使模型的训练过程变得非常缓慢。就像下山时每一步都迈得非常小,可能需要花费很长时间才能走到山谷底部,并且在这个过程中可能会陷入局部最优解,因为步子太小而无法跳出局部的 “小山谷”。
学习率的调整策略
固定学习率 :在整个训练过程中保持学习率不变。这种方法简单,但如果初始学习率选择不当,可能会带来前面提到的收敛问题。不过,在一些简单的模型或者对训练速度和精度要求不特别高的场景下,可能是一种可行的策略。
动态学习率(部分) :
余弦退火(Cosine Annealing) :学习率按照余弦函数的形式进行变化。公式为 ,其中
是第 t 时刻的学习率,
和
分别是学习率的最小值和最大值,T 是一个周期。它可以让学习率在训练过程中周期性地变化,有助于模型在训练初期快速调整参数,在后期精细调整,以更好地收敛。
指数衰减(Exponential Decay) :学习率随着时间指数级地减小。公式为 ,其中
是初始学习率,k 是衰减系数,t 是训练的迭代次数。这种策略使得模型在训练初期有较大的学习率来快速调整参数,在训练后期学习率逐渐减小,使参数能更精细地逼近最优值。
步长衰减(Step Decay) :每隔一定数量的迭代次数,将学习率按照一定的比例衰减。例如,在迭代次数达到一定阈值 T 时,将学习率乘以一个衰减因子 (
通常小于 1),即
,这样可以有效控制学习率的下降速度,同时避免学习率下降过快或过慢。
学习率调度器
torch.optim.lr_scheduler
提供了多种学习率调度器,用于动态调整神经网络训练过程中的学习率,下面是一些常见的学习率调度器及其使用方法、输入参数和代码演示:
StepLR
StepLR 调度器会在训练过程中的每个指定步数间隔,按设定的衰减因子降低学习率。具体来说,每隔 step_size 个 epoch 或 iteration,学习率就乘以 gamma 参数,呈阶梯状衰减.
优势
参数 :
optimizer
:优化器,如 SGD、Adam 等。
step_size
:多少个 epoch 后更新一次学习率。
gamma
:学习率的衰减系数,默认为 0.1,每次调整时学习率都会乘以这个值。
last_epoch
:最后一次更新学习率的 epoch,默认为 -1,表示从头开始训练。
使用场景
分阶段训练 :当训练过程可以划分为多个明确的阶段,每个阶段需要不同学习率时,如先快速学习再细致调整,StepLR 可在前期用高学习率快速收敛,后期降低学习率精细调整模型参数。
明确的训练阶段划分 :如果训练任务有明确的阶段划分,且每个阶段对学习率有不同要求,StepLR 能按照预定步骤调整学习率,以适应不同阶段的训练需求。
实现简单 :StepLR 调度逻辑简单,参数配置少,易于理解和使用,只需设置 step_size 和 gamma 即可实现学习率的基本调整策略。
稳定收敛 :在训练后期降低学习率,可减小参数更新幅度,使模型更稳定地接近最优解,提升模型精度,减少因学习率过高导致的模型性能波动或发散问题。
局限性
固定调整模式 :其调整策略较为固定,不考虑训练过程中的损失变化、准确率提升等实际性能表现,可能无法满足复杂训练场景下的动态调整需求。
参数选择敏感 :对 step_size 和 gamma 参数的选择较为敏感,不合适的参数可能导致学习率调整不当,影响模型收敛速度和性能,如 step_size 过大可能延迟学习率下降时机,过小则可能使学习率下降过快。
代码演示
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import StepLR
model = nn.Linear(10, 1)
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
for epoch in range(40):
for inputs, labels in dataset:
optimizer.zero_grad()
outputs = model(inputs)
loss = nn.MSELoss()(outputs, labels)
loss.backward()
optimizer.step()
scheduler.step()
MultiStepLR
MultiStepLR 调度器是深度学习中用于调整学习率的一种策略,它允许用户在指定的多个 epoch 点按指定的因子调整学习率。
MultiStepLR 调度器会在训练过程中,当 epoch 达到预设的里程碑(milestones)时,将学习率乘以一个指定的衰减因子 gamma。通过这种方式,可以在训练的不同阶段灵活地调整学习率,帮助模型更稳定地收敛。
参数 :
optimizer
:优化器。
milestones
:一个列表,指明在哪些 epoch 进行学习率更新。包含了在训练过程中学习率要降低的 epoch 编号,列表中的 epoch 编号必须是递增的。
gamma
:学习率的衰减系数,默认为 0.1。
last_epoch
:最后一次更新学习率的 epoch,默认为 -1。
使用场景
多阶段训练 :当训练过程可以划分为多个明确的阶段,每个阶段需要不同的学习率时,MultiStepLR 可以在预设的 epoch 点调整学习率,满足不同阶段的训练需求。
特定任务需求 :对于一些特定任务或模型架构,需要在特定的 epoch 后调整学习率以优化性能,MultiStepLR 可以根据需求进行定制化的学习率调整。
优势
灵活性高 :用户可以根据具体的训练需求,灵活地指定在哪些 epoch 点调整学习率,以及调整的幅度,适用于各种复杂的训练场景。
稳定性强 :通过在需要的时期降低学习率,可以帮助模型在较小的学习率下进行更精细的权重更新,提高模型的泛化能力,使模型更稳定地收敛。
局限性
参数选择敏感 :对 milestones 和 gamma 参数的选择较为敏感,不合适的参数可能导致学习率调整不当,影响模型收敛速度和性能。如果指定的 milestones 过于频繁或 gamma 过小,可能会使学习率下降过快,导致模型训练过早收敛;反之,若 milestones 间隔过长或 gamma 过大,则可能无法及时降低学习率,使模型在后期训练中难以精细调整参数。
调整方式固定 :虽然比 StepLR 更灵活,但其调整方式仍然是按照预设的规则进行,无法根据训练过程中的实际性能表现(如损失变化、准确率变化等)动态地调整学习率。
代码演示
scheduler = MultiStepLR(optimizer, milestones=[5,10,30], gamma=0.1)
for epoch in range(40):
for inputs, labels in dataset:
optimizer.zero_grad()
outputs = model(inputs)
loss = nn.MSELoss()(outputs, labels)
loss.backward()
optimizer.step()
scheduler.step()
ExponentialLR
ExponentialLR 是 PyTorch 中一种以指数方式衰减学习率的调度器,它在每个 epoch 或每个 batch 后按固定的指数因子缩减学习率,帮助模型以更平滑、渐进的方式逼近最优解。以下是对其的详细解释:
ExponentialLR 的基本公式是:new_lr = initial_lr × gamma^epoch
。其中,initial_lr
是训练开始时设定的学习率,gamma
是一个小于 1 的常数,表示每个 epoch 学习率的缩减因子,控制学习率递减的速度。在每个 epoch 结束后,学习率都会乘以 gamma
这个因子,从而实现指数衰减
参数 :
optimizer
:优化器。
gamma
:学习率的衰减系数。
last_epoch
:最后一次更新学习率的 epoch,默认为 -1。
适用场景
ExponentialLR 适用于以下场景:
需要平稳且持续减小学习率的任务 :当希望学习率在整个训练过程中持续且缓慢降低,以避免训练后期的震荡,帮助模型稳定收敛时,ExponentialLR 是一个简单有效的选择。
训练过程相对稳定的任务 :在训练过程相对稳定,不需要复杂的学习率调整策略时,ExponentialLR 可以满足需求。
优势
平滑性 :通过指数方式平滑地减少学习率,避免了学习率骤降可能引发的不稳定性,从而有助于模型更好地收敛。
简单性与通用性 :只需设置一个简单的缩减因子 gamma,即可实现学习率的指数衰减,适用于许多不同类型的任务和模型。
局限性
参数选择敏感 :对 gamma 参数的选择较为敏感,不合适的 gamma 值可能导致学习率调整不当。如果 gamma 过小,学习率会下降过快,可能导致模型训练过早收敛;反之,若 gamma 过大,则学习率衰减过慢,可能无法及时降低学习率,使模型在后期训练中难以精细调整参数。
无法动态调整 :其调整方式是按照固定的指数衰减规则进行,无法根据训练过程中的实际性能表现(如损失变化、准确率变化等)动态地调整学习率。
代码演示
scheduler = ExponentialLR(optimizer, gamma=0.9)
for epoch in range(60):
for inputs, labels in dataset:
optimizer.zero_grad()
outputs = model(inputs)
loss = nn.MSELoss()(outputs, labels)
loss.backward()
optimizer.step()
scheduler.step()
ReduceLROnPlateau
ReduceLROnPlateau
是 PyTorch 中一种基于性能指标动态调整学习率的调度器。
基本原理
ReduceLROnPlateau
通过监控验证集上的性能指标(如验证损失或验证精度)来决定是否调整学习率。当指标在若干个 epoch 内停止改善时,它会将学习率按一定比例降低,从而帮助模型更好地收敛。这种动态调整策略适用于模型训练的后期,当模型性能提升变缓时,可以让模型更精细地学习。
参数 :
optimizer
:优化器。
mode
:指定监控指标的模式,"min" 表示指标越小越好,"max" 表示指标越大越好。
factor
:学习率的衰减系数,默认为 0.1。
patience
:多少个 epoch 验证指标没有改善后,更新学习率。
verbose
:如果为 True,则在学习率更新时打印信息。
threshold
:判断指标是否改善的阈值,默认为 1e-4。
threshold_mode
:指定判断指标是否改善的模式,"rel" 表示相对变化,"abs" 表示绝对变化。
cooldown
:学习率更新后,多少个 epoch 不监控指标变化。
min_lr
:学习率的下限,默认为 0。
eps
:用于比较的epsilon值,默认为 1e-8。
使用场景
当模型在验证集上的性能长时间不再提升时,通过降低学习率,可以让模型更细致地搜索最优解。
对于学习率敏感的优化器(如 SGD),在训练后期使用 ReduceLROnPlateau
可以提高模型性能。
优势
动态调整:根据模型的实际性能表现动态调整学习率,比固定的调整策略更灵活。
自适应性:能够自适应地降低学习率,适合模型在不同训练阶段的需求。
局限性
依赖监控指标:需要选择合适的监控指标,并确保其与模型训练目标一致。
参数选择敏感:对参数(如 patience
、factor
等)的选择较为敏感,不合适的参数可能导致学习率调整不当。
代码演示
scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=5, verbose=True)
for epoch in range(40):
for inputs, labels in dataset:
optimizer.zero_grad()
outputs = model(inputs)
loss = nn.MSELoss()(outputs, labels)
loss.backward()
optimizer.step()
scheduler.step(loss)
CosineAnnealingLR
CosineAnnealingLR
是 PyTorch 中一种基于余弦退火方法调整学习率的调度器。
基本原理
CosineAnnealingLR
通过余弦退火策略逐渐减小学习率,其核心思想是让学习率按照余弦函数的形状进行变化,从初始学习率开始,在训练过程中逐渐减小到一个最小值,通常在训练后期再慢慢回升。这种方式可以使学习率在训练过程中更加平滑地变化,有助于模型更好地收敛,并在训练后期更细致地调整参数。
参数 :
optimizer
:优化器。
T_max
:最大周期数,即多少个 epoch 后重新开始一个余弦周期。
eta_min
:学习率的下限,默认为 0。
last_epoch
:最后一次更新学习率的 epoch,默认为 -1。
适用场景
需要平稳学习率调整的任务:当希望学习率在整个训练过程中平滑地减小,并在训练后期避免振荡时,可以使用 CosineAnnealingLR
。
复杂模型训练:对于一些复杂的模型,如深度神经网络,CosineAnnealingLR
可以帮助更好地寻找全局最优解,尤其在大规模数据集训练时,能够提高模型的泛化能力。
优势
平滑学习率变化:通过余弦函数的平滑特性,使学习率在训练过程中逐渐减小,避免了学习率骤降可能引发的不稳定性,提高了训练的稳定性。
提升模型性能:帮助模型在训练后期更细致地调整参数,从而提升最终的模型性能。
局限性
非线性调整的复杂性:余弦退火的学习率调整方式较为复杂,可能需要更多试验来确定合适的参数组合。
参数选择敏感:对 T_max
和 eta_min
参数的选择较为敏感,不合适的参数可能导致学习率调整不当,影响模型的收敛速度和性能。
防止过拟合:随着学习率的减小,模型的参数更新步伐减慢,可以有效防止过拟合。
scheduler = CosineAnnealingLR(optimizer, T_max=30,eta_min = 1e-4)
for epoch in range(60):
for inputs, labels in dataset:
optimizer.zero_grad()
outputs = model(inputs)
loss = nn.MSELoss()(outputs, labels)
loss.backward()
optimizer.step()
scheduler.step()
LambdaLR
LambdaLR
是 PyTorch 中一种高度灵活的学习率调度器,它允许用户通过自定义函数来动态调整学习率。
基本原理
LambdaLR
通过用户定义的 lambda 函数来确定学习率的调整方式。在每个 epoch 结束时,调度器会根据当前 epoch 数调用 lambda 函数,计算出一个学习率乘法因子,然后用该因子乘以初始学习率来更新当前学习率。公式如下: 其中,λ(epoch) 是用户定义的函数,base_lr 是初始学习率。
输入参数 :
optimizer
:优化器,用于更新模型参数。
lr_lambda
:一个函数或函数列表,每个函数根据当前 epoch 返回一个学习率乘数。如果使用多个参数组,则 lr_lambda
的长度应与参数组数量相同。
last_epoch
:最后一次更新学习率的 epoch,默认为 -1,表示从头开始训练。
适用场景
灵活自定义学习率调整策略:当需要实现复杂的学习率调整策略,而其他预定义的调度器无法满足需求时,LambdaLR
是一个理想的选择。例如,可以设计指数衰减、阶梯衰减或其他任意形式的学习率变化规则。
多参数组学习率独立调整:如果模型的不同参数组需要不同的学习率调整策略,LambdaLR
的 lr_lambda
参数可以是一个函数列表,每个函数对应一个参数组,从而实现对不同参数组学习率的独立控制。
优势
高度灵活:用户可以根据具体需求定义任意复杂的学习率变化规则,适合各种特殊场景。
便于实验:适合研究者快速测试不同的学习率调度策略,能够方便地调整和验证不同的 lambda 函数对模型训练效果的影响。
支持多组参数:支持对不同参数组设置不同的学习率调整函数,能够更好地满足模型训练中不同部分的优化需求。
局限性
学习率调整复杂度高:由于学习率的变化完全由用户定义的函数决定,对于一些没有经验的研究者或开发者来说,设计出合适的学习率调整函数可能具有一定难度。
参数选择敏感:不合适的 lambda 函数可能导致学习率调整不当,影响模型的收敛速度和性能。
import torch
import torch.nn as nn
import torch.optim as optim
model = nn.Linear(5, 3)
optimizer = optim.SGD(model.parameters(), lr=0.01)
def custom_lr_lambda(epoch):
if epoch < 10: # 第1阶段:前10个epoch,学习率线性增加
return (epoch + 1) / 10.0
elif epoch < 30: # 第2阶段:10到30个epoch,学习率保持恒定
return 1.0
elif epoch < 50: # 第3阶段:30到50个epoch,学习率按指数衰减
return 0.1 ** ((epoch - 30) / 20.0)
else: # 第4阶段:50个epoch之后,学习率保持最低值
return 0.01
scheduler = optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=custom_lr_lambda)
for epoch in range(60):
for inputs, labels in dataset:
optimizer.zero_grad()
outputs = model(inputs)
loss = nn.MSELoss()(outputs, labels)
loss.backward()
optimizer.step()
scheduler.step()
CyclicLR
CyclicLR
是 PyTorch 中一种循环学习率调度器,它根据循环学习率策略(Cyclical Learning Rate, CLR)动态调整学习率。
基本原理
CyclicLR
根据循环学习率策略,让学习率在两个边界(base_lr
和 max_lr
)之间以恒定频率循环变化。在每个 batch 结束后,调度器会更新学习率。
输入参数 :
optimizer
:所使用的优化器。
base_lr
:初始学习率,是每个参数组的下界。
max_lr
:每个参数组的上界,定义了循环的振幅(max_lr - base_lr
)。
step_size_up
:在循环的上升阶段中,学习率从 base_lr
增加到 max_lr
所需的训练迭代次数。
step_size_down
:在循环的下降阶段中,学习率从 max_lr
减少到 base_lr
所需的训练迭代次数。若为 None
,则默认与 step_size_up
相同。
mode
:学习率调整的模式,可选 'triangular'
(无幅度缩放的三角形循环)、'triangular2'
(每个循环将初始振幅缩放一半的三角形循环)、'exp_range'
(每个循环迭代按 gamma^cycle_iterations
缩放初始振幅)。
gamma
:在 'exp_range'
模式下,缩放初始振幅的因子。
scale_fn
:自定义的缩放策略,是一个单参数的 lambda 函数,其值域为 [0, 1]
。若指定,则 mode
参数会被忽略。
scale_mode
:定义 scale_fn
是基于周期还是迭代次数来计算。
cycle_momentum
:是否循环动量,若为 True
,动量会与学习率反向变化。
base_momentum
:动量的下界。
max_momentum
:动量的上界。
last_epoch
:上一个 epoch 的索引,用于恢复训练。
适用场景
训练复杂网络:在训练复杂网络时,CyclicLR
可以提供动态调整学习率的能力,帮助模型更好地收敛。
需要频繁调整学习率的任务:对于需要在训练过程中频繁调整学习率的任务,CyclicLR
可以以一定的频率调整学习率,而无需手动干预。
超参数搜索:在搜索超参数时,CyclicLR
可以帮助找到合适的学习率范围,从而提高模型性能。
优势
提高模型性能:通过动态调整学习率,可以在训练过程中更好地探索损失函数的曲面,从而提高模型的性能。
防止陷入局部最优:学习率的循环变化有助于模型跳出局部最优,继续寻找更优的解。
适用范围广:适用于多种不同的训练任务,尤其是那些对学习率敏感的任务。
局限性
参数选择复杂:需要选择多个参数(如 base_lr
、max_lr
、step_size_up
等),不合适的参数可能导致学习率调整不当,影响模型的收敛速度和性能。
不适合所有模型:对于一些简单的模型或任务,CyclicLR
可能不会带来显著的性能提升,反而增加了训练的复杂性。
代码演示
import torch
import torch.nn as nn
import torch.optim as optim
model = nn.Linear(5, 3)
optimizer = optim.SGD(model.parameters(), lr=0.001)
scheduler = optim.lr_scheduler.CyclicLR(
optimizer,
base_lr=0.005,
max_lr=0.01,
step_size_up=10,
step_size_down=10,
mode='triangular',
cycle_momentum=False
),
for epoch in range(60):
for i, (inputs, labels) in enumerate(dataset):
optimizer.zero_grad()
outputs = model(inputs)
loss = nn.MSELoss()(outputs, labels)
loss.backward()
optimizer.step()
scheduler.step()
OneCycleLR
OneCycleLR
是 PyTorch 中一种基于 1cycle 策略的学习率调度器,旨在通过动态调整学习率和动量来加速模型训练并提高性能。
基本原理
OneCycleLR
的核心思想是将学习率从一个较低的初始值逐渐增加到一个最大值,然后再逐步降低到一个比初始值更小的最小值。动量变化通常是相反的:动量从高到低再回到中间值。整个过程在一个训练周期内完成,不需要多个周期重复。这种策略能帮助模型更好地收敛,提高训练效率。
输入参数 :
optimizer
:优化器。
max_lr
:学习率的最大值。
total_steps
:整个训练过程的总步数,如果不指定,则需要同时指定 epochs
和 steps_per_epoch
。
epochs
:训练的总 epoch 数。
steps_per_epoch
:每个 epoch 的步数。
pct_start
:学习率提升阶段所占整个训练周期的比例,默认为 0.3。
anneal_strategy
:退火策略,可选 'cos'
或 'linear'
,分别代表余弦退火和线性退火。
cycle_momentum
:是否调整动量,默认为 True
。如果为 True
,动量会随着学习率的变化而反向变化。
base_momentum
:动量的最小值。
max_momentum
:动量的最大值。
div_factor
:初始学习率是 max_lr
除以 div_factor
的比值。
final_div_factor
:最终学习率是 max_lr
除以 final_div_factor
的比值。
three_phase
:如果为 True
,则训练过程分为三个阶段:提升学习率、第一次降低学习率、第二次降低学习率。
适用场景
需要快速收敛的任务:适合在训练初期快速提高学习率以加快参数调整,使模型在较短时间内收敛。
对学习率敏感的模型:能有效调整学习率,避免学习率过高或过低导致的模型训练问题。
优势
加速训练:通过在训练初期快速提升学习率,能更快地进行模型参数调整,使模型快速收敛。
提升模型性能:提供更优的优化路径,从而提高模型的最终表现。
减少手工调参需求:系统性的学习率安排减少了对多次调试不同学习率曲线的需求。
局限性
参数选择敏感:不合适的参数可能导致学习率调整不当,影响模型的收敛速度和性能。
适用范围有限:对于一些简单的模型或任务,OneCycleLR
可能不会带来显著的性能提升。
import torch
import torch.nn as nn
import torch.optim as optim
model = nn.Linear(5, 3)
optimizer = optim.SGD(model.parameters(), lr=0.01)
scheduler = optim.lr_scheduler.OneCycleLR(
optimizer,
max_lr=0.1,
epochs=60,
steps_per_epoch=2,
pct_start=0.25,
anneal_strategy='cos',
cycle_momentum=True,
base_momentum=0.85,
max_momentum=0.95,
div_factor=25.0,
final_div_factor=10000.0
),
for epoch in range(60):
for inputs, labels in dataset:
optimizer.zero_grad()
outputs = model(inputs)
loss = nn.MSELoss()(outputs, labels)
loss.backward()
optimizer.step()
scheduler.step()
作者:basketball616