• 优化器nn.optim-07


       在上述介绍中, nn.Module模块提供了网络骨架, nn.functional提供了各式各样的损失函数, 而Autograd又自动实现了求导与反向传播机制, 这时还缺少一个如何进行模型优化、 加速收敛的模块, nn.optim应运而生。

      nn.optim中包含了各种常见的优化算法, 包括随机梯度下降算法SGDStochastic Gradient Descent, 随机梯度下降) 、 AdamAdaptive Moment Estimation) 、 AdagradRMSProp, 这里仅对常用的SGDAdam两种算法进行详细介绍。

    1SGD方法

        梯度下降(Gradient Descent) 是迭代法中的一种, 是指沿着梯度下降的方向求解极小值, 一般可用于求解最小二乘问题。 在深度学习中,当前更常用的是SGD算法, 以一个小批次(Mini Batch) 的数据为单位, 计算一个批次的梯度, 然后反向传播优化, 并更新参数。 SGD的表
    达式如式(2-1) 与式(2-2) 所示 .

     公式中, gt代表了参数的梯度, η代表了学习率(Learning Rate) ,即梯度影响参数更新的程度, 是训练中非常重要的一个超参数。 SGD优化算法的好处主要有两点:

    ·分担训练压力: 当前数据集通常数量较多, 尺度较大, 使用较大的数据同时训练显然不现实, SGD则提供了小批量训练并优化网络的方法, 有效分担了GPU等计算硬件的压力。

    ·加快收敛: 由于SGD一次只采用少量的数据, 这意味着会有更多次的梯度更新, 在某些数据集中, 其收敛速度会更快。

    当然, SGD也有其自身的缺点:

    ·初始学习率难以确定: SGD算法依赖于一个较好的初始学习率,但设置初始学习率并不直观, 并且对于不同的任务, 其初始值也不固定。

    ·容易陷入局部最优: SGD虽然采用了小步快走的思想, 但是容易陷入局部的最优解, 难以跳出。

    有效解决局部最优的通常做法是增加动量(momentum) , 其概念来自于物理学, 在此是指更新的时候一定程度上保留之前更新的方向,同时利用当前批次的梯度进行微调, 得到最终的梯度, 可以增加优化的稳定性, 降低陷入局部最优难以跳出的风险。 其函数如式(2-3) 与式(2-4) 所示。

        公式中的μ为动量因子, 当此次梯度下降方向与上次相同时, 梯度会变大, 也就会加速收敛。 当梯度方向不同时, 梯度会变小, 从而抑制梯度更新的震荡, 增加稳定性。 在训练的中后期, 梯度会在局部极小值周围震荡, 此时gt接近于0, 但动量的存在使得梯度更新并不是0, 从而有可能跳出局部最优解。

      虽然SGD算法并不完美, 但在当今的深度学习算法中仍然取得了大量的应用, 使用SGD有时能够获得性能更佳的模型。

    2Adam方法

    SGD之外, Adam是另一个较为常见的优化算法。 Adam利用了梯度的一阶矩与二阶矩动态地估计调整每一个参数的学习率, 是一种学习率自适应算法。

    Adam的优点在于, 经过调整后, 每一次迭代的学习率都在一个确定范围内, 使得参数更新更加平稳。 此外, Adam算法可以使模型更快收敛, 尤其适用于一些深层网络, 或者神经网络较为复杂的场景.

    下面通过一个三层感知机的例子来介绍基本的优化过程。 新建一个mlp.py文件, 内容如下:

     1 # from torch import optim
     2 # optimizer = optim.SGD(model.parameters(), lr=0.001, momentum= 0.9)
     3 # optimizer = optim.Adam([var1, var2], lr=0.0001)
     4 
     5 import torch
     6 from torch import nn
     7 
     8 class MLP(nn.Module):
     9 
    10     def __init__(self, in_dim, hid_dim1, hid_dim2, out_dim):
    11         super(MLP, self).__init__()
    12 
    13         self.layer =  nn.Sequential(
    14             nn.Linear(in_dim, hid_dim1),
    15             nn.ReLU(),
    16             nn.Linear(hid_dim1, hid_dim2),
    17             nn.ReLU(),
    18             nn.Linear(hid_dim2, out_dim),
    19             nn.ReLU(0)
    20         )
    21 
    22     def forward(self, x):
    23         x = self.layer(x)
    24         return x
    View Code
     1 import torch
     2 from mlp import MLP
     3 from torch import optim
     4 from torch import nn
     5 
     6 # 实例化模型, 并赋予每一层的维度
     7 model = MLP(28*28, 300, 200, 10)
     8 #  打印model的结构, 由3个全连接层组成
     9 print(model)
    10 >> MLP(
    11         (layer): Sequential(
    12             (0): Linear(in_features=784, out_features=300, bias=True)
    13             (1): ReLU()
    14             (2): Linear(in_features=300, out_features=200, bias=True)
    15             (3): ReLU()
    16             (4): Linear(in_features=200, out_features=10, bias=True)
    17             (5): ReLU()
    18         )
    19     )
    20 
    21 #采用SGD优化器, 学习率为0.01
    22 optimizer = optim.SGD(params = model.parameters(), lr=0.01)
    23 data = torch.randn(10, 28*28)
    24 output = model(data)
    25 
    26 # 由于是10分类, 因此label元素从0到9, 一共10个样本
    27 label = torch.Tensor([1, 0, 4, 7, 9, 3, 4, 5, 3, 2]).long()
    28 print(label)
    29 >> tensor([1, 0, 4, 7, 9, 3, 4, 5, 3, 2])
    30 
    31 # 求损失
    32 criterion = nn.CrossEntropyLoss()
    33 loss = criterion(output, label)
    34 print(loss)
    35 tensor(2.2808, grad_fn=<NllLossBackward>)
    36 
    37 # 清空梯度, 在每次优化前都需要进行此操作
    38 o = optimizer.zero_grad()
    39 
    40 # 损失的反向传播
    41 l = loss.backward()
    42 
    43 # 利用优化器进行梯度更新
    44 ol = optimizer.step()
    View Code

    对于训练过程中的学习率调整, 需要注意以下两点:
    ·不同参数层分配不同的学习率: 优化器也可以很方便地实现将不同的网络层分配成不同的学习率, 即对于特殊的层单独赋予学习率, 其余的保持默认的整体学习率, 具体示例如下:

    1 # 对于model中需要单独赋予学习率的层, 如special层, 则使用'lr'关键字单独赋予
    2 optimizer = optim.SGD(
    3 [{'params': model.special.parameters(), 'lr': 0.001},
    4 {'params': model.base.parameters()}, lr=0.0001)
    View Code

    学习率动态调整: 对于训练过程中动态的调整学习率, 可以在迭代次数超过一定值后, 重新赋予optim优化器新的学习率。

  • 相关阅读:
    SpringBoot项目中,表单的验证操作
    微信点餐系统(十)-卖家端通用功能和上下架
    IDEA中Springboot静态文件加载(热部署)
    微信点餐系统(九)-卖家端订单
    微信点餐系统(八)-微信支付与退款
    MyBatis的生命周期
    关于flexjson将json转为javabean的使用
    Spring MVC中前端控制器拦截问题
    springmvc实现文件上传
    springmvc拦截器实现用户登录权限验证
  • 原文地址:https://www.cnblogs.com/zhaopengpeng/p/13641309.html
Copyright © 2020-2023  润新知