torch.optim.lr_scheduler
提供了三种根据epoch训练数来调整学习率(learning rate)的方法。具体方法如下:
torch.optim.lr_scheduler.StepLR
n e w − l r = i n i t i a l − l r ∗ γ e p o c h s t e p − s i z e new_-lr=initial_-lr*\gamma^{\frac{epoch}{step_-size}} new−lr=initial−lr∗γstep−sizeepoch
更新策略:
每过step_size个epoch,学习率进行一次更新
n e w − l r new_-lr new−lr:新得到的学习率。
i n i t i a l − l r initial_-lr initial−lr:初始学习率。
γ \gamma γ:参数gamma
,更新 l r lr lr的乘法因子。
s t e p − s i z e step_-size step−size:每训练step_size个epoch,更新一次 l r lr lr。
l a s t − e p o c h last_-epoch last−epoch:最后一个epoch的index,如果是训练了很多个epoch后中断了,继续训练,这个值就等于加载的模型的epoch。默认为-1表示从头开始训练,即从epoch=1开始。
代码如下:
import matplotlib.pyplot as plt
import torch
import torch.optim as optim
from torch.optim.lr_scheduler import StepLR
from torchvision.models import AlexNet
num_epochs = 100
#定义2分类网络
model = AlexNet(num_classes=2)
optimizer = optim.SGD(params=model.parameters(), lr=0.05)
scheduler = StepLR(
optimizer=optimizer,
step_size=20, # 设定调整的间隔数
gamma=0.5, # 系数
last_epoch=-1
)
# 迭代训练
lrs, epochs = [], []
for epoch in range(num_epochs):
lrs.append(scheduler.get_lr()) #.get_lr()获取当前学习率
epochs.append(epoch)
pass # 在这里进行迭代训练
#学习率更新
scheduler.step()
# visualize
plt.figure()
plt.legend()
plt.plot(epochs, lrs, label='StepLR')
plt.show()
torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1)
n e w − l r = i n i t i a l − l r ∗ γ b i s e c t − r i g h t ( m i l e s t o n e s , e p o c h ) new_-lr=initial_-lr*\gamma ^{bisect_-right(milestones,epoch)} new−lr=initial−lr∗γbisect−right(milestones,epoch)
更新策略:
每次遇到milestones
中的epoch
,学习率做一次更新。
n e w − l r new_-lr new−lr:新得到的学习率。
i n i t i a l − l r initial_-lr initial−lr:初始学习率。
γ \gamma γ:参数gamma
,更新 l r lr lr的乘法因子。
m i l e s t o n e s milestones milestones:递增的list,存放需要更新 l r lr lr的epoch。
l a s t − e p o c h last_-epoch last−epoch:最后一个epoch的index,如果是训练了很多个epoch后中断了,继续训练,这个值就等于加载的模型的epoch。默认为-1表示从头开始训练,即从epoch=1开始。
b i s e c t − r i g h t ( m i l e s t o n e s , e p o c h ) bisect_-right(milestones,epoch) bisect−right(milestones,epoch):bisect
模块中的bisect_right
函数,返回值是把epoch
插入排序好的列表milestones
式的位置。
代码如下:
import matplotlib.pyplot as plt
import torch
import torch.optim as optim
from torch.optim.lr_scheduler import MultiStepLR
from torchvision.models import AlexNet
num_epochs = 100
#定义2分类网络
model = AlexNet(num_classes=2)
optimizer = optim.SGD(params=model.parameters(), lr=0.05)
scheduler = MultiStepLR(
optimizer=optimizer,
milestones=[10, 20, 40], # 设定调整的间隔数
gamma=0.5, # 系数
last_epoch=-1
)
# train-like iteration
lrs, epochs = [], []
for epoch in range(num_epochs):
lrs.append(scheduler.get_lr()) #.get_lr()获取当前学习率
epochs.append(epoch)
pass # 在这里进行迭代训练
#学习率更新
scheduler.step()
# visualize
plt.figure()
plt.legend()
plt.plot(epochs, lrs, label='MultiStepLR')
plt.show()
其中最后一个epoch的index,如果是训练了很多个epoch后中断了,继续训练,这个值就等于加载的模型的epoch。默认为-1表示从头开始训练,即从epoch=1开始。
3.指数衰减调整(Exponential):torch.optim.lr_scheduler.ExponentialLR
n e w − l r = i n i t i a l − l r ∗ γ e p o c h new_-lr=initial_-lr*\gamma ^{epoch} new−lr=initial−lr∗γepoch
import matplotlib.pyplot as plt
import torch
import torch.optim as optim
from torch.optim.lr_scheduler import ExponentialLR
from torchvision.models import AlexNet
import seaborn as sns
num_epochs = 100
#定义2分类网络
model = AlexNet(num_classes=2)
optimizer = optim.SGD(params=model.parameters(), lr=0.05)
scheduler = ExponentialLR(
optimizer=optimizer,
gamma=0.5, # 系数
last_epoch=-1
)
# train-like iteration
lrs, epochs = [], []
for epoch in range(num_epochs):
lrs.append(scheduler.get_lr()) #.get_lr()获取当前学习率
epochs.append(epoch)
pass # 在这里进行迭代训练
#学习率更新
scheduler.step()
# visualize
plt.figure()
plt.plot(epochs, lrs, label='ExponentialLR')
plt.legend()
plt.show()
4.余弦退火调整(CosineAnnealing):torch.optim.lr_sheduler.CosineAnnealingLR
n e w − l r = e t a − m i n + ( i n i t i a l − l r − e t a − m i n ) ∗ ( 1 + c o s ( e p o c h T − m a x ∗ π ) ) new_-lr=eta_-min+(initial_-lr-eta_-min)*(1+cos(\frac{epoch}{T_-max}*\pi )) new−lr=eta−min+(initial−lr−eta−min)∗(1+cos(T−maxepoch∗π))
更新策略:
每次遇到milestones
中的epoch
,学习率做一次更新。
n e w − l r new_-lr new−lr:新得到的学习率。
i n i t i a l − l r initial_-lr initial−lr:初始学习率。
e t a − m i n eta_-min eta−min:表示最小学习率。
T − m a x T_-max T−max:代表1/2个cos周期所对应的epoch值,学习率下降到最小值时的epoch数,即当epoch=T_max时,学习率下降到余弦函数最小值,当epoch>T_max时,学习率将增大;
l a s t − e p o c h last_-epoch last−epoch:最后一个epoch的index,如果是训练了很多个epoch后中断了,继续训练,这个值就等于加载的模型的epoch。默认为-1表示从头开始训练,即从epoch=1开始。
import matplotlib.pyplot as plt
import torch
import torch.optim as optim
from torch.optim.lr_scheduler import CosineAnnealingLR
from torchvision.models import AlexNet
num_epochs = 100
#定义2分类网络
model = AlexNet(num_classes=2)
optimizer = optim.SGD(params=model.parameters(), lr=0.05)
scheduler = CosineAnnealingLR(
optimizer=optimizer,
T_max=20, # 设定调整的间隔数
eta_min=0.005, # 系数
last_epoch=-1
)
# 迭代训练
lrs, epochs = [], []
for epoch in range(num_epochs):
lrs.append(scheduler.get_lr()) #.get_lr()获取当前学习率
epochs.append(epoch)
pass # 在这里进行迭代训练
#学习率更新
scheduler.step()
# visualize
plt.figure()
plt.legend()
plt.plot(epochs, lrs, label='CosineAnnealingLR')
plt.show()
二、自适应调整:
自适应调整学习率 ReduceLROnPlateau:torch.optim.lr_scheduler.ReduceLROnPlateau
n e w − l r = λ ∗ o l d − l r new_-lr=\lambda *old_-lr new−lr=λ∗old−lr
三、自定义调整:
自定义调整学习率 LambdaLR:torch.optim.lr_scheduler.LambdaLr(optimizer, lr_lambda, last_epoch=-1)
更新策略:
遇到模型不同的层参数时,根据该层参数的调整方式来调整学习率。
为不同参数组设定不同学习率调整策略,在fine-tune中特别有用,我们不仅可以为不同层设置不同的学习率,还可以为不同层设置不同的学习率调整策略。
n e w − l r = λ ∗ i n i t i a l − l r new_-lr=\lambda *initial_-lr new−lr=λ∗initial−lr
n e w − l r new_-lr new−lr:新得到的学习率。
i n i t i a l − l r initial_-lr initial−lr:初始学习率。
λ λ λ:通过参数lr_lambda
和epoch
得到的。
l r − l a m b d a lr_-lambda lr−lambda:根据epoch计算λ的函数;或者是一个list的这样的function,分别计算各个parameter groups的学习率更新用到的λ;
import matplotlib.pyplot as plt
import torch
import torch.optim as optim
from torch.optim.lr_scheduler import LambdaLR
from torchvision.models import AlexNet
import seaborn as sns
num_epochs = 100
#定义2分类网络
model = AlexNet(num_classes=2)
# optimizer parameter groups 设置了个优化组:权重,偏置,其他参数
pg0, pg1, pg2 = [], [], []
for k, v in model.named_parameters():
v.requires_grad = True
if '.bias' in k:
pg2.append(v) # biases
elif '.weight' in k and '.bn' not in k:
pg1.append(v) # apply weight decay
else:
pg0.append(v) # all else
optimizer = optim.SGD(pg1, lr=0.05)
#给optimizer管理的参数组中增加新的组参数,
#可为该组参数定制lr,momentum,weight_decay 等在finetune 中常用。
optimizer.add_param_group({
'params': pg2}) # add pg2 (biases)
# 对于卷积层权重的学习率,每十轮调整为原来的 0.1 倍
pg1 = lambda epoch: 0.1 ** (epoch // 10)
# 对于偏置权重的学习率,每轮调整为原来的 0.94 倍
pg2 = lambda epoch: 0.94 ** epoch
scheduler = LambdaLR(
optimizer=optimizer,
lr_lambda=[pg1, pg2], #传入一个函数或一个以函数为元素列表,作为学习率调整的策略
last_epoch=-1
)
weight_lrs, bias_lrs, epochs = [], [], []
for epoch in range(num_epochs):
weight_lrs.append(scheduler.get_lr()[0])
bias_lrs.append(scheduler.get_lr()[1])
epochs.append(epoch)
pass # iter and train here
scheduler.step(epoch)
# visualize
plt.figure()
plt.plot(epochs, weight_lrs, label='step')
plt.plot(epochs, bias_lrs, label='exponential')
plt.legend()
plt.show()