pytorch学习(六)——优化器

文章目录

  • 1. 优化器概述
  • 2. 优化器算法
    • 2.1 Adam
    • 2.2 RAdam
    • 2.3 AdamW
  • 3. 保存读取
  • 4. 学习率更新
    • 4.1 自定义学习率更新
    • 4.2 常数衰减
    • 4.3 分段衰减
    • 4.4 指数衰减
    • 4.5 循环学习率

1. 优化器概述

深度学习的目标是通过不断改变网络参数,使得参数能够对输入做各种非线性变换拟合输出,本质上就是一个函数去寻找最优解,所以如何去更新参数是深度学习研究的重点。通常将更新参数的算法称为优化器,字面理解就是通过什么算法去优化网络模型的参数。常用的优化器就是梯度下降。接下来讲的就是梯度下降和进一步优化梯度下降的各种算法。

2. 优化器算法

优化器的参数优化提供很多种方法的梯度下降,这些算法都是为了能够更快的迭代到参数的最优解,比如 AdamRMSpropSGD 等等算法,下面我来介绍几种效果比较好的算法。

2.1 Adam

Adam 算法同时获得了 AdaGrad 和 RMSProp 算法的优点,适应性梯度算法(AdaGrad)为每一个参数保留一个学习率以提升在稀疏梯度(即自然语言和计算机视觉问题)上的性能,均方根传播(RMSProp)基于权重梯度最近量级的均值为每一个参数适应性地保留学习率。这意味着算法在非稳态和在线问题上有很有优秀的性能。

pytorch中的API如下所示:

torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False, *, foreach=None, maximize=False, capturable=False)

params:要优化的参数
lr:初始学习率
如果要讲全部参数的含义恐怕要扯出很多的原理了,一般情况下只需要设置上面两个参数即可。

特点

  • 收敛快
  • 所需内存小
  • 容易陷入局部最优解。

2.2 RAdam

Ada收敛快,但是容易陷入局部解中。Radam使用预热的方法来解决Adam容易收敛到局部最优解的问题,前期选用比较稳的SGD + Momentum来进行训练,来稳定缩小方差。

pytorch中的API如下所示:

torch.optim.RAdam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, foreach=None)

参数的同样也只需要掌握前面两个参数即可。

特点

  • RAdam对学习速率变化(最重要的超参数)具有更强的鲁棒性,并在各种数据集和各种AI体系结构中提供更好的训练精度和泛化。
  • RAdam根据方差的潜在散度动态地打开或关闭自适应学习率,它提供了不需要可调参数的动态warmup。

2.3 AdamW

AdamW与Adam相比,加入了加入weight decay,通常会给模型带来更低的训练loss和测试误差。除此之外,在固定相同的训练loss的情况下,AdamW也有更好的泛化性能。

AdamW与Adam相比,具有更优异的性能。

pytorch中函数的API如下:

torch.optim.AdamW(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0.01, amsgrad=False, *, maximize=False, foreach=None, capturable=False)

参数的同样也只需要掌握前面两个参数即可。

3. 保存读取

保存
保存优化器可以使用 Optimizer.state_dict(),将其中的参数以字典形式返回出来,然后使用 torch.save() 进行保存。保存的代码如下示例所示

torch.save(optimizer.state_dict(), PATH)

读取
可以使用 Optimizer.load_state_dict() 方法对存储的数据进行,读取的代码如下所示:

optimizer.load_state_dict(torch.load(PATH))

4. 学习率更新

在深度学习中,最重要的超参数要数学习率了,学习率的调整对整个模型的训练起到至关重要的作用,学习率的更新方法十分多,下面我简要的介绍一下。有关下面各种算法的介绍、用处以及作用可以参考这篇文章。

torch.optim.lr_scheduler 中含有一些学习率更新的方法,这些方法在一定程度上能够对整个模型的训练起到一些作用。从经验上看,学习率在一开始要保持大些来保证收敛速度,在收敛到最优点附近时要小些以避免来回振荡。

4.1 自定义学习率更新

pytorch中允许自定义学习率的更新函数,该函数的API如下所示:

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

参数解释如下:
optimizer:传入的优化器
lr_lambda:自定义的学习率改变规则,可以是lambda表达式,也可以是函数,其含有一个参数 epoch,是 lr_scheduler 自己传入的参数
last_epoch:epoch计数器,表示当前已经完成多少个epoch,默认-1,表示还未开始训练,对于加载checkpoint继续训练,那么这里要传入对应的已迭代次数
verbose:是否在学习率更新时打印学习率

更新学习率的方法如下:
l r n e w = l a m b d a ∗ l r i n i t i a l lr_{new} = lambda * lr_{initial} lrnew=lambdalrinitial其中 l a m b d a lambda lambdalr_lambda 参数返回的数值, l r i n i t i a l lr_{initial} lrinitial 是最初设置的学习率,不是上一轮的学习率

代码示例

import torch
from torch import nn
import math


class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=2, stride=1, padding=0)

    def forward(self, x):
        out = self.conv(x)
        return out


net = Net()


def set_lr(epoch):
    lamda = math.pow(0.5, int(epoch / 3))
    return lamda


optimizer = torch.optim.Adam(net.parameters(), lr=1e-2)
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=set_lr)

for i in range(9):
    print("lr of epoch", i, "=>", scheduler.get_last_lr())
    # 更新模型参数
    optimizer.step()
    # 更新学习率
    scheduler.step()

输出如下:

lr of epoch 0 => [0.01]
lr of epoch 1 => [0.01]
lr of epoch 2 => [0.01]
lr of epoch 3 => [0.005]
lr of epoch 4 => [0.005]
lr of epoch 5 => [0.005]
lr of epoch 6 => [0.0025]
lr of epoch 7 => [0.0025]
lr of epoch 8 => [0.0025]

4.2 常数衰减

即每经过一定的epoch,学习率变为之前的多少倍,该函数的API如下所示:

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

参数解释如下:
step_size:经过 step_size 个epoch后学习率进行衰减
gamma:每次学习率衰减为上次学习率的多少倍
其余同名参数参照上面的解释。

更新学习率的方法为:
l r n e w = γ e p o c h s t e p _ s i z e ∗ l r i n i t i a l lr_{new}=\gamma^{\frac{epoch}{step\_size}}*lr_{initial} lrnew=γstep_sizeepochlrinitial其中 γ \gamma γ 为上面函数的 gamma 参数。

代码示例
这里我们仅改变变量 scheduler,即学习率管理器,其余代码不变,查看结果。

scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 3, 0.1)

输出如下:

lr of epoch 0 => [0.01]
lr of epoch 1 => [0.01]
lr of epoch 2 => [0.01]
lr of epoch 3 => [0.001]
lr of epoch 4 => [0.001]
lr of epoch 5 => [0.001]
lr of epoch 6 => [0.0001]
lr of epoch 7 => [0.0001]
lr of epoch 8 => [0.0001]

4.3 分段衰减

当前迭代的次数达到指定的epoch后,学习率按照指定倍数进行衰减。

函数API如下所示

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

milestones:为一个列表,当epoch到达列表中指定的epoch时,发生衰减。

代码示例:
这里我们仅改变变量 scheduler,即学习率管理器,其余代码不变,查看结果。

scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=[3,7], gamma=0.1)

输出如下:

lr of epoch 0 => [0.01]
lr of epoch 1 => [0.01]
lr of epoch 2 => [0.01]
lr of epoch 3 => [0.001]
lr of epoch 4 => [0.001]
lr of epoch 5 => [0.001]
lr of epoch 6 => [0.001]
lr of epoch 7 => [0.0001]
lr of epoch 8 => [0.0001]

4.4 指数衰减

指数衰减的API如下所示:

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

学习率更新的规则如下:
l r n e w = γ e p o c h ∗ l r i n i t i a l lr_{new}=\gamma^{epoch}*lr_{initial} lrnew=γepochlrinitial
其中 γ \gamma γ 参数为上面的 gamma

代码示范
这里我们仅改变变量 scheduler,即学习率管理器,其余代码不变,查看结果。

scheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.99)

输出如下:

lr of epoch 0 => [0.01]
lr of epoch 1 => [0.0095]
lr of epoch 2 => [0.009025]
lr of epoch 3 => [0.00857375]
lr of epoch 4 => [0.0081450625]
lr of epoch 5 => [0.007737809374999999]
lr of epoch 6 => [0.007350918906249998]
lr of epoch 7 => [0.006983372960937498]
lr of epoch 8 => [0.006634204312890623]

4.5 循环学习率

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:LR下界
max_lr:LR上界
step_size_up:每个循环分为两部分,一部分上升,一部分下降,构成一个三角形,这部分设置上升区间的迭代次数(注意是迭代,每一个batch算一次,而不是epoch)。
step_size_down:下降区间的迭代次数。

你可能感兴趣的:(Pytorch,pytorch)