深度学习学习率lr_scheduler调整小结
禁止以任何形式转载或抄袭!!
简介
learning rate schedules主要就是对分子部分进行调整,采用learning rate schedules的时候多用于SGD这类非自适应的算法之中。
PyTorch提供的学习率调整策略分为三大类:
- 有序调整:等间隔调整(Step),按需调整学习率(MultiStep),指数衰减调整(Exponential)和 余弦退火CosineAnnealing
- 自适应调整:自适应调整学习率 ReduceLROnPlateau
- 自定义调整:自定义调整学习率 LambdaLR
代码
在PyTorch 1.1.0之前,学习率调度程序应该在优化器更新之前调用;1.1.0以后改变了这种方式。如果在优化器更新(调用optimizer.step())之前使用学习率调度程序(调用scheduler.step()),这将跳过学习率调度程序的第一个值。In PyTorch 1.1.0 and later, you should call them in the opposite order: optimizer.step()
before lr_scheduler.step()
.
model_param = [Parameter(torch.randn(2, 2, requires_grad=True))]
optimizer = SGD(model_param, 0.1)
scheduler = ExponentialLR(optimizer, gamma=0.9)
for epoch in range(20):
for input, target in dataset:
optimizer.zero_grad()
output = model(input)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
scheduler.step()
注意,一般都是在优化器进行调整之后,才应用学习率调整策略对学习率进行调整。
大多数学习率调整程序,都是可以根据前一个调整策略所获得的学习率再次进行调整的。
model = [Parameter(torch.randn(2, 2, requires_grad=True))]
optimizer = SGD(model, 0.1)
scheduler1 = ExponentialLR(optimizer, gamma=0.9)
scheduler2 = MultiStepLR(optimizer, milestones=[30,80], gamma=0.1)
for epoch in range(20):
for input, target in dataset:
optimizer.zero_grad()
output = model(input)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
scheduler1.step()
scheduler2.step()
StepLR
等间隔调整
scheduler = lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
MultiStepLR
按需调整学习率
scheduler = lr_scheduler.MultiStepLR(optimizer, milestones=[40,70], gamma=0.1)
ExponentialLR
指数衰减,用得少
scheduler =lr_scheduler.ExponentialLR(optimizer, gamma=0.9)
OneCycleLR
scheduler =lr_scheduler.OneCycleLR(optimizer,max_lr=0.9,total_steps=1000, verbose=True)
注意:之前的几个学习率优化器是放在每个epoch,每个epoch更新一次,这个方法是每个step更新一次,应该放在step的循环中。
- total_steps:总的batch数,这个参数设置后就不用设置epochs和steps_per_epoch,anneal_strategy 默认是"cos"方式,当然也可以选择"linear"
- 注意这里的max_lr和你优化器中的lr并不是同一个
- 低版本torch里面没有这个函数
CyclicLR
同样的,这里也是以每个step进行更新的。
scheduler = lr_scheduler.CyclicLR(optimizer, base_lr=0.01, max_lr=0.1,step_size_up=150,step_size_down=250,mode='triangular')
mode=‘triangular2’:
scheduler = lr_scheduler.CyclicLR(optimizer, base_lr=0.01, max_lr=0.1,step_size_up=150,step_size_down=250,mode='exp_range',gamma=0.997)
CosineAnnealingLR
与上一个函数所不同的是,这里使用余弦函数进行学习率的衰减,而且学习率是大学习率开始的。仍然是每个step更新。
T_max:Cosine是个周期函数,这里的T_max就是这个周期的一半,如果你将T_max设置为10,则学习率衰减的周期是20个epoch,其中前10个epoch从学习率的初值(也是最大值)下降到最低值,后10个epoch从学习率的最低值上升到最大值
eta_min:学习率衰减时的最小值,默认值为0
last_epoch:(上次训练)最后一个epoch的索引值,默认值为-1。如果你将其设置为20,那定义出来的scheduler的第一次step就会到第21个epoch对应的学习率。这里是为了resuming
optimizer = optim.SGD(params=model.parameters(), lr=0.05)
scheduler = lr_scheduler.CosineAnnealingLR(optimizer, T_max=200, eta_min=0.01, last_epoch=-1)
当然,这里你可以只选择用最前面的一段,从大到小的余弦衰减
CosineAnnealingWarmRestarts
T_0 – 设定初次在哪里WarmRestarts
T_mult – 每次Restarts后周期扩展系数 默认为: 1.
eta_min–最小学习率,默认为0
scheduler = lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0=300, T_mult=1, eta_min=0)
scheduler = lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0=200, T_mult=2, eta_min=0)
这一个是用于自适应调整的学习率衰减函数。
功能:监控指标,当指标不再变化则调整(很实用)
比如监控Loss不再下降、或者分类准确率acc不再上升就进行学习率的调整。
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
scheduler = ReduceLROnPlateau(optimizer, 'min')
for epoch in range(10):
train(...)
val_loss = validate(...)
# Note that step should be called after validate()
scheduler.step(val_loss)
LambdaLR
自定义调整策略
这里主要是通过lr_lambda (function or list) 参数来设定学习率调整策略:
lambda1 = lambda epoch: 0.95 ** epoch
scheduler = LambdaLR(optimizer, lr_lambda=lambda1)
或者有多个学习率需要调整
#Assuming optimizer has two groups.
lambda1 = lambda epoch: epoch // 30
lambda2 = lambda epoch: 0.95 ** epoch
scheduler = LambdaLR(optimizer, lr_lambda=[lambda1, lambda2])
我这里来定义一个复杂一点的函数,
def lr_lambda(current_step: int,num_warmup_steps=280,num_training_steps=1000):
# 自定义函数
'''
num_warmup_steps (:obj:`int`):
The number of steps for the warmup phase.
num_training_steps (:obj:`int`):
The total number of training steps.
last_epoch (:obj:`int`, `optional`, defaults to -1):
The index of the last epoch when resuming training.
'''
if current_step < num_warmup_steps:
return float(current_step) / float(max(1, num_warmup_steps))
return max(
0.0, float(num_training_steps - current_step) / float(max(1, num_training_steps - num_warmup_steps))
)
scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lr_lambda)
MultiplicativeLR
将每个参数组的学习速率乘以指定函数中给定的因子。跟LambdaLR差不多,用得很少,就不画图了。
lambdaa = lambda epoch : 0.5
scheduler = optim.lr_scheduler.MultiplicativeLR(optimizer, lambdaa)