深度学习的目标是通过不断改变网络参数,使得参数能够对输入做各种非线性变换拟合输出,本质上就是一个函数去寻找最优解,只不过这个最优解是一个矩阵,而如何快速求得这个最优解是深度学习研究的一个重点,以经典的resnet-50为例,它大约有2000万个系数需要进行计算,那么我们如何计算出这么多系数,有以下两种方法:

  1. 第一种是直接暴力穷举一遍参数,这种方法实施可能性基本为0,堪比愚公移山plus的难度。
  2. 为了使求解参数过程更快,人们提出了第二种办法,即BP+优化器逼近求解。

因此,优化器是根据网络反向传播的梯度信息来更新网络的参数,以起到降低loss函数计算值,使得模型输出更加接近真实标签。

1. Pytorch中的优化器

在pytorch中已经内置了以下的优化器:

  • torch.optim.Adadelta
  • torch.optim.Adagrad
  • torch.optim.Adam
  • torch.optim.AdamW
  • torch.optim.SparseAdam
  • torch.optim.Adamax
  • torch.optim.ASGD
  • torch.optim.LBFGS
  • torch.optim.RMSprop
  • torch.optim.Rprop
  • torch.optim.SGD

这些优化器都继承自torch.optim.Optimizer这个优化器的基类。

在本文中我们先介绍torch.optim.Optimizer基类,再介绍各个优化器。

2. 优化器基类torch.optim.Optimizer

2.1 torch.optim.Optimizer

torch.optim.Optimizer(params, defaults)

torch.optim.Optimizer为所有优化器的基类。

其中,

  • params:torch.Tensors或者dict类型的可迭代对象,一般是指torch.nn.Module.paramters(),即网络的参数
  • defaults: 一个包含优化选项默认值的字典(当参数组没有指定时使用)

2.2 torch.optim.Optimizer的属性

torch.optim.Optimizer有三个属性,

1 torch.optim.Optimizer.defaults

torch.optim.Optimizer.defaults存储的是优化器的超参数,例子如下

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim
import matplotlib.pyplot as plt

class MyNet(nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()
        self.hidden = nn.Linear(1, 20)
        self.predict = nn.Linear(20, 1)

    def forward(self,x):
        x = F.relu(self.hidden(x))
        x = self.predict(x)
        return x


if __name__ == '__main__':
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

    model = MyNet().to(device)
    optimizer = torch.optim.Adam(model.parameters(),lr=0.0001,betas=(0.9, 0.99))
    print('optimizer.defaults:{}'.format(optimizer.defaults))

输出

optimizer.defaults:{'lr': 0.0001, 'betas': (0.9, 0.99), 'eps': 1e-08, 'weight_decay': 0, 'amsgrad': False}

2 torch.optim.Optimizer.state

torch.optim.Optimizer.state 为参数的缓存

3. torch.optim.Optimizer.param_groups

torch.optim.Optimizer.param_groups为优化器的参数组,是一个list,然后其中每一个元素为一个字典,分别记录了paramslrweight_decay等与优化器参数相关的信息,例子如下

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim
import matplotlib.pyplot as plt

class MyNet(nn.Module):
    def __init__(self):
        super(MyNet, self).__init__()
        self.hidden = nn.Linear(1, 20)
        self.predict = nn.Linear(20, 1)

    def forward(self,x):
        x = F.relu(self.hidden(x))
        x = self.predict(x)
        return x


if __name__ == '__main__':
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

    model = MyNet().to(device)
    optimizer = torch.optim.Adam(model.parameters(),lr=0.0001,betas=(0.9, 0.99))
    print('optimizer.param_groups:{}'.format(optimizer.param_groups))

输出

optimizer.param_groups:[{'params': [Parameter containing:
tensor([[-0.1789],
        [-0.1629],
        [-0.6816],
        [-0.7967],
        [-0.5432],
        [-0.7973],
        [-0.1869],
        [ 0.7843],
        [-0.1039],
        [-0.4303],
        [-0.4451],
        [ 0.5766],
        [ 0.6883],
        [-0.0862],
        [ 0.5169],
        [ 0.0244],
        [-0.1295],
        [ 0.7358],
        [-0.9221],
        [-0.1463]], device='cuda:0', requires_grad=True), Parameter containing:
tensor([-0.3876, -0.0316, -0.1787,  0.8979,  0.9626,  0.0452, -0.8819,  0.8417,
         0.7994, -0.4167, -0.1814, -0.3666, -0.6344, -0.7134, -0.3289,  0.9688,
        -0.7236, -0.1622,  0.2909,  0.3827], device='cuda:0',
       requires_grad=True), Parameter containing:
tensor([[ 0.2151,  0.0721,  0.1951, -0.1590,  0.0827, -0.2209,  0.1915,  0.2087,
         -0.0106, -0.0042,  0.0260, -0.0419, -0.0034,  0.2065, -0.1061,  0.0834,
          0.0561, -0.1628, -0.0110,  0.0828]], device='cuda:0',
       requires_grad=True), Parameter containing:
tensor([0.0428], device='cuda:0', requires_grad=True)], 
'lr': 0.0001, 
'betas': (0.9, 0.99), 
'eps': 1e-08, 
'weight_decay': 0, 
'amsgrad': False}]

继承自torch.optim.Optimizer的每一个优化器都继承上述的三个属性。

2.3 torch.optim.Optimizer的方法

2.3.1 add_param_group

1. 函数形式

add_param_group(param_group)

2. 函数功能

添加一个参数组到当前优化器的参数组。

此函数在微调预训练网络时非常有用,因为可以使被冻结的层可训练并且添加到参数优化的过程中。

3. 函数参数

  • param_groups:dict字典,指定应添加到参数组的Tensor

2.3.2 load_state_dict

1. 函数形式

load_state_dict(state_dict)

2. 函数功能

加载优化器状态字典。

可以用来实现模型的断点续训,继续上一次的参数进行训练。

3. 函数参数

  • state_dict:dict字典,从state_dict()返回的优化器状态。

2.3.3 state_dict

1. 函数形式

state_dict()

2. 函数功能

返回优化器状态字典。

其返回的内容包含两个部分:

  • state:当前优化状态的dict,不同的优化器保存的内容不同
  • param_groups:包含所有参数组的字典

2.3.4 step

1. 函数形式

step(closure)

2. 函数功能

指定单步的优化器优化,进行参数更新。

3. 函数参数

  • closure:可调用的函数对象,该函数中的功能为重新计算模型结果并返回loss。

2.3.5 zero_grad

1. 函数形式

zero_grad(set_to_none=False)

2. 函数功能

设置所有参数的梯度,将其置0。

PyTorch的特性是张量的梯度不自动清零,因此每次反向传播后都需要清空梯度。

3. 函数参数

  • set_to_none:bool,默认值为False。如果设置为True时,会将梯度设置为None,而不是设置为0。这种操作通常会降低内存占用,并可一定程度提升性能,但是这种操作会影响一些方面。

    比如,

    1):当用户尝试访问梯度并对其执行手动操作时,None或0的张量的行为将不同;

    2):如果设置为True,并进行误差反向传播,对于没有接受到梯度的参数,其梯度会一直为None;

    3):对于梯度为None或者0,torch.optim.optimizers可能会有不同的处理方式,一种是以梯度为0进行处理,另一种则是跳过此步骤;

继承自torch.optim.Optimizer的每一个优化器都继承上述的方法。

2.4 torch.optim.Optimizer的使用

for input, target in dataset:
    # 梯度置零
    optimizer.zero_grad()
    # 模型推理
    output = model(input)
    # 求解loss
    loss = loss_fn(output, target)
    # 反向传播
    loss.backward()
    # 更新参数
    optimizer.step()

或者

for input, target in dataset:
    def closure():
        optimizer.zero_grad()
        output = model(input)
        loss = loss_fn(output, target)
        loss.backward()
        return loss
    optimizer.step(closure)

3. Pytorch中的优化器算法

3.1 torch.optim.Adadelta

实现论文ADADELTA: An Adaptive Learning Rate Method的算法。

1. 类形式

torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e-06, weight_decay=0)

2. 类参数

  • params:可迭代对象,一般是指torch.nn.Module.paramters(),即网络的参数
  • lr:float,默认值为1.0。在delta被应用到参数更新之前对它缩放的系数
  • rho:float,默认值为0.9。用于计算平方梯度的运行平均值的系数
  • eps:float,默认值为1e-6。为了增加数值计算的稳定性而加到分母里的项
  • weight_decay:float,默认值为0。权重衰减,L2惩罚项

3.2 torch.optim.Adagrad

实现论文Adaptive Subgradient Methods for Online Learning and Stochastic Optimization的算法。

1. 类形式

torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0, initial_accumulator_value=0, eps=1e-10)

2. 类参数

  • params:可迭代对象,一般是指torch.nn.Module.paramters(),即网络的参数

  • lr:float,默认值为1e-2。学习率

  • lr_decay:float,默认值为0。学习率衰减系数

  • weight_decay:float,默认值为0。权重衰减,L2惩罚项

  • eps:float,默认值为1e-2。为了增加数值计算的稳定性而加到分母里的项

3.3 torch.optim.Adam

实现论文[Adam: A Method for Stochastic Optimization](Adam: A Method for Stochastic Optimization)的算法,L2惩罚项的更改参考Decoupled Weight Decay Regularization

1. 类形式

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

2. 类参数

  • params:可迭代对象,一般是指torch.nn.Module.paramters(),即网络的参数

  • lr:float,默认为1e-3。学习率

  • betas:Tuple[float,float],默认值为[0.9,0.999]。用于计算梯度及其平方的运行平均值的系数

  • eps:float,默认值为1e-8。为了增加数值计算的稳定性而加到分母里的项

  • weight_decay:float,默认值为0。权重衰减,L2惩罚项

  • amsgrad:bool,默认值为False。是否使用本文算法的变体AMSGrad:On the Convergence of Adam and Beyond

3.4 torch.optim.AdamW

实现论文Adam: A Method for Stochastic Optimization,其变体为Decoupled Weight Decay Regularization

1. 类形式

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

2. 类参数

  • params:可迭代对象,一般是指torch.nn.Module.paramters(),即网络的参数
  • lr:float,默认为1e-3。学习率
  • betas:Tuple[float,float],默认值为[0.9,0.999]。用于计算梯度及其平方的运行平均值的系数
  • eps:float,默认值为1e-8。为了增加数值计算的稳定性而加到分母里的项
  • weight_decay:float,默认值为0。权重衰减,L2惩罚项
  • amsgrad:bool,默认值为False。是否使用本文算法的变体AMSGrad:On the Convergence of Adam and Beyond

3.5 torch.optim.SparseAdam

实现适用于稀疏张量的Adam算法。

1. 类形式

torch.optim.SparseAdam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08)

2. 类参数

  • params:可迭代对象,一般是指torch.nn.Module.paramters(),即网络的参数
  • lr:float,默认为1e-3。学习率
  • betas:Tuple[float,float],默认值为[0.9,0.999]。用于计算梯度及其平方的运行平均值的系数
  • eps:float,默认值为1e-8。为了增加数值计算的稳定性而加到分母里的项

3.6 torch.optim.Adamax

实现Adamax算法(基于无穷范数的Adam变体),在论文Adam: A Method for Stochastic Optimization提出。

1. 类形式

torch.optim.Adamax(params, lr=0.002, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)

2. 类参数

  • params:可迭代对象,一般是指torch.nn.Module.paramters(),即网络的参数
  • lr:float,默认为2e-3。学习率
  • betas:Tuple[float,float],默认值为[0.9,0.999]。用于计算梯度及其平方的运行平均值的系数
  • eps:float,默认值为1e-8。为了增加数值计算的稳定性而加到分母里的项
  • weight_decay:float,默认值为0。权重衰减,L2惩罚项

3.7 torch.optim.ASGD

实现论文Acceleration of stochastic approximation by averaging中提出的平均梯度下降算法。

1. 类形式

torch.optim.ASGD(params, lr=0.01, lambd=0.0001, alpha=0.75, t0=1000000.0, weight_decay=0)

2. 类参数

  • params:可迭代对象,一般是指torch.nn.Module.paramters(),即网络的参数
  • lr:float,默认为1e-2。学习率
  • lambd:float,默认为1e-4。衰减项
  • alpha:float,默认值为0.75。eta更新力度
  • t0:float,默认值为1e6。开始求平均值的点
  • weight_decay:float,默认值为0。权重衰减,L2惩罚项

3.8 torch.optim.LBFGS

实现L-BFGS算法

1. 类形式

torch.optim.LBFGS(params, lr=1, max_iter=20, max_eval=None, tolerance_grad=1e-07, tolerance_change=1e-09, history_size=100, line_search_fn=None)

2. 类参数

  • params:可迭代对象,一般是指torch.nn.Module.paramters(),即网络的参数
  • lr:float,默认为1。学习率
  • max_iter:int,默认值为20。每个优化步骤的最大迭代次数
  • max_eval:int,默认值为max_iter * 1.25。每个优化步骤的最大函数评估数
  • tolerance_grad:float,默认值为1e-5。一阶最优性的终止容差
  • tolerance_change:float,默认值为1e-9。功能值/参数变化的终止容差
  • history_size:int,默认值为100。更新历史记录大小
  • line_search_fn:str,默认值为None。strong_wolft或者None

3.9 torch.optim.RMSprop

实现RMSprop算法。

1. 类形式

torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)

2. 类参数

  • params:可迭代对象,一般是指torch.nn.Module.paramters(),即网络的参数
  • lr:float,默认为1e2。学习率
  • momentum:float,默认值为0。动量因子
  • alpha:float,默认值为0.99。平滑常数
  • eps:float,默认值为1e-8。为了增加数值计算的稳定性而加到分母里的项
  • centered:bool,默认值为False。如果设置为True,计算中心RMSProp,通过估计其方差对梯度进行归一化
  • weight_decay:float,默认值为0。权重衰减,L2惩罚项

3.10 torch.optim.Rprop

实现弹性反向传播算法

1. 类形式

torch.optim.Rprop(params, lr=0.01, etas=(0.5, 1.2), step_sizes=(1e-06, 50))

2. 类参数

  • params:可迭代对象,一般是指torch.nn.Module.paramters(),即网络的参数
  • lr:float,默认为1e2。学习率
  • etas:Tuple[float,float],默认值为(0.5,1.2)。(etamius,etaplis)数据对,乘法递增因子和递减因子
  • step_sizes:Tuple[float,float],默认值为(1e-6,50),最小和最大允许步长

3.11 torch.optim.SGD

实现随机梯度下降算法(可选动量)

1. 类形式

torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0, nesterov=False)

2. 类参数

  • params:可迭代对象,一般是指torch.nn.Module.paramters(),即网络的参数
  • lr:float。学习率
  • momentum:float,默认值为0。动量因子
  • dampening:float,默认值为0。动量阻尼
  • weight_decay:float,默认值为0。权重衰减,L2惩罚项
  • nesterov:bool,默认为False。如果设置为True,则启用Nesterov momentum

参考链接