首页 > 其他 > 详细

优化器nn.optim-07

时间:2020-09-09 20:40:48      阅读:96      评论:0      收藏:0      [点我收藏+]

   在上述介绍中, 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优化器新的学习率。

 

优化器nn.optim-07

原文:https://www.cnblogs.com/zhaopengpeng/p/13641309.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!