pytorch-torch.optim.lr_scheduler 调整学习率的六种策略

pytorch torch.optim.lr_scheduler 调整学习率的六种策略

1. 为什么需要调整学习率

在深度学习训练过程中,最重要的参数就是学习率,通常来说,在整个训练过层中,学习率不会一直保持不变,为了让模型能够在训练初期快速收敛,学习率通常比较大,在训练末期,为了让模型收敛在更小的局部最优点,学习率通常要比较小。

2. 学习率的初始值设置

其实,不同的任务学习率的初始值是需要试验几次来获得的,使用的优化器不同,mini-batch 的 batch_size 大小不同,学习率的初始值也不太相同。
根据我的实验经验,同一个任务,如果使用Adam优化器,学习率初始值0.001比较好,Adam优化器对于初始值实际上不太敏感,基本都能做到快速收敛;如果使用SGD优化器的话,学习率需要在Adam的基础上乘以10倍或者100倍,也就是使用0.1或者0.01比较好。
需要注意的一点,通常 batch_size 扩大 n 倍,学习率也要相应扩大 ( n ) \sqrt(n) ( n),虽然这么说,我自己实验的时候,没发现太多作用,可能是因为使用Adam的原因。

3. torch 学习率的调整策略

pytorch 提供了一些基础的学习率调整策略,在 torch.optim.lr_scheduler 模块里,下方的代码实现了5种可能用到(其实我自己用的都是最基础的阶梯下降)的学习率调整方法,图片可视化了学习率变小的过程,非常简单,对照图片和代码仔细看看就明白每个scheduler的具体参数含义了:

import torch
import matplotlib.pyplot as plt

lr = 0.001

# 20代表从lr从最大到最小的epoch数,0代表学习率的最小值
scheduler_cos = torch.optim.lr_scheduler.CosineAnnealingLR(torch.optim.SGD([torch.ones(1)], lr), 20, 0)
# 20 和 0.5 代表每走20个epoch,学习率衰减0.5倍,阶梯形式
scheduler_step = torch.optim.lr_scheduler.StepLR(torch.optim.SGD([torch.ones(1)], lr), 20, 0.5)
# 每走一个epoch,学习率衰减0.95倍
scheduler_exp = torch.optim.lr_scheduler.ExponentialLR(torch.optim.SGD([torch.ones(1)], lr), 0.95)
# 三角的形式,0.0001代表最小的学习率, 0.001代表最大的学习率, 20代表一个升降周期
scheduler_cyc = torch.optim.lr_scheduler.CyclicLR(torch.optim.SGD([torch.ones(1)], lr), 0.0001, 0.001, 20)
# 阶梯衰减,每次衰减的epoch数根据列表 [20, 30, 60, 80] 给出,0.8代表学习率衰减倍数
scheduler_mul = torch.optim.lr_scheduler.MultiStepLR(torch.optim.SGD([torch.ones(1)], lr), [20, 30, 60, 80], 0.8)

lr_cos  = []
lr_step = []
lr_exp  = []
lr_cyc  = []
lr_mul  = []
for i in range(100):
    lr_cos  += scheduler_cos.get_last_lr()
    lr_step += scheduler_step.get_last_lr()
    lr_exp  += scheduler_exp.get_last_lr()
    lr_cyc  += scheduler_cyc.get_last_lr()
    lr_mul  += scheduler_mul.get_last_lr()
    scheduler_cos.step()
    scheduler_step.step()
    scheduler_exp.step()
    scheduler_cyc.step()
    scheduler_mul.step()

plt.figure(figsize=(12,7))
plt.plot(list(range(len(lr_cos))), lr_cos,
         list(range(len(lr_step))), lr_step,
         list(range(len(lr_exp))), lr_exp, 
         list(range(len(lr_cyc))), lr_cyc, 
         list(range(len(lr_mul))), lr_mul,)
plt.legend(['cos','step','exp','cyc', 'mul'], fontsize=20)
plt.xlabel('epoch', size=15)
plt.ylabel('lr', size=15)
plt.show()

运行上面代码后的效果:
在这里插入图片描述

四种调整学习率详解

[pytorch] torch.optimizer.lr_scheduler调整学习率
orch.optim.lr_scheduler模块提供了一些根据epoch训练次数来调整学习率(learning rate)的方法。一般情况下我们会设置随着epoch的增大而逐渐减小学习率从而达到更好的训练效果。

学习率的调整应该放在optimizer更新之后,下面是一个参考蓝本:

scheduler = ...
for epoch in range(100):
     train(...)
     validate(...)
     scheduler.step()

另外本文介绍的调整学习率的函数都是基于epoch大小变化进行调整的。

torch.optim.lr_scheduler.LambdaLR

class torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=-1)

更新的公式为:
在这里插入图片描述
其中new_lr
new_lr是得到的新的学习率,initial_lr
initial_lr是初始的学习率,λ
λ是通过参数lr_lambda和epoch得到的。
参数:

  • optimizer (Optimizer):要更改学习率的优化器;
  • lr_lambda(function or list):根据epoch计算λ的函数;或者是一个list的这样的function,分别计算各个parameter groups的学习率更新用到的λ;
  • last_epoch (int):最后一个epoch的index,如果是训练了很多个epoch后中断了,继续训练,这个值就等于加载的模型的epoch。默认为-1表示从头开始训练,即从epoch=1开始。
import torch
import torch.nn as nn
from torch.optim.lr_scheduler import LambdaLR

initial_lr = 0.1

class model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=3, kernel_size=3)

    def forward(self, x):
        pass

net_1 = model()

optimizer_1 = torch.optim.Adam(net_1.parameters(), lr = initial_lr)
scheduler_1 = LambdaLR(optimizer_1, lr_lambda=lambda epoch: 1/(epoch+1))

print("初始化的学习率:", optimizer_1.defaults['lr'])

for epoch in range(1, 11):
    # train

    optimizer_1.zero_grad()
    optimizer_1.step()
    print("第%d个epoch的学习率:%f" % (epoch, optimizer_1.param_groups[0]['lr']))
    scheduler_1.step()

输出结果是:

初始化的学习率: 0.11个epoch的学习率:0.1000002个epoch的学习率:0.0500003个epoch的学习率:0.0333334个epoch的学习率:0.0250005个epoch的学习率:0.0200006个epoch的学习率:0.0166677个epoch的学习率:0.0142868个epoch的学习率:0.0125009个epoch的学习率:0.01111110个epoch的学习率:0.010000

torch.optim.lr_scheduler.StepLR

class torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1)

更新的公式:
在这里插入图片描述
参数:

  • optimizer (Optimizer):要更改学习率的优化器;
  • step_size(int):每训练step_size个epoch,更新一次参数;
  • gamma(float):更新lr的乘法因子;
  • last_epoch (int):最后一个epoch的index,如果是训练了很多个epoch后中断了,继续训练,这个值就等于加载的模型的epoch。默认为-1表示从头开始训练,即从epoch=1开始。

代码:

import torch
import torch.nn as nn
from torch.optim.lr_scheduler import StepLR
import itertools


initial_lr = 0.1

class model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=3, kernel_size=3)

    def forward(self, x):
        pass

net_1 = model()

optimizer_1 = torch.optim.Adam(net_1.parameters(), lr = initial_lr)
scheduler_1 = StepLR(optimizer_1, step_size=3, gamma=0.1)

print("初始化的学习率:", optimizer_1.defaults['lr'])

for epoch in range(1, 11):
    # train

    optimizer_1.zero_grad()
    optimizer_1.step()
    print("第%d个epoch的学习率:%f" % (epoch, optimizer_1.param_groups[0]['lr']))
    scheduler_1.step()

输出结果为:

初始化的学习率: 0.11个epoch的学习率:0.1000002个epoch的学习率:0.1000003个epoch的学习率:0.1000004个epoch的学习率:0.0100005个epoch的学习率:0.0100006个epoch的学习率:0.0100007个epoch的学习率:0.0010008个epoch的学习率:0.0010009个epoch的学习率:0.00100010个epoch的学习率:0.000100

torch.optim.lr_scheduler.MultiStepLR

class torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1)

更新公式为:

在这里插入图片描述
参数:

  • optimizer (Optimizer):要更改学习率的优化器;
  • milestones(list):递增的list,存放要更新lr的epoch;
  • gamma(float):更新lr的乘法因子;
  • last_epoch (int):最后一个epoch的index,如果是训练了很多个epoch后中断了,继续训练,这个值就等于加载的模型的epoch。默认为-1表示从头开始训练,即从epoch=1开始。

代码:

import torch
import torch.nn as nn
from torch.optim.lr_scheduler import MultiStepLR
import itertools


initial_lr = 0.1

class model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=3, kernel_size=3)

    def forward(self, x):
        pass

net_1 = model()

optimizer_1 = torch.optim.Adam(net_1.parameters(), lr = initial_lr)
scheduler_1 = MultiStepLR(optimizer_1, milestones=[3, 7], gamma=0.1)

print("初始化的学习率:", optimizer_1.defaults['lr'])

for epoch in range(1, 11):
    # train

    optimizer_1.zero_grad()
    optimizer_1.step()
    print("第%d个epoch的学习率:%f" % (epoch, optimizer_1.param_groups[0]['lr']))
    scheduler_1.step()

输出结果为:

初始化的学习率: 0.11个epoch的学习率:0.1000002个epoch的学习率:0.1000003个epoch的学习率:0.1000004个epoch的学习率:0.0100005个epoch的学习率:0.0100006个epoch的学习率:0.0100007个epoch的学习率:0.0100008个epoch的学习率:0.0010009个epoch的学习率:0.00100010个epoch的学习率:0.001000

torch.optim.lr_scheduler.ExponentialLR

class torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=-1)

更新公式为:
在这里插入图片描述
参数:

  • optimizer (Optimizer):要更改学习率的优化器;
  • gamma(float):更新lr的乘法因子;
  • gamma(float):更新lr的乘法因子;
    last_epoch (int):最后一个epoch的index,如果是训练了很多个epoch后中断了,继续训练,这个值就等于加载的模型的epoch。默认为-1表示从头开始训练,即从epoch=1开始。
import torch
import torch.nn as nn
from torch.optim.lr_scheduler import ExponentialLR
import itertools


initial_lr = 0.1

class model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=3, kernel_size=3)

    def forward(self, x):
        pass

net_1 = model()

optimizer_1 = torch.optim.Adam(net_1.parameters(), lr = initial_lr)
scheduler_1 = ExponentialLR(optimizer_1, gamma=0.1)

print("初始化的学习率:", optimizer_1.defaults['lr'])

for epoch in range(1, 11):
    # train

    optimizer_1.zero_grad()
    optimizer_1.step()
    print("第%d个epoch的学习率:%f" % (epoch, optimizer_1.param_groups[0]['lr']))
    scheduler_1.step()

输出结果为:

初始化的学习率: 0.11个epoch的学习率:0.1000002个epoch的学习率:0.0100003个epoch的学习率:0.0010004个epoch的学习率:0.0001005个epoch的学习率:0.0000106个epoch的学习率:0.0000017个epoch的学习率:0.0000008个epoch的学习率:0.0000009个epoch的学习率:0.00000010个epoch的学习率:0.000000
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值