这里主要记录两种比较常用的学习率调整的策略:学习率预热(warmup)和学习率衰减。
学习率预热
学习率预热是在训练开始阶段逐渐增加学习率,以帮助模型更好地收敛。预热阶段通常在训练的前几个epoch中进行,随后再根据预定义的衰减策略进行学习率衰减。
示例代码如下:
import torch
import torch.optim as optim
import torch.optim.lr_scheduler as lr_scheduler
# 定义优化器和学习率调度器
model = YourModel()
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.1)
# 学习率预热参数
warmup_epochs = 5
warmup_lr_init = 0.01
warmup_lr_end = 0.1
# 在训练循环中更新学习率
for epoch in range(warmup_epochs):
# 计算当前预热阶段的学习率
warmup_lr = warmup_lr_init + (warmup_lr_end - warmup_lr_init) * epoch / warmup_epochs
# 设置当前阶段的学习率
for param_group in optimizer.param_groups:
param_group['lr'] = warmup_lr
# 训练模型的代码
# 更新学习率调度器
scheduler.step()
# 正常训练阶段,学习率衰减
for epoch in range(warmup_epochs, num_epochs):
# 训练模型的代码
# 更新学习率调度器
scheduler.step()
在上述示例中,我们首先定义了一个模型和一个优化器,然后创建了一个学习率调度器(这里使用了StepLR作为示例)。接下来,我们设置了学习率预热的参数,包括预热阶段的迭代次数(warmup_epochs)以及初始学习率(warmup_lr_init)和最终学习率(warmup_lr_end)。
在训练循环的前warmup_epochs个迭代中,我们逐渐增加学习率,从warmup_lr_init线性地增加到warmup_lr_end。在每个迭代中,我们根据当前的学习率更新优化器的参数组。
之后,我们进入正常的训练阶段,使用学习率调度器进行学习率衰减(StepLR的示例中,每个epoch后学习率会按照设置的gamma进行衰减)。
通过这样的学习率预热机制,可以使模型在训练初期更好地适应数据,提高训练的稳定性和性能。根据实际需求,可以根据预热阶段的迭代次数、初始学习率和最终学习率来调整预热效果。
学习率衰减
学习率衰减是在模型训练中一种常见的策略,它在训练的过程中逐渐降低学习率。
常见的学习率衰减方法包括:
- 常数衰减:按照人工预定义的衰减频率或衰减步骤进行衰减
- 自适应衰减:通过监测某一指标(如loss)的变化情况,当该指标不变化或者变化较小时,调整学习率;
- 自定义衰减:Lambda方法提供的调整策略十分灵活,我们可以为不同的层设定不同的学习率调整方法,这在fine-tune中十分有用,我们不仅可为不同的层设定不同的学习率,还可以为其设定不同的学习率调整策略。
pytorch中针对上述三种不同的衰减策略内置了6个学习率衰减的函数,依次如下:
1)StepLR 学习率衰减(按固定步长衰减)
函数定义
class torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1)
功能: 等间隔调整学习率,调整倍数为gamma倍,调整间隔为step_size。间隔单位是step。需要注意的是,step通常是指epoch,而不是iteration。
参数:
step_size(int):学习率下降间隔数,若为30,则会在30、60、90…个epoch时,将学习率调整为lr*gamma。
gamma(float): 学习率调整倍数,默认为0.1倍,即下降10倍。
last_epoch(int):上一个epoch数,这个变量用来指示学习率是否需要调整。当last_epoch符合设定的间隔时,就会对学习率进行调整。当为-1时,学习率设置为初始值。
示例代码:
import torch
import torch.optim as optim
import torch.optim.lr_scheduler as lr_scheduler
# 定义优化器和学习率调度器
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)
# 在训练循环中更新学习率
for epoch in range(num_epochs):
# 训练模型的代码
# 更新学习率
scheduler.step()
2)MultiStepLR 学习率衰减
函数定义
class torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1)
功能: 在指定的epoch处衰减
参数:
milestones(list): 一个list,每一个元素代表何时调整学习率,list元素必须是递增的。如 milestones=[30,90,120]
gamma(float):学习率调整倍数,默认为0.1倍,即下降10倍。
last_epoch(int) :同上
示例代码
import torch
import torch.optim as optim
import torch.optim.lr_scheduler as lr_scheduler
# 定义优化器和学习率调度器
optimizer = optim.SGD(model.parameters(), lr=0.1)
milestones = [30, 90, 120] # 里程碑(epoch)列表
scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=milestones, gamma=0.1)
# 在训练循环中更新学习率
for epoch in range(num_epochs):
# 训练模型的代码
# 更新学习率
scheduler.step()
3)CosineAnnealingLR 学习率衰减(余弦退火衰减)
函数定义
class torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max, eta_min=0, last_epoch=-1)
功能: 以余弦函数为周期,并在每个周期最大值时重新设置学习率。衰减的原理是将学习率从一个较大的初始值逐渐减小到一个较小的最小值,然后再逐渐增加回初始值。在每个周期(设定的epoch数)内,学习率都会按照余弦函数的形式进行调整,使得学习率在训练过程中逐渐变化。
具体来说,CosineAnnealingLR 方法根据给定的周期数(T_max)和最小学习率(eta_min),在每个周期内计算学习率的更新值。学习率在每个周期的前半段呈现余弦递减的趋势,后半段则逐渐增加回初始值。每个周期结束后,学习率都会重置为初始值。
参数:
T_max(int): 一次学习率周期的迭代次数,即T_max个epoch之后重新设置学习率。
eta_min(float): 最小学习率,即在一个周期中,学习率最小会下降到eta_min,默认值为0
示例代码:
import torch
import torch.optim as optim
import torch.optim.lr_scheduler as lr_scheduler
# 定义模型和优化器
model = YourModel()
optimizer = optim.SGD(model.parameters(), lr=0.1)
# 定义学习率调度器
T_max = 10 # 周期数
eta_min = 0.01 # 最小学习率
scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max=T_max, eta_min=eta_min)
# 在训练循环中更新学习率
for epoch in range(num_epochs):
# 训练模型的代码
# 更新学习率调度器
scheduler.step()
4)ExponentialLR 学习率衰减(按指数衰减)
函数定义
class torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=-1)
功能: 按指数衰减调整学习率,调整公式: lr = lr * gamma**epoch
参数:
gamma: 学习率调整倍数的底,指数为epoch,即 gamma**epoch
last_epoch(int):同上
示例代码:
import torch
import torch.optim as optim
import torch.optim.lr_scheduler as lr_scheduler
# 定义优化器和学习率调度器
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = lr_scheduler.ExponentialLR(optimizer, gamma=0.95)
# 在训练循环中更新学习率
for epoch in range(num_epochs):
# 训练模型的代码
# 更新学习率
scheduler.step()
5)ReduceLROnPlateau 学习率衰减(基于指标的变化)
函数定义
class torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10, verbose=False, threshold=0.0001, threshold_mode='rel', cooldown=0, min_lr=0, eps=1e-08)
功能: 当某指标不再变化(下降或升高),调整学习率,这是非常实用的学习率调整策略。例如,当验证集的loss不再下降时,进行学习率调整;或者监测验证集的accuracy,当accuracy不再上升时,则调整学习率。
参数:
mode(str): 模式选择,有 min和max两种模式,min表示当指标不再降低(如监测loss),max表示当指标不再升高(如监测accuracy)。
factor(float): 学习率调整倍数(等同于其它方法的gamma),即学习率更新为 lr = lr * factor patience(int)- 直译——“耐心”,即忍受该指标多少个step不变化,当忍无可忍时,调整学习率。注,可以不是连续5次。
verbose(bool)-:是否打印学习率信息
threshold(float): Threshold for measuring the new optimum,配合threshold_mode使用,
默认值1e-4。作用是用来控制当前指标与best指标的差异。
threshold_mode(str): 选择判断指标是否达最优的模式,有两种模式,rel和abs。
当threshold_mode = rel,并且mode = max时,dynamic_threshold = best * ( 1 + threshold ); 当threshold_mode = rel,并且mode = min时,dynamic_threshold = best * ( 1 - threshold ); 当threshold_mode = abs,并且mode = max时,dynamic_threshold = best + threshold ; 当threshold_mode = rel,并且mode = max时,dynamic_threshold = best - threshold
cooldown(int): “冷却时间“,当调整学习率之后,让学习率调整策略冷静一下,让模型再训练一段时间,再重启监测模式。
min_lr(float or list):学习率下限,可为float,或者list,当有多个参数组时,可用list进行设置。
eps(float): 学习率衰减的最小值,当学习率变化小于eps时,则不调整学习率。
示例代码:
import torch
import torch.optim as optim
import torch.optim.lr_scheduler as lr_scheduler
# 定义优化器和学习率调度器
optimizer = optim.SGD(model.parameters(), lr=0.1)
scheduler = lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=5)
# 在训练循环中更新学习率
for epoch in range(num_epochs):
# 训练模型的代码
# 计算损失
loss = ...
# 更新学习率
scheduler.step(loss)
6)LambdaLR 学习率衰减(使用自定义的衰减函数)
函数定义
class torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=-1)
功能: 为不同参数组设定不同学习率调整策略。
调整规则为,lr = base_lr * lambda(self.last_epoch) 。
它允许根据自定义的衰减函数动态地调整学习率。LambdaLR 提供了一种灵活的方式来定义学习率的变化规律,可以根据训练的进程或其他自定义条件来调整学习率。
在 LambdaLR 中,我们需要定义一个衰减函数 lambda_fn,该函数接受当前训练的 epoch 数作为输入,并返回一个学习率的缩放因子。缩放因子会与初始学习率相乘,从而得到调整后的学习率。
参数:
lr_lambda(function or list): 一个计算学习率调整倍数的函数,输入通常为step,当有多个参数组时,设为list。
last_epoch(int):同上
示例代码:
import torch
import torch.optim as optim
import torch.optim.lr_scheduler as lr_scheduler
# 定义模型和优化器
model = YourModel()
optimizer = optim.SGD(model.parameters(), lr=0.1)
# 定义学习率调度器
lambda_fn = lambda epoch: 0.5 ** epoch # 自定义衰减函数
scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda_fn)
# 在训练循环中更新学习率
for epoch in range(num_epochs):
# 训练模型的代码
# 更新学习率调度器
scheduler.step()
在上述示例中,我们定义了一个模型和一个优化器,并创建了一个 LambdaLR 的学习率调度器。我们使用 lambda_fn 函数作为衰减函数,它以当前 epoch 数作为输入,并返回一个缩放因子。在每个 epoch 结束后,我们调用 scheduler.step() 方法来更新学习率。
通过使用 LambdaLR,我们可以根据自定义的衰减函数灵活地调整学习率。在示例中,我们使用指数衰减函数,每个 epoch 学习率减半,但你可以根据需要定义其他衰减规则。
需要注意的是,使用 LambdaLR 时,衰减函数的设计很关键。确保衰减函数能够合理地调整学习率,以便在训练过程中获得更好的收敛效果。可以根据具体问题和实验结果来调整衰减函数的形式和参数。
参考:
https://zhuanlan.zhihu.com/p/69411064
以上即为平时比较常见的集中学习率调整方法。