torch.optim.lr_scheduler 提供了动态调整学习率的方法。在使用的时, Learning Rate Scheduler 一般在优化器的更新参数之后调用。另外,我们也可以在程序中使用多个 scheduler 来调整学习率,如下代码所示:
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()
接下来,介绍 PyTorch 官网提供的几种学习率优化策略。主要包含以下几种:
lr_scheduler.LambdaLR
lr_scheduler.MultiplicativeLR
lr_scheduler.StepLR
lr_scheduler.MultiStepLR
lr_scheduler.ConstantLR
lr_scheduler.LinearLR
lr_scheduler.ExponentialLR
1. LambdaLR
LambdaLR 每个 step 后,lr 调整为上一个时刻的 lr_lambda,例如:lr_lambda=0.9,则 lambda step: 0.9 ** step
。
LambdaLR(optimizer, lr_lambda, last_epoch=- 1, verbose=False)
示例代码:
import torch from torch.optim.lr_scheduler import LambdaLR import torch.optim as optim import torch.nn as nn import torch import matplotlib.pyplot as plt if __name__ == '__main__': # 模型参数 parameter = [nn.Parameter(torch.tensor([1, 2, 3], dtype=torch.float32))] # 优化器 optimizer = optim.Adam(parameter, lr=0.1) # 调度器 scheduler = LambdaLR(optimizer=optimizer, lr_lambda=lambda step: 0.9 ** step) learning_rates = [0.1] for _ in range(10): # 先优化器更新 optimizer.step() # 再调度器更新 scheduler.step() # 存储学习率 learning_rates.append(scheduler.get_last_lr()[0]) print('%.5f' % scheduler.get_last_lr()[0]) # 绘制学习率变化 plt.plot(range(11), learning_rates, 'ro-') plt.title('LambdaLR') plt.grid() plt.show()
2. MultiplicativeLR
MultiplicativeLR 与 LambdaLR 区别如下:
LambdaLR 是由初始学习率乘以 lambda 函数的返回值,而 MultiplicativeLR 则是使用上一个学习率乘以 lambda 函数的返回值。
MultiplicativeLR(optimizer, lr_lambda, last_epoch=- 1, verbose=False)
示例代码:
import torch from torch.optim.lr_scheduler import MultiplicativeLR import torch.optim as optim import torch.nn as nn import torch import matplotlib.pyplot as plt if __name__ == '__main__': # 模型参数 parameter = [nn.Parameter(torch.tensor([1, 2, 3], dtype=torch.float32))] # 优化器 optimizer = optim.Adam(parameter, lr=0.1) # 调度器 scheduler = MultiplicativeLR(optimizer=optimizer, lr_lambda=lambda step: 0.9) learning_rates = [0.1] for _ in range(10): # 先优化器更新 optimizer.step() # 再调度器更新 scheduler.step() # 存储学习率 learning_rates.append(scheduler.get_last_lr()[0]) print('%.5f' % scheduler.get_last_lr()[0]) # 绘制学习率变化 plt.plot(range(11), learning_rates, 'ro-') plt.title('MultiplicativeLR') plt.grid() plt.show()
3. StepLR
StepLR 可以实现迭代固定多少 epoch 时,对学习率进行衰减。
StepLR(optimizer, step_size, gamma=0.1, last_epoch=- 1, verbose=False)
- gamma 就是衰减的系数。假设:gamma=0.1,则学习率衰减为上一个学习率的 0.1
- step_size 表示经过多少个 step 对学习率进行一次衰减
比如:我们每 5 个 epoch,就把学习修改为上一个学习率的 0.5,如下代码所示:
import torch from torch.optim.lr_scheduler import StepLR import torch.optim as optim import torch.nn as nn import torch import matplotlib.pyplot as plt if __name__ == '__main__': # 模型参数 parameter = [nn.Parameter(torch.tensor([1, 2, 3], dtype=torch.float32))] # 优化器 optimizer = optim.SGD(parameter, lr=0.1) # 调度器 scheduler = StepLR(optimizer=optimizer, step_size=5, gamma=0.5) learning_rates = [0.1] for _ in range(100): # 先优化器更新 optimizer.step() # 再调度器更新 scheduler.step() # 存储学习率 print('%.5f' % scheduler.get_last_lr()[0]) learning_rates.append(scheduler.get_last_lr()[0]) # 绘制学习率变化 plt.plot(range(101), learning_rates) plt.title('StepLR') plt.grid() plt.show()
4. MultiStepLR
MultiStepLR 和 StepLR 的区别是,前者可以自定义多个 step 点来进行学习率衰减,而后者只能根据固定的间隔来衰减学习率。
MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=- 1, verbose=False)
参数中 milestones 是列表类型,用来设置需要进行学习率衰减的 epoch 点。例如,我们总共进行 100 epoch,设置 [10, 40, 50, 80] 这 4 个 epoch 点来衰减学习率。
import torch from torch.optim.lr_scheduler import MultiStepLR import torch.optim as optim import torch.nn as nn import torch import matplotlib.pyplot as plt if __name__ == '__main__': # 模型参数 parameter = [nn.Parameter(torch.tensor([1, 2, 3], dtype=torch.float32))] # 优化器 optimizer = optim.SGD(parameter, lr=0.1) # 调度器 scheduler = MultiStepLR(optimizer=optimizer, gamma=0.5, milestones=[10, 40, 50, 80]) learning_rates = [0.1] for _ in range(100): # 先优化器更新 optimizer.step() # 再调度器更新 scheduler.step() # 存储学习率 print('%.5f' % scheduler.get_last_lr()[0]) learning_rates.append(scheduler.get_last_lr()[0]) # 绘制学习率变化 plt.plot(range(101), learning_rates) plt.title('MultiStepLR') plt.grid() plt.show()
5. ConstantLR
我们希望训练开始时,使用较小的学习率训练多个 step,然后再使用大的学习率继续训练。在这里,小学习率和大学习率都是固定的。ConstantLR 可以做这样的工作。
ConstantLR(optimizer, factor=0.33, total_iters=5, last_epoch=- 1, verbose=False)
factor 用来指定小学习率,total_iters 指定使用该小学习率训练多少 step,在 total_iters 轮次结束之后,学习率会回到我们在 optimizer 里设置的初始学习率。
import torch from torch.optim.lr_scheduler import ConstantLR import torch.optim as optim import torch.nn as nn import torch import matplotlib.pyplot as plt if __name__ == '__main__': # 模型参数 parameter = [nn.Parameter(torch.tensor([1, 2, 3], dtype=torch.float32))] # 优化器 optimizer = optim.Adam(parameter, lr=1) # 调度器 scheduler = ConstantLR(optimizer=optimizer, factor=0.1, total_iters=5) learning_rates = [0.1] for _ in range(10): # 先优化器更新 optimizer.step() # 再调度器更新 scheduler.step() # 存储学习率 learning_rates.append(scheduler.get_last_lr()[0]) print('%.5f' % scheduler.get_last_lr()[0]) # 绘制学习率变化 plt.plot(range(11), learning_rates, 'ro-') plt.title('ConstantLR') plt.grid() plt.show()
6. LinearLR
LinearLR(optimizer, start_factor=0.33, end_factor=1.0, total_iters=5, last_epoch=- 1, verbose=False)
学习率经过 total_iters
个 step 从 lr * start_factor
到 lr * end_factor
,然后恒定保持不变, lr 为优化器指定。
import torch from torch.optim.lr_scheduler import LinearLR import torch.optim as optim import torch.nn as nn import torch import matplotlib.pyplot as plt if __name__ == '__main__': # 模型参数 model_parameters = [nn.Parameter(torch.tensor([1, 2, 3], dtype=torch.float32))] # 优化器 optimizer = optim.SGD(model_parameters, lr=0.1) # 调度器 scheduler = LinearLR(optimizer=optimizer, start_factor=0.001, end_factor=0.10, total_iters=50) learning_rates = [] for _ in range(100): # 先优化器更新 optimizer.step() # 再调度器更新 scheduler.step() # 存储学习率 print('%.5f' % scheduler.get_last_lr()[0]) learning_rates.append(scheduler.get_last_lr()[0]) # 绘制学习率变化 plt.plot(range(100), learning_rates) plt.title('LinearLR') plt.grid() plt.show()
7. ExponentialLR
ExponentialLR 表示学习率每个 epoch 是 epoch-1 学习率的 0.9(gamma=0.9)。
ExponentialLR(optimizer, gamma, last_epoch=- 1, verbose=False)
import torch from torch.optim.lr_scheduler import ExponentialLR import torch.optim as optim import torch.nn as nn import torch import matplotlib.pyplot as plt if __name__ == '__main__': # 模型参数 model_parameters = [nn.Parameter(torch.tensor([1, 2, 3], dtype=torch.float32))] # 优化器 optimizer = optim.SGD(model_parameters, lr=0.1) # 调度器 scheduler = ExponentialLR(optimizer=optimizer, gamma=0.9) learning_rates = [] for _ in range(100): # 先优化器更新 optimizer.step() # 再调度器更新 scheduler.step() # 存储学习率 print('%.5f' % scheduler.get_last_lr()[0]) learning_rates.append(scheduler.get_last_lr()[0]) # 绘制学习率变化 plt.plot(range(100), learning_rates) plt.title('ExponentialLR') plt.grid() plt.show()
输出结果:
0.09000 # 0.1000 * 0.9 0.08100 # 0.9000 * 0.9 0.07290 # 0.0810 * 0.9 0.06561 # 0.7290 * 0.9 # 后面以此类推