学习率是深度学习中的一个重要超参数,选择合适的学习率能够帮助模型更好地收敛。
本文主要介绍深度学习训练过程中的6种学习率衰减策略以及相应的Pytorch实现。
1. StepLR
- 按固定的训练epoch数进行学习率衰减。
- 举例说明:
# lr = 0.05 if epoch < 30
# lr = 0.005 if 30 <= epoch < 60
# lr = 0.0005 if 60 <= epoch < 90
在上述例子中,每30个epochs衰减十倍学习率。
- 计算公式和pytorch计算代码如下:
def _get_closed_form_lr(self):
return [base_lr * self.gamma ** (self.last_epoch // self.step_size)
for base_lr in self.base_lrs]
- pytorch调用及相关参数:
torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=- 1, verbose=False)
optimizer:表示使用的优化器;
step_size:表示学习率调整步长;
gamma:表示学习率衰减乘法因子,默认:0.1;
last_epoch:表示上一个epoch数,默认:-1,此时学习率的值为初始学习率;
verbose:表示是否每次更新都输出一次学习率的值,默认:False。
- 代码示例及结果展示:
lr_scheduler=torch.optim.lr_scheduler.StepLR(optimizer,step_size=3,gamma=0.1,last_epoch=-1)
设置10个epoch时,输出训练过程中的学习率如下:
2. MultiStepLR
- 当epoch数达到固定数值进行学习率衰减。
- 举例说明:
# milestones=[30,80]
# lr = 0.05 if epoch < 30
# lr = 0.005 if 30 <= epoch < 80
# lr = 0.0005 if epoch >= 80
在上述例子中,当epoch达到milestones中的数值时进行学习率衰减。
- 计算公式和pytorch计算代码如下:
其中bisect_right函数表示epoch数插入milestones中列表的位置,
例如:milstones=[2,5,8]
last_epoch==1→bisect_right(milestones,last_epoch)=0;
last_epoch==3→bisect_right(milestones,last_epoch)=1;
last_epoch==6→bisect_right(milestones,last_epoch)=2;
def _get_closed_form_lr(self):
milestones = list(sorted(self.milestones.elements()))
return [base_lr * self.gamma ** bisect_right(milestones, self.last_epoch)
for base_lr in self.base_lrs]
- pytorch调用及相关参数:
torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=- 1, verbose=False)
milestones:一个关于epoch索引的列表,当epoch值达到列表中的数值时进行学习率衰减。
其他参数相同。
- 代码示例及结果展示:
lr_scheduler=torch.optim.lr_scheduler.MultiStepLR(optimizer,milestones=[2,5,8],gamma=0.1,last_epoch=-1)
3. ExponentialLR
- 根据当前epoch进行学习率衰减
- 计算公式和pytorch计算代码如下:
def _get_closed_form_lr(self):
return [base_lr * self.gamma ** self.last_epoch
for base_lr in self.base_lrs]
- pytorch调用及相关参数:
torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=- 1, verbose=False)
- 代码示例及结果展示:
lr_scheduler=torch.optim.lr_scheduler.ExponentialLR(optimizer,gamma=0.1,last_epoch=-1)
4. linearLR
- 在epoch数达到total_iters数值之前,使用线性改变乘法因子衰减学习率。
- 计算公式和pytorch计算代码如下:
def _get_closed_form_lr(self):
return [base_lr * (self.start_factor +
(self.end_factor - self.start_factor) * min(self.total_iters, self.last_epoch) / self.total_iters)
for base_lr in self.base_lrs]
- pytorch调用及相关参数:
torch.optim.lr_scheduler.LinearLR(optimizer, start_factor=0.3333333333333333, end_factor=1.0, total_iters=5, last_epoch=- 1, verbose=False)
start_factor: 在第一个epoch中乘以base_lr的数值,默认1/3;
end_factor:在线性变化过程结束时乘以base_lr的数值,默认:1;
total_iters:乘法因子达到1的迭代次数,默认:5。
- 举例说明:
lr_scheduler = LinearLR(optimizer, start_factor=0.5, total_iters=4)
base_lr=0.05
# epoch == 0→lr = base_lr * start_factor = 0.05 * 0.5=0.025;
# epoch == 1→lr = 0.05 * (0.5 + 0.5 * 0.25) = 0.3125;
......
# epoch ≥ 4→lr = base_lr * end_factor = 0.05(当epoch数等于total_iters时,min(self.total_iters, self.last_epoch) / self.total_iters = 1)
5. ConstantLR
- 在epoch数达到total_iters数值之前,使用常数因子衰减学习率。
- 计算公式和pytorch计算代码如下:
def _get_closed_form_lr(self):
return [base_lr * (self.factor + (self.last_epoch >= self.total_iters) * (1 - self.factor))
for base_lr in self.base_lrs]
- pytorch调用及相关参数:
torch.optim.lr_scheduler.ConstantLR(optimizer, factor=0.3333333333333333, total_iters=5, last_epoch=- 1, verbose=False)
factor:在epoch达到total_iters之前,学习率乘以的常数因子,默认1/3;
total_iters:衰减学习率的步数。
- 举例说明:
lr_scheduler = ConstantLR(self.opt, factor=0.5, total_iters=4)
base_lr = 0.05
# epoch == 0 → lr = base_lr * (factor + 0 * (1-factor)) = 0.05 * 0.5 = 0.025
......
# epoch == 4 → lr = base_lr * (factor + 1 - factor) = 0.05
6. LambdaLR
- 使用lambda定义的函数衰减学习率。
- 计算公式和pytorch计算代码如下:
def get_lr(self):
if not self._get_lr_called_within_step:
warnings.warn("To get the last learning rate computed by the scheduler, "
"please use `get_last_lr()`.")
return [base_lr * lmbda(self.last_epoch)
for lmbda, base_lr in zip(self.lr_lambdas, self.base_lrs)]
- pytorch调用及相关参数:
torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=- 1, verbose=False)
lr_lambda:当给定epoch数,计算乘法因子的函数(可以自己定义)
- 代码示例及结果展示:
lr_scheduler=torch.optim.lr_scheduler.LambdaLR(optimizer,lr_lambda=lambda epoch:epoch/30 )
7. MultiplicativeLR
- 同样是使用了与epoch有关的lambda函数,与LambdaLR不同的地方在于,它是对old_lr更新。
- 计算公式和pytorch计算代码如下:
def get_lr(self):
if not self._get_lr_called_within_step:
warnings.warn("To get the last learning rate computed by the scheduler, "
"please use `get_last_lr()`.", UserWarning)
if self.last_epoch > 0:
return [group['lr'] * lmbda(self.last_epoch)
for lmbda, group in zip(self.lr_lambdas, self.optimizer.param_groups)]
else:
return [group['lr'] for group in self.optimizer.param_groups]
- pytorch调用及相关参数:
torch.optim.lr_scheduler.MultiplicativeLR(optimizer, lr_lambda, last_epoch=- 1, verbose=False)
8.CosineAnnealingLR
- 模拟余弦退火曲线调整学习率
- 计算公式和pytorch计算代码如下:
def _get_closed_form_lr(self):
return [self.eta_min + (base_lr - self.eta_min) *
(1 + math.cos(math.pi * self.last_epoch / self.T_max)) / 2
for base_lr in self.base_lrs]
- pytorch调用及相关参数:
torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max, eta_min=0, last_epoch=- 1, verbose=False)
T_max:最大迭代次数,一次学习率周期的迭代次数。
eta_min:最小学习率,默认:0。
- 代码示例及结果展示:
lr_scheduler=torch.optim.lr_scheduler.CosineAnnealingLR(optimizer,T_max=3,eta_min=0)
base_lr=0.01
当epoch是T_max的奇数倍时,学习率会下降到最小值eta_min。
9. ChainedScheduler
- 可以调用其他学习率调整策略。
- pytorch调用及相关参数:
torch.optim.lr_scheduler.ChainedScheduler(schedulers)
schedules:设置的其他学习率调整策略,可以是一个包含多个学习率调整策略的列表。
- 代码示例及结果:
scheduler1 = ConstantLR(self.opt, factor=0.1, total_iters=2)
scheduler2 = ExponentialLR(self.opt, gamma=0.9)
lr_scheduler = ChainedScheduler([scheduler1, scheduler2])
schedules里的学习率调整策略同时使用
base_lr = 1
# lr = 0.09 if epoch == 0 (先使用scheduler2策略得到lr = 0.9;再使用scheduler1策略得到最终new_lr = 0.09)
# lr = 0.081 if epoch == 1
# lr = 0.729 if epoch == 2
# lr = 0.6561 if epoch == 3
# lr = 0.59049 if epoch >= 4
10.SequentialLR
- 与ChainedScheduler在每一个epoch中同时调用schedules中的学习率策略不同的是,SequentialLR针对epoch按顺序调用schedules中的学习率策略。
- pytorch调用及相关参数:
torch.optim.lr_scheduler.SequentialLR(optimizer, schedulers, milestones, last_epoch=- 1, verbose=False)
- 代码示例及结果:
scheduler1 = ConstantLR(self.opt, factor=0.1, total_iters=2)
scheduler2 = ExponentialLR(self.opt, gamma=0.9)
lr_scheduler = SequentialLR(optimizer, schedulers=[scheduler1, scheduler2], milestones=[2])
base_lr = 1
# lr = 0.1 if epoch == 0
# lr = 0.1 if epoch == 1
# lr = 0.9 if epoch == 2
# lr = 0.81 if epoch == 3
# lr = 0.729 if epoch == 4
epoch
11.ReduceLROnPlateau
- 当训练指标不再改进时,调整学习率。
- pytorch调用及相关参数:
torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10, threshold=0.0001, threshold_mode='rel', cooldown=0, min_lr=0, eps=1e-08, verbose=False)
mode:有min、max两种模式,在 min 模式下,当指标的数量停止减少时(如loss),学习率将减少; 在max模式下,当指标的数量停止增加时(如accuracy),学习率将减少,默认值:min;
factor:学习率减少的倍数,new_lr = old_lr * factor,默认:0.1;
patience:指标没有提升的epoch数,之后降低学习率。例如,patience = 2,会忽略前 2 个没有改善的 epoch,并且只有在第 3 个 epoch 之后指标仍然没有改善的情况下降低 学习率。 默认值:10。
threshold:衡量新的最佳阈值,只关注重大变化。 默认值:1e-4。
threshold_mode:有rel、abs两种模式,
cooldown:在 学习率减少后恢复正常操作之前要等待的 epoch 数。 默认值:0。
min_lr:标量或标量列表。学习率的下限。 默认值:0。
eps:应用于 学习率的最小衰减。 如果新旧 学习率之间的差异小于 eps,则忽略更新。 默认值:1e-8。
- 代码示例及结果:
lr_scheduler=torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer,mode='min',patience=2,cooldown=2)
第一个epoch是初始学习率;
设置patience = 2,即指标在经历3个epoch后仍然没有提升,衰减学习率,new_lr = old_lr * factor(0.1),如图中第4个epoch时开始衰减学习率;
设置cooldown = 2,即衰减学习率后有2个epoch的cooldown时期(5、6epoch),在cooldown时期不进行patience阶段的epoch计数;
cooldown时期结束恢复patience阶段epoch计数(图中从第7个epoch开始计数,在第10个epoch学习率衰减)。
12.CyclicLR
- 根据循环学习策略设置学习率。(每训练一个batch,更新一次学习率)
- 在《 Cyclical Learning Rates for Training Neural Networks》这篇文章中有详细描述。
- pytorch调用及相关参数:
torch.optim.lr_scheduler.CyclicLR(optimizer, base_lr, max_lr, step_size_up=2000, step_size_down=None, mode='triangular', gamma=1.0, scale_fn=None, scale_mode='cycle', cycle_momentum=True, base_momentum=0.8, max_momentum=0.9, last_epoch=- 1, verbose=False)
base_lr:初始学习率,循环中的学习率下边界;
max_lr:每个参数组在循环中的上层学习率边界。从功能上讲,它定义了周期幅度 (max_lr - base_lr)。任何周期的 lr 是 base_lr 和一些幅度缩放的总和;因此 max_lr 实际上可能无法达到,具体取决于缩放函数。
step_size_up:在一个周期增加的一半中训练迭代的次数。默认值:2000;
step_size_down:循环减半中的训练迭代次数。如果 step_size_down 为 None,则设置为 step_size_up。默认值:None;
mode:包含三种{triangular, triangular2, exp_range} ,如果 scale_fn 不是 None,则忽略此参数。默认值:“triangular”;
gamma:‘exp_range’ 缩放函数中的常数:gamma**(cycle iterations)默认值:1.0;
scale_fn:由单个参数 lambda 函数定义的自定义缩放策略,其中 0 <= scale_fn(x) <= 1 for all x >= 0。如果指定,则忽略“mode”。默认值:None;
scale_mode:{‘cycle’, ‘iterations’}。定义是否在cycle number或cycle iterations (training iterations since start of cycle)上评估 scale_fn。默认值:cycle;
cycle_momentum:如果为真,则动量与“base_momentum”和“max_momentum”之间的学习率成反比。默认值:True;
base_momentum: 循环中的动量下边界,默认值:0.8;
max_monmentum:循环中的动量上边界,默认值:0.9;
- 官方代码及示例:
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
scheduler = torch.optim.lr_scheduler.CyclicLR(optimizer, base_lr=0.01, max_lr=0.1)
data_loader = torch.utils.data.DataLoader(...)
for epoch in range(10):
for batch in data_loader:
train_batch(...)
scheduler.step()
13.OneCycleLR
- 根据循环学习策略设置学习率。(每训练一个batch,更新一次学习率)
- 相关文章《Super-Convergence: Very Fast Training of Neural Networks Using Large Learning Rates》
- pytorch调用及相关参数:
torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr, total_steps=None, epochs=None, steps_per_epoch=None, pct_start=0.3, anneal_strategy='cos', cycle_momentum=True, base_momentum=0.85, max_momentum=0.95, div_factor=25.0, final_div_factor=10000.0, three_phase=False, last_epoch=- 1, verbose=False)
max_lr:在循环中的上层学习率边界;
total_steps:循环总步数。如果此处未提供值,则必须通过提供 epochs 和 steps_per_epoch 的值来推断。默认值:None;
epochs:训练的epochs;
steps_per_epoch:每个 epoch 训练的步数;
pct_start:提高学习率所花费的周期百分比(in number of steps)。默认值:0.3;
anneal_strategy:{‘cos’, ‘linear’} 指定退火策略:“cos”表示余弦退火,“linear”表示线性退火。默认值:'cos';
div_factor:通过 initial_lr = max_lr/div_factor 确定初始学习率 默认值:25;
final_div_factor:通过 min_lr = initial_lr/final_div_factor 确定最小学习率 默认值:1e4;
three_phase:如果为 True,则使用计划的第三阶段根据“final_div_factor”消除学习率,而不是修改第二阶段(前两个阶段将关于“pct_start”指示的步骤对称)。
- 官方代码及示例:
data_loader = torch.utils.data.DataLoader(...)
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
scheduler = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=0.01, steps_per_epoch=len(data_loader), epochs=10)
for epoch in range(10):
for batch in data_loader:
train_batch(...)
scheduler.step()
14.CosineAnnealingWarmRestarts
- 和余弦退火类似,多了warmrestart操作。
- pytorch调用及相关参数:
torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(optimizer, T_0, T_mult=1, eta_min=0, last_epoch=- 1, verbose=False)
T_0:第一次restart的迭代次数;
T_mult:在一次restar后,因子增加:math:`T_{i};
eta_min:最小学习率,默认值:0。
- 官方代码及示例:
scheduler = CosineAnnealingWarmRestarts(optimizer, T_0, T_mult)
iters = len(dataloader)
for epoch in range(20):
for i, sample in enumerate(dataloader):
inputs, labels = sample['inputs'], sample['labels']
optimizer.zero_grad()
outputs = net(inputs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
scheduler.step(epoch + i / iters)
参考及引用:
1.https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate
2.https://zhuanlan.zhihu.com/p/352744991
3.https://blog.csdn.net/qyhaill/article/details/103043637