服务热线:13988889999

站内公告:

诚信为本:市场永远在变,诚信永远不变。
Pytorch:torch.optim模块

你的位置: 首页 > 杏福新闻

Pytorch:torch.optim模块

2024-06-24 13:53:57  点击量:

本篇笔记主要介绍torch.optim模块,记录学习过程

在深度学习中,我们通常会使用优化算法来调整神经网络的权重和偏差,以便模型能够更好地拟合训练数据。是PyTorch中的一个模块,它提供了各种优化算法的实现,用于自动化地优化神经网络的参数。换句话说,可以帮助我们让模型更好地学习,从而提高性能。

  • 优化器主要是在模型训练阶段对模型可学习参数进行更新, 常用优化器有 SGD,RMSprop,Adam等
  • 优化器初始化时传入模型的可学习参数,以及其他超参数如 lr,momentum等
  • 在训练过程中先调用 清空梯度,再调用 反向传播,最后调用更新模型参数

简单使用示例如下所示:

 

1.1 PyTorch 中的优化器

所有优化器都是继承父类 Optimizer,如下列表是 PyTorch 提供的优化器:
(具体用法和优缺点,后续更新。。。。。。。。。。。)

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

1.2 父类Optimizer 基本原理

Optimizer 是所有优化器的父类,它主要有如下公共方法:

: 添加模型可学习参数组
: 进行一次参数更新
: 清空上次迭代记录的梯度信息
: 返回 dict 结构的参数状态
: 加载 dict 结构的参数状态

上述方法一一解读:

1.2.1 初始化 Optimizer

初始化优化器只需要将模型的**可学习参数(params)超参数(defaults)**分别传入优化器的构造函数

关键几个点为:

  1. self.defaults = defaults
  2. self.state = defaultdict(dict)
  3. self.param_groups = [] 特别重要,最需要记住的属性,特别是属性的内容和其形式。
  4. self.add_param_group方法,往self.param_groups里面放东西。

下面是Optimizer的初始化函数核心代码:

 

该初始化方法接收两个参数,一个是params,一个是defaults

这两个分开说,先说params,最常见的就是model.parameters(),当然net.parameters()也是一样的,就是模型类的对象的变量名不同,如下所示。

 

params是个生成器,只返回各模型层的参数,没有参数名。

注意__init__方法中,得到一个新的变量 ,(这里self.param_groups是干什么的呢??)。

,list可以把生成器的元素都取出来,所以,很明显,param_groups就是一个Parameter类对象的列表,里面的元素是每个网络层的参数weight和bias(如果有)

 

param_groups[0]是Parameter类,不是dict,这种形式的param_groups会被改造,将整个param_groups作为值,"params"作为键,形成一个键值对,放在字典里,然后重新赋值给param_groups。

现在我们要记得 的形式,一个列表,里面是一个字典,字典的键是"params",值为所有网络层的参数。

 

将param_groups中的每个元素送进这个列表中。现在的param_groups里只有一个元素{“param”: [参数]}。

1.2.2 add_param_group

该方法在初始化函数中用到,主要用来向 添加不同分组的模型参数

 

将上述代码分为8个步骤: 请认真看一遍代码以及注释

现在我们知道self.param_groups这个列表中具有字典,每个字典的keys为dict_keys([‘params’, ‘lr’, ‘momentum’, ‘dampening’, ‘weight_decay’, ‘nesterov’]),当然,每个键都有其对应的值。这些键值对是构建SGD实例时,传进来的参数。

params还有一种常见形式如下。

 

我们可以对比一下 这种形式(前面讲的)上述model.parameters() 这种方式的不同。

  • 前者是包含着字典的列表,后者是生成器
  • 进入到Optimizer类的初始化函数中,前者不变,还是包含2个字典的列表,后者先变成参数的列表,再变成只有一个字典的列表,该字典中只有一个键值对,"params"和所有参数值
  • 在执行self.add_param_group()方法的循环里,前者需要遍历两个字典,后者只有一个字典,也就是说,最终在self.param_groups这个列表中,前者最终具有两个具有全部键值对的字典,后者只有一个
  • 在如上self.add_param_group()方法中,步骤2处,取出前者字典中的"params"对应的值为生成器,在步骤3处,将其变成了参数的列表,后者在步骤2和步骤3处没变化,因为在初始化一开始就使用list()将model.parameters()的所有参数取出来了。
  • 在如上self.add_param_group()方法中,标记为步骤4处没区别。在步骤5处有区别,并且该区别非常关键。这是对不同参数设置不同学习率和动量的地方。
    param_group是循环中取出的字典,对于如上有两个字典的来说,就是将self.defaults里面取出来的键值对,分别放到两个字典中去。param_group.setdefault(name,
    default)这句代码。如果param_group这个字典中比如第一个字典具有"lr"这个键的,保持不变,对于第二个字典里面没有"lr"这个键的,将default和name设置为新的键值对。不知道的同学可以看一下dict中setdefault这个方法的功能。
  • 前者的步骤6和步骤7,由于存在两个字典,所以第二次需要和第一次进行对比,看看两个字典里面的"params"这个键对应的参数是否相同,如果相同,引用的就是同一块地址,设置不同的学习率等参数就没意义了,就会报错。
  • 最后,将两个具有所有键值对,但是参数不同的两个字典,加入到self.param_groups这个列表中。
1.2.3 step

此方法主要完成一次模型参数的更新

基类 Optimizer 定义了 step 方法接口,如下所示

 

子类如 SGD 需要实现 step 方法,如下所示:

 
  • step 方法可传入闭包函数 closure,主要目的是为了实现如Conjugate Gradient和LBFGS等优化算法,这些算法需要对模型进行多次评估
  • Python 中闭包概念:在一个内部函数中,对外部作用域的变量进行引用(并且一般外部函数的返回值为内部函数),那么内部函数就被认为是闭包

下面是 closure 的简单示例:

 
1.2.4 zero_grad

在反向传播计算梯度之前对上一次迭代时记录的梯度清零,参数set_to_none 设置为 True 时会直接将参数梯度设置为 None,从而减小内存使用

但通常情况下不建议设置这个参数,因为梯度设置为 None 和 0 在 PyTorch 中处理逻辑会不一样。

 
1.2.5 state_dict() 和 load_state_dict

这两个方法实现序列化反序列化功能。

  • : 将优化器管理的参数和其状态信息以 dict 形式返回
  • : 加载之前返回的 dict,更新参数和其状态

两个方法可用来实现模型训练中断后继续训练功能

 
 

2.1 基类: _LRScheduler

学习率调整类主要的逻辑功能就是每个 epoch 计算参数组的学习率,更新 optimizer对应参数组中的lr值,从而应用在optimizer里可学习参数的梯度更新。

所有的学习率调整策略类的父类是,基类 定义了如下方法:

  • : 子类公用
  • : 子类需要实现
  • : 子类公用
  • : 显示 lr 调整信息
  • : 子类可能会重写
  • : 子类可能会重写
2.1.1 初始化

LR_scheduler是用于调节学习率lr的,在代码中,我们经常看到这样的一行代码

 

在pytorch代码中,各种类型scheduler大多基于 _LRScheduler

基类的初始化函数可传入两个参数,

  • 第一是optimizer就是之前我们讲过的优化器的实例
  • 第二个参数last_epoch是最后一次 epoch 的 index,默认值是 -1,代表初次训练模型

此时会对optimizer里的各参数组设置初始学习率 initial_lr。若last_epoch传入值大于 -1,则代表从某个 epoch 开始继续上次训练,此时要求optimizer的参数组中有initial_lr初始学习率信息。

初始化函数内部的 函数主要是为了确保是在之后调用的 (PyTorch=1.1 发生变化). 注意在__init__函数最后一步调用了self.step(),即_LRScheduler在初始化时已经调用过一次step()方法。

 
2.1.2 step

当模型完成一个 epoch 训练时,需要调用step()方法,该方法里对last_epoch自增之后,在内部上下文管理器类里调用子类实现的get_lr()方法获得各参数组在此次 epoch 时的学习率,并更新到 optimizer的param_groups属性之中,最后记录下最后一次调整的学习率到self._last_lr,此属性将在get_last_lr()方法中返回。在这个方法中用到了上下文管理功能的内部类 _enable_get_lr_call,实例对象添加了_get_lr_called_within_step属性,这个属性可在子类中使用。此外,需要注意的是,step方法中的参数epoch已经废弃了,在使用时可以直接忽略这个参数。

 
2.1.3 get_last_lr、get_lr和print_lr

get_last_lr()方法比较简单,就是step()方法调用后,记录的最后一次 optimizer各参数组里更新后的学习率信息
get_lr() 方法是抽象方法,定义了更新学习率策略的接口,不同子类继承后会有不同的实现.其返回值是[lr1, lr2, …]结构
print_lr(is_verbose, group, lr, epoch=None)): 该方法提供了显示 lr 调整信息的功能

 
2.1.4 state_dict 和 load_state_dict

这两个方法和Optimizer里的方法功能是一样的,就是为了保存和重新加载状态信息,需要注意的是,这里不会重复记录self.optimizer属性的状态信息,因为 Optimizer 有自己实现的对应方法。

state_dict(): 以字典 dict 形式返回当前实例除 self.optimizer 之外的其他所有属性信息
load_state_dict(state_dict): 重新载入之前保存的状态信息

 

参考:
https://zhuanlan.zhihu.com/p/346205754?utm_medium=social&utm_oi=73844937195520&utm_id=0
https://zhuanlan.zhihu.com/p/539642125

首页 |杏福介绍 |杏福展示 |杏福新闻 |杏福注册 |杏福登录 |杏福平台 |杏福APP下载 |杏福代理加盟 |联系我们

13988889999

Copyright © 2012-2018 首页-杏福娱乐-杏福商务站

地址:海南省海口市玉沙路58号电话:0898-88889999手机:13988889999

ICP备案编号:琼ICP备88889999号

微信扫一扫

微信扫一扫

>

平台注册入口