Pytorch中的学习率调整
主要的学习率调整策略都是继承这个类:
class _LRScheduler
主要属性:
optimizer: 关联的优化器
last_epoch: 记录epoch数
base_lrs: 记录初始学习率
主要方法:
step():更新下一个epoch的学习率
get_lr():虚函数,计算下一个epoch的学习率
pytorch学习率调整方法
StepLR()
等间隔调整学习率
#函数形式
torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1)
# 参数:
optimizer: 优化器对象
step_size: 调整间隔数,根据epoch数设置间隔,若为 30,则会在 30、60、90…个 step 时,将学习率调整为 lr*gamma
gamma: 调整系数(学习率调整倍数,默认为 0.1 倍,即下降 10 倍)
last_epoch:上一个 epoch 数,这个变量用来指示学习率是否需要调整。当last_epoch 符合设定的间隔时,就会对 学习率进行调整。当为-1时,学习率设置为初始值
调整方式 lr = lr*gamma
# 实例
scheduler_lr = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1) # 设置学习率下降策略,实例化对象
scheduler_lr.step() # 更新学习率
实例:
LR = 0.1
iteration = 10
max_epoch = 200
scheduler_lr = optim.lr_scheduler.StepLR(optimizer, step_size=50, gamma=0.1) # 设置学习率下降策略
lr_list, epoch_list = list(), list()
for epoch in range(max_epoch):
lr_list.append(scheduler_lr.get_lr())
epoch_list.append(epoch)
for i in range(iteration):
loss = torch.pow((weights - target), 2)
loss.backward()
optimizer.step()
optimizer.zero_grad()
scheduler_lr.step()
plt.plot(epoch_list, lr_list, label="Step LR Scheduler")
plt.xlabel("Epoch")
plt.ylabel("Learning rate")
plt.legend()
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gGv4jloD-1610949310070)(C:\F\notebook\学习率调整策略\微信截图_20210118134901.png)]
从上面可以看出,每到50的倍数,学习率L R LRLR为原来的0.1倍
MultiStepLR()
按给定间隔调整学习率,这个方法适合后期调试使用,观察 loss 曲线,为每个实验 定制学习率调整时机
# 函数形式
torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1)
# 参数:
optimizer: 优化器对象
milestones: 指定需要调整的epoch位置,列表形式list
gamma: 调整系数
调整方式 lr = lr*gamma
# 实例
scheduler_lr = optim.lr_scheduler.MultiStepLR(optimizer, milestones=[2,5,8], gamma=0.1) # 设置学习率下降策略,实例化对象
scheduler_lr.step() # 更新学习率
实例:
LR = 0.1
iteration = 10
max_epoch = 200
milestones = [50, 125, 160]
scheduler_lr = optim.lr_scheduler.MultiStepLR(optimizer, milestones=milestones, gamma=0.1)
lr_list, epoch_list = list(), list()
for epoch in range(max_epoch):
lr_list.append(scheduler_lr.get_lr())
epoch_list.append(epoch)
for i in range(iteration):
loss = torch.pow((weights - target), 2)
loss.backward()
optimizer.step()
optimizer.zero_grad()
scheduler_lr.step()
plt.plot(epoch_list, lr_list, label="Multi Step LR Scheduler\nmilestones:{}".format(milestones))
plt.xlabel("Epoch")
plt.ylabel("Learning rate")
plt.legend()
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5z8ALtlA-1610949310074)(C:\F\notebook\学习率调整策略\微信截图_20210118132813.png)]由于设置了时刻数为50, 125, 160,因此从上图可以看出,在这几个点,学习率为原来的0.1倍
ExponentialLR()
按指数衰减调整学习率
# 函数形式
torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.95, last_epoch=-1)
# 功能: 按指数衰减调整学习率
# 参数:
optimizer: 优化器对象
gamma: 指数的底,通常接近1
调整方式 lr = lr*gamma**epoch
# 实例
scheduler_lr = optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.95) # 设置学习率下降策略,实例化对象
scheduler_lr.step() # 更新学习率
实例:
LR = 0.1
iteration = 10
max_epoch = 200
gamma = 0.95
scheduler_lr = optim.lr_scheduler.ExponentialLR(optimizer, gamma=gamma)
lr_list, epoch_list = list(), list()
for epoch in range(max_epoch):
lr_list.append(scheduler_lr.get_lr())
epoch_list.append(epoch)
for i in range(iteration):
loss = torch.pow((weights - target), 2)
loss.backward()
optimizer.step()
optimizer.zero_grad()
scheduler_lr.step()
plt.plot(epoch_list, lr_list, label="Exponential LR Scheduler\ngamma:{}".format(gamma))
plt.xlabel("Epoch")
plt.ylabel("Learning rate")
plt.legend()
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4W41TQ3g-1610949310076)(C:\F\notebook\学习率调整策略\微信截图_20210118134835.png)]
CosineAnnealingLR
余弦周期调整学习率,并在每个周期最大值时重新设置学习率
# 函数形式
scheduler_lr = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=t_max, eta_min=0.)
#参数
T_max:一次学习率周期的迭代次数,即 T_max 个 epoch 之后重新设置学习率
eta_min:最小学习率,即在一个周期中,学习率最小会下降到 eta_min,默认值为0
调整方式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2evWpCYe-1610949310079)(C:\F\notebook\学习率调整策略\1610942468.jpg)]
实例:
LR = 0.1
iteration = 10
max_epoch = 200
t_max = 50
scheduler_lr = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=t_max, eta_min=0.)
lr_list, epoch_list = list(), list()
for epoch in range(max_epoch):
lr_list.append(scheduler_lr.get_lr())
epoch_list.append(epoch)
for i in range(iteration):
loss = torch.pow((weights - target), 2)
loss.backward()
optimizer.step()
optimizer.zero_grad()
scheduler_lr.step()
plt.plot(epoch_list, lr_list, label="CosineAnnealingLR Scheduler\nT_max:{}".format(t_max))
plt.xlabel("Epoch")
plt.ylabel("Learning rate")
plt.legend()
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H3InyTSj-1610949310082)(C:\F\notebook\学习率调整策略\微信截图_20210118134821.png)]
ReduceLROnPlateau()
监控指标,当某指标不再变化(下降或升高),调整学习率,这是非常实用的学习率调整策略。 例如,当验证集的 loss 不再下降时,进行学习率调整;或者监测验证集的 accuracy,当 accuracy 不再上升时,则调整学习率
# 函数形式
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进行确定是否调整学习率
# 参数:
mode:min/max 两种模式
factor:调整系数
patience:“耐心”,接受几次不变化
cooldown:“冷却时间”,停止监控一段时间
verbose:是否打印日志
min_lr:学习率下限
eps:学习率衰减最小值
# 实例
scheduler_lr = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10)
# 设置学习率下降策略,实例化对象
scheduler_lr.step(loss) # 更新学习率
实例:
LR = 0.1
iteration = 10
max_epoch = 200
loss_value = 0.5
accuray = 0.9
factor = 0.1
mode = "min"
patience = 10
cooldown = 10
min_lr = 1e-4
verbose = True
scheduler_lr = optim.lr_scheduler.ReduceLROnPlateau(optimizer, factor=factor, mode=mode, patience=patience,cooldown=cooldown, min_lr=min_lr, verbose=verbose)
for epoch in range(max_epoch):
for i in range(iteration):
# train(...)
optimizer.step()
optimizer.zero_grad()
if epoch == 5:
loss_value = 0.4
scheduler_lr.step(loss_value)
# Epoch 17: reducing learning rate of group 0 to 1.0000e-02.
# Epoch 38: reducing learning rate of group 0 to 1.0000e-03.
# Epoch 59: reducing learning rate of group 0 to 1.0000e-04.
LambdaLR
自定义调整策略
- 主要参数:
lr_lambda
:一个计算学习率调整倍数的函数,输入通常为 step,当有多个参数组时,设为 list- 调整策略:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mGeQuIsd-1610949310084)(C:\F\notebook\学习率调整策略\微信截图_20210118134211.png)] - 实例:
LR = 0.1
iteration = 10
max_epoch = 200
lr_init = 0.1
weights_1 = torch.randn((6, 3, 5, 5))
weights_2 = torch.ones((5, 5))
optimizer = optim.SGD([
{'params': [weights_1]},
{'params': [weights_2]}], lr=lr_init)
lambda1 = lambda epoch: 0.1 ** (epoch // 20)
lambda2 = lambda epoch: 0.95 ** epoch
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=[lambda1, lambda2])
lr_list, epoch_list = list(), list()
for epoch in range(max_epoch):
for i in range(iteration):
# train(...)
optimizer.step()
optimizer.zero_grad()
scheduler.step()
lr_list.append(scheduler.get_lr())
epoch_list.append(epoch)
print('epoch:{:5d}, lr:{}'.format(epoch, scheduler.get_lr()))
plt.plot(epoch_list, [i[0] for i in lr_list], label="lambda 1")
plt.plot(epoch_list, [i[1] for i in lr_list], label="lambda 2")
plt.xlabel("Epoch")
plt.ylabel("Learning Rate")
plt.title("LambdaLR")
plt.legend()
plt.show()
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-djWdNG92-1610949310086)(C:\F\notebook\学习率调整策略\微信截图_20210118134432.png)]
学习率调整小结
PyTorch 提供了六种学习率调整方法,可分为三大类,分别是
- 有序调整:依一定规律有序进行调整,这一类是最常用的,分别是等间隔下降(Step),按需设定下降间隔(MultiStep),指数下降(Exponential)和 CosineAnnealing。这四种方法的调整时机都是人为可控的,也是训练时常用到的
- 自适应调整:依训练状况伺机调整,这就是 ReduceLROnPlateau 方法。该法通过监测某一 指标的变化情况,当该指标不再怎么变化的时候,就是调整学习率的时机,因而属于自适 应的调整
- 自定义调整:lambda 方法提供的调整策略十分灵活,我们可以为不 同的层设定不同的学习率调整方法,这在 fine-tune 中十分有用,我们不仅可为不同的层 设定不同的学习率,还可以为其设定不同的学习率调整策略