PyTorch基础:神经网络工具箱torch.nn(优化器nn.optim)

nn.Module模块提供了网络骨架,nn.functional提供了各式各样的损失函数,而Autograd又自动实现了求导与反向传播机制,这时候还缺少一个如何进行模型优化、加速收敛的模块,nn.optim应运而生。
nn.optim中包含了各种常见的优化算法,包括随机梯度下降算法SGD(Stochatic Gradient Descent,随机梯度下降)、Adam(Adaptive Moment Esitmation)、Adagrad、RMSProp。

SGD方法
梯度下降(Gradient Descent)是迭代法中的一种,是指沿着梯度下降的方向求解极小值,一般可用于求解最小二乘问题。在深度学习中,当前更常使用的是SGD算法,以一个小批次(Mini Batch)的数据为单位,计算一个批次的梯度,然后反向传播优化,并更新参数
在这里插入图片描述
梯度影响学习参数更新的程度,是训练中非常重要的一个超参数。SGD优化算法的好处主要有两点:

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

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

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

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

  • 容易陷入局部最优:SGD虽然采用了小步快走的思想,但是容易陷入局部的最优解,难以跳出
    有效解决局部最优的做法是增加动量(momentum),其概念来自于物理学,在此是指更新的时候一定程度上保留之前更新的方向,同时利用当前批次的梯度进行微调,得到最终的梯度,可以增加优化的稳定性,降低陷入局部最优难以跳出的风险,其函数如下:
    在这里插入图片描述
    当此次梯度下降方向与上次相同时,梯度会变大,也就会加速收敛。当梯度方向不同时,梯度会变小,从而一直梯度更新的震荡,增加稳定性。在训练的中后期,梯度会在局部极小值周围震荡,此时g_t接近于0,但动量的存在使得梯度更新并不是0,从而有可能跳出局部最优解。
    最然SGD算法并不完美,但在当今的深度学习算法中仍然取得了大量的应用,使用SGD有时候能够获得性能更佳的模型

Adam方法
在SGD之外,Adam是另一个较为常见的优化算法。Adam利用了梯度的一阶矩与二阶矩动态地估计调整每一个参数的学习率,是一种学习率自适应算法
Adam的有点在于经过调整后,每一次迭代的学习率都在一个确定的范围之内,使得参数更新更加平稳。此外,Adam算法可以使模型更快收敛,尤其使用与一些深层网络,或者神经网络较为复杂的场景
在这里插入图片描述
我们计算了梯度的指数平均和梯度平方的指数平均(等式1和等式2)。为了得出学习步幅,等式3在学习率上乘以梯度的平均(类似动量),除以梯度平方平均的均方根(类似RMSProp)。等式4是权重更新步骤
超参数β1一般取0.9,β2一般取0.99,φ 一般定为1e-10

下面利用PyTorch来搭建常用的优化器,传入的参数包括网络中需要学习优化的Tensor对象、学习率和权值衰减等

from torch import optim
optimizer = optim.SGD(model.parameters(),lr=0.001,momentum=0.9)
optimizer = optim.Adam([var1,var2],lr=0.0001)

下面通过一个三层感知机的例子来介绍基本的优化过程:
mlp.py

from torch import nn


class MLP(nn.Module):
    def __init__(self, in_dim, hid_dim1, hid_dim2, out_dim):
        super(MLP, self).__init__()
        #通过Sequential快速搭建三层的感知机
        self.layer = nn.Sequential(
          nn.Linear(in_dim, hid_dim1),
          nn.ReLU(),
          nn.Linear(hid_dim1, hid_dim2),
          nn.ReLU(),
          nn.Linear(hid_dim2, out_dim),
          nn.ReLU()
                                   )
        
    def forward(self, x):
        x = self.layer(x)
        return x

终端:

>>> import torch
>>> from mlp import MLP
>>> from torch import optim
>>> from torch import nn
>>> #实例化模型,并赋予每一层的维度
>>> model = MLP(28*28,300,200,10)
>>> model    #打印model的结构,由3个全连接层组成
MLP(
  (layer): Sequential(
    (0): Linear(in_features=784, out_features=300, bias=True)
    (1): ReLU()
    (2): Linear(in_features=300, out_features=200, bias=True)
    (3): ReLU()
    (4): Linear(in_features=200, out_features=10, bias=True)
    (5): ReLU()
  )
)
>>> #采用SGD优化器,学习率为0.01
>>> optimizer = optim.SGD(params = model.parameters(),lr=0.01)
>>> data = torch.randn(10,28*28)
>>> data
tensor([[-0.9042, -0.2768,  1.0551,  ...,  0.4825, -0.6427, -0.7589],
        [-1.3073, -0.5553, -0.4306,  ..., -0.9818, -1.1010, -0.1162],
        [-1.9565,  0.6977, -0.6221,  ...,  0.0488, -0.6585, -0.3977],
        ...,
        [-1.6100,  0.5664,  0.1511,  ...,  0.2569,  0.8622, -2.1218],
        [-0.9872, -0.3189,  0.1302,  ..., -0.2465, -2.3916,  1.4722],
        [-0.7321,  0.6455,  1.4625,  ..., -0.5394,  0.4357, -0.1728]])
>>> output = model(data)
>>> #由于是10个分类,因此label元素从0到9,一共10个样本
>>> label = torch.Tensor([1,0,4,7,9,3,4,5,3,2]).long()
>>> label
tensor([1, 0, 4, 7, 9, 3, 4, 5, 3, 2])
>>> #求损失
>>> criterion = nn.CrossEntropyLoss()
>>> loss = criterion(output,label)
>>> loss
tensor(2.2849, grad_fn=<NllLossBackward>)
>>> #清空梯度,在每次优化前都需要进行此操作
>>> optimizer.zero_grad()
>>> #损失的反向传播
>>> loss.backward()
>>> #利用优化器进行梯度更新
>>> optimizer.step()

对于训练过程中的学习率调整,需要注意以下两点:

  • 学习率动态调整:对于训练过程中动态的调整学习率,可以在迭代次数超过一定值后,重新赋予optim优化器新的学习率
  • 不同参数层分配不同的学习率:优化器也可以很方便地实现将不同的网络层分配成不同的学习率,即对于特殊的层单独赋予学习率其余的保持默认的整体学习率,具体实例如下:
#对于model中需要单独赋予学习率的层,如special层,则使用‘lr’关键字单独赋予
optimizer = optim.SGD(
    [{'params': model.special.parameters(),'lr': 0.001},
     {'prarms': model.base.parameters()},lr=0.0001]
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丁天牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值