查看原文
其他

【他山之石】pytorch中optimizer对loss的影响

“他山之石,可以攻玉”,站在巨人的肩膀才能看得更高,走得更远。在科研的道路上,更需借助东风才能更快前行。为此,我们特别搜集整理了一些实用的代码链接,数据集,软件,编程技巧等,开辟“他山之石”专栏,助你乘风破浪,一路奋勇向前,敬请关注。

作者:知乎—Agnio-ltp

地址:https://www.zhihu.com/people/agnio-ltp

神经网络优化器的作用是为了优化神经网络,从而加速训练网络。pytorch中的optimizer包含好几个常用的分类器。这些分类器的原理各有差异,比如学习率,权重衰减等方面。这里分析不同分类器对于反向传播后的loss值的影响,通常loss值在多次反向传播后越小那么模型预测的准确率会越高,下面就直接通过代码来分析。
编译环境:anaconda、pytorch


01

读取数据集并构建模型
import torchimport torch.nn as nnimport torch.nn.functional as Fimport torchvisionimport torchvision.datasets as dsetimport torchvision.transforms as transformsimport torch.optim as optim
模型训练,使用线性模型
class Model(nn.Module): def __init__(self): super(Model, self).__init__() self.f1 = nn.Linear(28*28, 100, bias=True) self.f2 = nn.Linear(100, 10, bias=True)
def forward(self, data): data = self.f1(data) data = F.relu(data) data = self.f2(data) return data
读取MNIST数据集
root = 'data/MNIST'transformfun = transforms.Compose([ transforms.ToTensor(), ])mnist = torchvision.datasets.MNIST(root, train=True, transform=transformfun, target_transform=None, download=True)
count = 8 #每次选择8张进行训练,这里没必要选择太多mnist_loader = torch.utils.data.DataLoader(dataset = mnist ,batch_size=count ,shuffle=True)
构建函数方便后面使用不同分类器进行反向传播,而不需要复制粘贴大量代码
def other_optimizer(optimizer,model,mnist_loader): for epoch in range(10): #反向传播10次,并计算总的损失值 total_loss = 0 for batch in mnist_loader: images, labels = batch inputs = images.reshape(count,-1) output = model(inputs) loss = F.cross_entropy(output, labels)#计算损失值 optimizer.zero_grad() loss.backward() # 反向传播 optimizer.step() # 更新权值 total_loss += loss.item() print("反向传播次数:", epoch, " loss:", total_loss)

02

SGD——随机梯度下降
原理:每次随机选取数据样本进行学习,每次只随机选择一个样本来更新模型参数,因此每次的学习是非常快速的,并且可以进行在线更新。随机梯度下降最大的缺点在于每次更新可能并不会按照正确的方向进行,因此可以带来优化波动(扰动)。随机梯度下降所带来的波动有个好处就是对于类似盆地区域(即很多局部极小值点)那么这个波动的特点可能会使得优化的方向从当前的局部极小值点跳到另一个更好的局部极小值点,这样便可能对于非凸函数,最终收敛于一个较好的局部极值点,甚至全局极值点。
model = Model()optimizer = optim.SGD(model.parameters(), lr=0.01)other_optimizer(optimizer,model,mnist_loader)


03

SGD+momentum 动量法
利用SGD的时候,有时候会下降的非常慢,并且可能会陷入到局部最小值中。动量的引入就是为了加快学习过程,特别是对于高曲率、小但一致的梯度,或者噪声比较大的梯度能够很好的加快学习过程。动量的主要思想是积累了之前梯度指数级衰减的移动平均(前面的指数加权平均)
optimizer = optim.SGD(model.parameters(), lr=0.1,momentum=0.9)#注意这里lr=0.1other_optimizer(optimizer,model,mnist_loader)


04

SGD+Momentum +Nesterov
衔接上面的原理,变化在于就是拿着上一步的速度先走一小步,再看当前的梯度然后再走一步。
optimizer_Nesterov=optim.SGD(model.parameters(),lr=0.01, momentum=0.9, nesterov=True)other_optimizer(optimizer_Nesterov,model,mnist_loader)


05

RMSProp
该分类器的全称叫 Root Mean Square Prop。该算法初步解决了优化中摆动幅度大的问题,所谓的摆动幅度就是在优化中经过更新之后参数的变化范围。
optimizer_RMS=optim.RMSprop(model.parameters(), lr=0.01, alpha=0.99)print('RMSprop分类器:')other_optimizer(optimizer_RMS,model,mnist_loader)


06

AdaGrad分类器
Adagrad用来处理一些参数的下降不平衡问题。有些参数已经近乎最优,因此只需要微调了,而另一些可能还需要很大的调整。这种情况可能会在样本较少的情况下出现,比如含有某一特征的样本出现较少,因此被代入优化的次数也较少,这样就导致不同参数的下降不平衡。
optimizer_AdaGrad=optim.Adam(model.parameters(), lr=0.01)print('AdaGrad分类器:')other_optimizer(optimizer_AdaGrad,model,mnist_loader)


07

Adam优化算法,逐参数适应学习率方法
算法全称,adaptive moment estimation,自适应矩估计。概率论中矩的含义是:如果一个随机变量 X 服从某个分布,X 的一阶矩是 E(X),也就是样本平均值,X 的二阶矩就是 E(X^2),也就是样本平方的平均值。Adam 算法根据损失函数对每个参数的梯度的一阶矩估计和二阶矩估计动态调整针对于每个参数的学习速率。Adam 也是基于梯度下降的方法,但是每次迭代参数的学习步长都有一个确定的范围,不会因为很大的梯度导致很大的学习步长,参数的值比较稳定。
#Adam看起来像是RMSProp的Momentum版optimizer_Adam=optim.Adam(model.parameters(), lr=0.01, betas=(0.9, 0.99))print('Adam优化算法:')other_optimizer(optimizer_Adam,model,mnist_loader)


本文目的在于学术交流,并不代表本公众号赞同其观点或对其内容真实性负责,版权归原作者所有,如有侵权请告知删除。



“他山之石”历史文章


更多他山之石专栏文章,

请点击文章底部“阅读原文”查看



分享、点赞、在看,给个三连击呗!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存