3.8 Pytorch优化器()
优化器是根据网络反向传播的梯度信息来更新网络的参数,以起到降低loss函数计算值,使得模型输出更加接近真实标签。
3.9.1 Pytorch提供的优化器
-
torch.optim.ASGD(params, lr=0.01, lambd=0.0001, alpha=0.75, t0=1000000.0, weight_decay=0)
功能:实现平均随机梯度下降算法。
参数:
-
- params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
- lr (
float
, 可选) – 学习率(默认:1e-2) - lambd (
float
, 可选) – 衰减项(默认:1e-4) - alpha (
float
, 可选) – eta更新的指数(默认:0.75) - t0 (
float
, 可选) – 指明在哪一次开始平均化(默认:1e6) - weight_decay (
float
, 可选) – 权重衰减(L2惩罚)(默认: 0) -- 预防过拟合(沐神)
- torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0)
功能:实现Adagrad算法,Adagrad适用于数据稀疏或者分布不平衡的数据集
参数:
-
- params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
- lr (
float
, 可选) – 学习率(默认: 1e-2) - lr_decay (
float
, 可选) – 学习率衰减(默认: 0) - weight_decay (
float
, 可选) – 权重衰减(L2惩罚)(默认: 0)
优点:它可以自动调节学习率,不需要人为调节
缺点:仍依赖于人工设置一个全局学习率,随着迭代次数增多,学习率会越来越小,最终会趋近于0
-
torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e-06, weight_decay=0)
功能:实现Adadelta算法,是Adagard的改进版,对学习率进行自适应约束,但是进行了计算上的简化,加速效果不错,训练速度快
参数:
-
- params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
- rho (
float
, 可选) – 用于计算平方梯度的运行平均值的系数(默认:0.9) - eps (
float
, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-6) - lr (
float
, 可选) – 在delta被应用到参数更新之前对它缩放的系数(默认:1.0) - weight_decay (
float
, 可选) – 权重衰减(L2惩罚)(默认: 0)
优点:避免在训练后期,学习率过小;初期和中期,加速效果不错,训练速度快
缺点:还是需要自己手动指定初始学习率,初始梯度很大的话,会导致整个训练过程的学习率一直很小,在模型训练的后期,模型会反复地在局部最小值附近抖动,从而导致学习时间变长
- torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)
功能:实现Adam算法。
原理:将Momentum算法和RMSProp算法结合起来使用的一种算法,既用动量来累积梯度,又使得收敛速度更快同时使得波动的幅度更小,并进行了偏差修正
参数:
-
- params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
- lr (
float
, 可选) – 学习率(默认:1e-3) - betas (Tuple[
float
,float
], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数(默认:0.9,0.999) - eps (
float
, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8) - weight_decay (
float
, 可选) – 权重衰减(L2惩罚)(默认: 0)
优点:
1、对目标函数没有平稳要求,即loss function可以随着时间变化
2、参数的更新不受梯度的伸缩变换影响
3、更新步长和梯度大小无关,只和alpha、beta_1、beta_2有关系。并且由它们决定步长的理论上限
4、更新的步长能够被限制在大致的范围内(初始学习率)
5、能较好的处理噪音样本,能天然地实现步长退火过程(自动调整学习率)
6、很适合应用于大规模的数据及参数的场景、不稳定目标函数、梯度稀疏或梯度存在很大噪声的问题
- torch.optim.AdamW(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0.01, amsgrad=False, *, maximize=False, foreach=None, capturable=False)
功能:Adam的进化版,是目前训练神经网络最快的方式
参数:
-
参数(可迭代) – 可迭代参数以优化或指示定义参数组
-
lr(浮点数,可选)– 学习速率(默认值:1e-3)
-
betas(元组[浮点数,浮点数],可选)–用于计算梯度及其平方的运行平均值的系数(默认值:(0.9,0.999))
-
eps(浮点数,可选)– 添加到分母以提高数值稳定性的术语(默认值:1e-8)
-
weight_decay(浮点数,可选)– 权重衰减系数(默认值:1e-2)
-
amsgrad(布尔值,可选)–是否使用此算法的AMSGrad变体(默认:False)
-
最大化(布尔值,可选)–根据目标最大化参数,而不是最小化(默认值:False)
-
foreach(布尔值,可选)– 是否使用优化器的 foreach 实现(默认值:无)
-
可捕获(布尔值,可选)– 此实例在 CUDA 图中捕获是否安全。传递 True 可能会损害未绘制的性能,因此,如果您不打算以图形捕获此实例,请将其保留为 False(默认值:False)
优点:比Adam收敛得更快
缺点:只有fastai使用,缺乏广泛的框架,而且也具有很大的争议性
- torch.optim.Adamax(params, lr=0.002, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)
功能:实现Adamax算法,Adam的改进版,对Adam增加了一个学习率上限的概念,是Adam的一种基于无穷范数的变种。
参数:
-
- params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
- lr (
float
, 可选) – 学习率(默认:2e-3) - betas (Tuple[
float
,float
], 可选) – 用于计算梯度以及梯度平方的运行平均值的系数 - eps (
float
, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8) - weight_decay (
float
, 可选) – 权重衰减(L2惩罚)(默认: 0)
优点:对学习率的上限提供了一个更简单的范围
- torch.optim.SparseAdam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08)
功能:实现适用于稀疏张量的 Adam 算法的“阉割版”。
参数:
-
- 参数(可迭代) – 可迭代参数以优化或指示定义参数组
- lr(浮点数,可选)– 学习速率(默认值:1e-3)
- betas(元组[浮点数,浮点数],可选)–用于计算梯度及其平方的运行平均值的系数(默认值:(0.9,0.999))
- eps(浮点数,可选)– 添加到分母以提高数值稳定性的术语(默认值:1e-8)
优点:相当于Adam的稀疏张量专用版本
- torch.optim.LBFGS(params, lr=1, max_iter=20, max_eval=None, tolerance_grad=1e-05, tolerance_change=1e-09, history_size=100, line_search_fn=None)
功能:实现L-BFGS算法。是一种在牛顿法基础上提出的一种求解函数根的算法,简单来说,L-BFGS和梯度下降、SGD干的同样的事情,但大多数情况下收敛速度更快
L-BFGS是对BFGS的改进,特点就是节省内存。是解无约束非线性规划问题最常用的方法
参数:
-
- lr (
float
) – 学习率(默认:1) - max_iter (
int
) – 每一步优化的最大迭代次数(默认:20)) - max_eval (
int
) – 每一步优化的最大函数评价次数(默认:max * 1.25) - tolerance_grad (
float
) – 一阶最优的终止容忍度(默认:1e-5) - tolerance_change (
float
) – 在函数值/参数变化量上的终止容忍度(默认:1e-9) - history_size (
int
) – 更新历史的大小(默认:100)
- lr (
优点:收敛速度快、内存开销少,是解无约束非线性规划问题最常用的方法
缺点:使用条件严苛
- torch.optim.Rprop(params, lr=0.01, etas=(0.5, 1.2), step_sizes=(1e-06, 50))
原理:
1、首先为各权重变化赋一个初始值,设定权重变化加速因子与减速因子。
2、在网络前馈迭代中当连续误差梯度符号不变时,采用加速策略,加快训练速度;当连续误差梯度符号变化时,采用减速策略,以期稳定收敛。
3、网络结合当前误差梯度符号与变化步长实现BP,同时,为了避免网络学习发生振荡或下溢,算法要求设定权重变化的上下限
功能:实现弹性反向传播算法。
参数:
-
- params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
- lr (
float
, 可选) – 学习率(默认:1e-2) - etas (Tuple[
float
,float
], 可选) – 一对(etaminus,etaplis), 它们分别是乘法的增加和减小的因子(默认:0.5,1.2) - step_sizes (Tuple[
float
,float
], 可选) – 允许的一对最小和最大的步长(默认:1e-6,50)
缺点:优化方法适用于full-batch,不适用于mini-batch,因此基本上没什么用
- torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)
功能:实现RMSprop算法。RProp的改进版,也是Adagard的改进版
思想:梯度震动较大的项,在下降时,减小其下降速度;对于震动幅度小的项,在下降时,加速其下降速度
参数:
-
- params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
- lr (
float
, 可选) – 学习率(默认:1e-2) - momentum (
float
, 可选) – 动量因子(默认:0) - alpha (
float
, 可选) – 平滑常数(默认:0.99) - eps (
float
, 可选) – 为了增加数值计算的稳定性而加到分母里的项(默认:1e-8) - centered (
bool
, 可选) – 如果为True,计算中心化的RMSProp,并且用它的方差预测值对梯度进行归一化 - weight_decay (
float
, 可选) – 权重衰减(L2惩罚)(默认: 0)
优点:可缓解Adagrad学习率下降较快的问题,并且引入均方根(分母),可以减少摆动,适合处理非平稳目标,对于RNN效果很好
缺点:依然依赖于全局学习率
- torch.optim.SGD(params, lr=, momentum=0, dampening=0, weight_decay=0, nesterov=False)
功能:实现随机梯度下降算法(momentum可选)。
参数:
-
- params (iterable) – 待优化参数的iterable或者是定义了参数组的dict
- lr (
float
) – 学习率 - momentum (
float
, 可选) – 动量因子(默认:0) - weight_decay (
float
, 可选) – 权重衰减(L2惩罚)(默认:0) - dampening (
float
, 可选) – 动量的抑制因子(默认:0) - nesterov (
bool
, 可选) – 使用Nesterov动量(默认:False)
优点:①使用mini-batch的时候,可以收敛得很快
缺点:①在随机选择梯度的同时会引入噪声,使得权值更新的方向不一定正确
②不能解决局部最优解的问题
若使用动量( momentum不为0可加快收敛速度,有一定摆脱局部最优的能力,一定程度上缓解了没有动量的时候的问题)
上述优化算法均继承于Optimizer:
class Optimizer(object): def __init__(self, params, defaults): self.defaults = defaults self.state = defaultdict(dict) self.param_groups = []
Optimizer
有三个属性:
defaults
:存储的是优化器的超参数
{'lr': 0.1, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False}
state
:参数的缓存
defaultdict(<class 'dict'>, {tensor([[ 0.3864, -0.0131], [-0.1911, -0.4511]], requires_grad=True): {'momentum_buffer': tensor([[0.0052, 0.0052], [0.0052, 0.0052]])}})
param_groups
:管理的参数组,是一个list,其中每个元素是一个字典,顺序是params,lr,momentum,dampening,weight_decay,nesterov
[{'params': [tensor([[-0.1022, -1.6890],[-1.5116, -1.7846]], requires_grad=True)], 'lr': 1, 'momentum': 0, 'dampening': 0, 'weight_decay': 0, 'nesterov': False}]
Optimizer
其他方法:
-
zero_grad()
:清空所管理参数的梯度,PyTorch的特性是张量的梯度不自动清零,因此每次反向传播后都需要清空梯度。 step()
:执行一步梯度更新,参数更新
-
add_param_group()
:添加参数组
-
load_state_dict()
:加载状态参数字典,可以用来进行模型的断点续训练,继续上次的参数进行训练
-
state_dict()
:获取优化器当前状态信息字典
3.9.2 实际操作
import os import torch # 设置权重,服从正态分布 --> 2 x 2 weight = torch.randn((2, 2), requires_grad=True) # 设置梯度为全1矩阵 --> 2 x 2 weight.grad=torch.ones((2, 2)) # 输出现有的weight和data print("The data of weight before step:\n{}".format(weight.data)) print("The grad of weight before step:\n{}".format(weight.grad)) # 实例化优化器 optimizer = torch.optim.SGD([weight], lr=0.1, momentum=0.9) # 进行一步梯度更新 optimizer.step() # 查看进行一步后的值,梯度 print("The data of weight after step:\n{}".format(weight.data)) print("The grad of weight after step:\n{}".format(weight.grad)) # 梯度清零 optimizer.zero_grad() # 检验权重是否为0 print("The grad of weight after optimizer.zero_grad():\n{}".format(weight.grad)) # 输出参数 print("optimizer.params_group is \n{}".format(optimizer.param_groups)) # 查看参数位置,optimizer和weight的位置一样,我觉得这里可以参考Python是基于值管理 print("weight in optimizer:{}\nweight in weight:{}\n".format(id(optimizer.param_groups[0]['params'][0]), id(weight)))
# 添加参数:weight2 weight2 = torch.randn((3, 3), requires_grad=True) optimizer.add_param_group({"params": weight2, 'lr': 0.0001, 'nesterov': True})# 添加参数组 # 查看现有的参数 print("optimizer.param_groups is\n{}".format(optimizer.param_groups)) # 查看当前状态信息 opt_state_dict = optimizer.state_dict() print("state_dict before step:\n", opt_state_dict) # 进行5次step操作 for _ in range(50): optimizer.step() # 输出现有状态信息 print("state_dict after step:\n", optimizer.state_dict()) # 保存参数信息 torch.save(optimizer.state_dict(),os.path.join(r"SavePath", "optimizer_state_dict.pkl")) print("----------done-----------") # 加载参数信息 state_dict = torch.load(r"SavePath + \optimizer_state_dict.pkl") # 需要修改为你自己的路径
optimizer.load_state_dict(state_dict)
print("load state_dict successfully\n{}".format(state_dict))
# 输出最后属性信息 print("\n{}".format(optimizer.defaults)) print("\n{}".format(optimizer.state)) print("\n{}".format(optimizer.param_groups))
注:
1. 每个优化器都是一个类,我们一定要进行实例化才能使用:
class Net(nn.Moduel): ... net = Net() optim = torch.optim.SGD(net.parameters(), lr=lr) optim.step()
2.optimizer在一个神经网络的epoch中需要实现下面两个步骤:
-
-
梯度置零
-
梯度更新
-
optimizer = torch.optim.SGD(net.parameters(), lr = 1e-3) for epoch in range(epochs): ... optimizer.zero_grad() # 梯度清零 loss = ... # 计算loss loss.backward() # loss反向传播 optimizer.step() # 梯度更新
3.给网络不同的层赋予不同的优化器参数。
from torch import optim from torchvision.models import resnet18 net = resnet18() optimizer = optim.SGD([ {'params':net.fc.parameters()},#fc的lr使用默认的1e-5 {'params':net.layer4[0].conv1.parameters(),'lr':1e-2}],lr=1e-5) # 可以使用param_groups查看属性标签:weight,float,默认,PyTorch,lr,模块,1e,参数,组成 From: https://www.cnblogs.com/5466a/p/16611186.html