【Pytorch神经网络理论篇】 10 优化器模块+退化学习率

简介: 反向传播的意义在于告诉模型我们需要将权重修改到什么数值可以得到最优解,在开始探索合适权重的过程中,正向传播所生成的结果与实际标签的目标值存在误差,反向传播通过这个误差传递给权重,要求权重进行适当的调整来达到一个合适的输出,最终使得正向传播所预测的结果与标签的目标值的误差达到最小,以上即为反向传播的核心思想

同学你好!本文章于2021年末编写,获得广泛的好评!


故在2022年末对本系列进行填充与更新,欢迎大家订阅最新的专栏,获取基于Pytorch1.10版本的理论代码(2023版)实现,


Pytorch深度学习·理论篇(2023版)目录地址为:


CSDN独家 | 全网首发 | Pytorch深度学习·理论篇(2023版)目录


本专栏将通过系统的深度学习实例,从可解释性的角度对深度学习的原理进行讲解与分析,通过将深度学习知识与Pytorch的高效结合,帮助各位新入门的读者理解深度学习各个模板之间的关系,这些均是在Pytorch上实现的,可以有效的结合当前各位研究生的研究方向,设计人工智能的各个领域,是经过一年时间打磨的精品专栏!

https://v9999.blog.csdn.net/article/details/127587345


欢迎大家订阅(2023版)理论篇


以下为2021版原文~~~~



187c8aa4f5404301be69edd27997ca3e.png


1 优化器模块的作用


1.1 反向传播的核心思想


反向传播的意义在于告诉模型我们需要将权重修改到什么数值可以得到最优解,在开始探索合适权重的过程中,正向传播所生成的结果与实际标签的目标值存在误差,反向传播通过这个误差传递给权重,要求权重进行适当的调整来达到一个合适的输出,最终使得正向传播所预测的结果与标签的目标值的误差达到最小,以上即为反向传播的核心思想


1.2 优化器简介


正向结构与损失函数获取完毕之后,通过优化器模块中优化函数来实现对学习参数的优化,其内部原理主要是梯度下降的方法实现的


1.2.1 优化器与梯度下降


优化器是指通过算法帮助模型在训练过程中更快更好地将参数调整到位,梯度下降主要在损失函数求解出损失值时,它利用梯度下降的方向为前进方向,沿着梯度下降的方向求解最小值,帮助模型找到最小的那个损失值,从而可以反向推算出学习参数的权重,达到优化的目的。


1.3 优化器的类型


1.3.1 批量梯度下降


主要特点:遍历全部数据集计算一次损失函数,根据函数结果更新梯度。


缺点:每次都要遍历全部数据集,计算开销大,计算慢,不支持在线学习。


1.3.2 随机梯度下降


主要特点:每检查一个数据就进行损失函数计算,求梯度更新函数


缺点:计算速度快,收敛性不好,易在最优点附近摆动,两次参数也可能互相抵消,函数震荡剧烈。


1.3.3 小批量梯度下降(折中)


主要特点:将数据集分成若干批,按照批次来实现更新参数,一批中的一组数据共同决定梯度的反向,梯度下降方向不易跑偏,减少随机性,计算量小。


缺点:————————


2 优化器


2.1 常见的优化器


2.1.1 Adam


较为常用,学习率设为3e-4


2.1.2 Ranger


基于RAdam与Lookhead优化器基础上融合而来,兼顾两者的优点,综合性能占优,使得其在各种模型中都具有较高的精度、收敛速度快、使用方便、无需手动调参。


  • RAdam:带有整流器的Adam,能够利用潜在散度动态地打开或者管理自适应学习率。


  • Lookhead:通过迭代更新两组权重的方法,提前观察另一个优化器生成的序列进而选择探索方向。


2.1.3 AMSGrad


在Adam优化器基础上使用二阶冲量,在计算机视觉模型上表现更为出色


2.1.4 Adamax


在带有词向量的自然语言处理模型中表现得更好


2.2 如何选取优化器


2.2.1 手动精确调整模型方面


一般先使用Adam优化器训练模型,在模型无法进一步收敛后,再使用SGD优化器进行手动调节学习率,进一步提升模型性能。


2.2.2 自动精确调整模型方面


一般以Adam优化器为最常用,在收敛速度、模型训练精度都具有较好的效果,对于学习率设置较为宽松,更易于使用。


2.3 优化器的使用


2.3.1 优化器调用方法


优化器在工作时,先算出梯度(根据损失值对某个参数求偏导),再沿着该梯度的方向算出一段距离(由学习率决定),该差值作为变化值更新到原有参数上。


import torch
### Adam()是优化器方法 
#model.parameters():待优化的权重参数,调用模型的parameters(),将返回值传入
#lr:学习率,学习率越大收敛越快!
optimizer = torch.optim.Adam(model.parameters(),lr = lreaning_rate)


2.3.2 查看优化器的参数结构


Pytorch中的每个优化器类中均有param_groups属性,该属性包括每个待优化权重的配置参数,是一个列表对象


list(optimizer.param_group[0].keys())
#返回: ['params','lr','eps','weight_deacy','amsgrad']
#返回: ['优化器要作用的权重参数','学习率','','权重参数的衰减率','是否使用二阶冲量的方式']
### 权重参数的衰减率weight_deacy是指模型在训练过程中使用L2郑泽华的衰减参数,L2正则化是一种防止过拟合的方法


3 退化学习率


3.1 退化学习率简介


退化学习率/学习率衰减,即在刚训练开始时,使用大的学习率加速,训练到一定程度后使用小的学习率来提高精度。


3.1.1 退化学习率/学习率衰减 手动代码实现


import sklearn.datasets
import torch
import numpy as np
import matplotlib.pyplot as plt
from LogicNet_fun import LogicNet, plot_losses, predict, plot_decision_boundary
# 准备数据
np.random.seed(0)  # 设置随机种子
X, Y = sklearn.datasets.make_moons(200, noise=0.2)  # 生成两组半圆形数据
arg = np.squeeze(np.argwhere(Y == 0), axis=1)  # 获取第1组数据索引
arg2 = np.squeeze(np.argwhere(Y == 1), axis=1)  # 获取第2组数据索引
plt.title("moons data")  # 设置可视化标题
plt.scatter(X[arg, 0], X[arg, 1], s=100, c='b', marker='+', label='data1')  # 显示第一组数据索引
plt.scatter(X[arg2, 0], X[arg2, 1], s=40, c='r', marker='o', label='data2')  # 显示第二组数据索引
plt.legend()  # 显示图例
plt.show()
# 搭建网络模型
model = LogicNet(inputdim=2,hiddendim=3,outputdim=2) #实例化模型 输入数据的维度、隐藏节点的数量、模型最终结果的分类数
optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定义优化器 在反向传播时使用
# 训练模型
xt = torch.from_numpy(X).type(torch.FloatTensor) #将数据转化为张量形式
yt = torch.from_numpy(Y).type(torch.LongTensor)
epochs = 1000 #训练次数
losses = [] # 损失值列表:用来接受每一步的损失值
lr_list = [] # 学习率列表:用来接受每一步的学习率
for i in range(epochs):
    loss = model.getloss(xt,yt)
    losses.append(loss.item()) # 保存中间状态的损失值
    optimizer.zero_grad() # 清空之前的梯度
    loss.backward() # 反向传播损失值
    optimizer.step() # 更新参数
    if i % 50 == 0: # 每五十步将学习率 lr X 0.99
        for p in optimizer.param_groups:
            p['lr'] = p['lr'] * 0.99
    lr_list.append(optimizer.state_dict()['param_groups'][0]['lr'])
# 学习率可视化
plt.plot(range(epochs),lr_list,color='r')
plt.show()


a12190c63dc24c92b281ea52e8b1cc51.png


3.2 使用lr_scheduler接口实现退化学习率


在Ptorch的optim模块中,将退化学习率的多种实现方法封装到lr_scheduler接口中


3.2.1 使用lr_scheduler接口实现退化学习率 代码实现


import sklearn.datasets
import torch
import numpy as np
import matplotlib.pyplot as plt
from LogicNet_fun import LogicNet, plot_losses, predict, plot_decision_boundary
# 准备数据
np.random.seed(0)  # 设置随机种子
X, Y = sklearn.datasets.make_moons(200, noise=0.2)  # 生成两组半圆形数据
arg = np.squeeze(np.argwhere(Y == 0), axis=1)  # 获取第1组数据索引
arg2 = np.squeeze(np.argwhere(Y == 1), axis=1)  # 获取第2组数据索引
plt.title("moons data")  # 设置可视化标题
plt.scatter(X[arg, 0], X[arg, 1], s=100, c='b', marker='+', label='data1')  # 显示第一组数据索引
plt.scatter(X[arg2, 0], X[arg2, 1], s=40, c='r', marker='o', label='data2')  # 显示第二组数据索引
plt.legend()  # 显示图例
plt.show()
# 搭建网络模型
model = LogicNet(inputdim=2,hiddendim=3,outputdim=2) #实例化模型 输入数据的维度、隐藏节点的数量、模型最终结果的分类数
optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定义优化器 在反向传播时使用
# 训练模型
xt = torch.from_numpy(X).type(torch.FloatTensor) #将数据转化为张量形式
yt = torch.from_numpy(Y).type(torch.LongTensor)
epochs = 1000 #训练次数
losses = [] # 损失值列表:用来接受每一步的损失值
lr_list = [] # 学习率列表:用来接受每一步的学习率
scheduler = torch.optim.lr_scheduler.StepLR(optimizer,step_size=50,gamma=0.99) # 设置退化学习率,每50步乘以0.99
for i in range(epochs):
    loss = model.getloss(xt,yt)
    losses.append(loss.item()) # 保存中间状态的损失值
    optimizer.zero_grad() # 清空之前的梯度
    loss.backward() # 反向传播损失值
    optimizer.step() # 更新参数
    scheduler.step() # 调用退化学习率对象
    lr_list.append(optimizer.state_dict()['param_groups'][0]['lr'])
# 学习率可视化
plt.plot(range(epochs),lr_list,color='r')
plt.show()

69289b4f9c5c49ac99a6c36cc11a41a0.png


3.2.2 lr_scheduler接口中的退化学习率种类


  • 等间隔调整学习率StepLR():每训练指定步数,学习率调整为 lr = lr×gamma (gamma为手动设置的退化率参数)。


#optimizer (Optimizer) – 包装的优化器。
#step_size (int) – 学习率衰减间隔,例如若为 30,则会在 30、 60、 90…个 epoch 时,将学习率调整为 lr * gamma。
#gamma (float) – 学习率衰减的乘积因子。
#last_epoch (int) – 最后一个epoch的指数。这个变量用来指示学习率是否需要调整。当last_epoch 符合设定的间隔时,就会对学习率进行调整。当为-1 时,学习率设置为初始值。
class torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1)
#调整倍数为gamma 倍,调整间隔为step_size。当last_epoch = -1时,将初始lr设置为lr。


  • 多间隔调整学习率MultiStepLR():按照指定的步数来调整学习率。调整方式也是lr= lr x gamma。


  • 指数衰减调整学习率ExponentialLR():每训练一步,学习率呈指数型衰减,即学习率调整为lr=lr ∗ gamma^epoch (step为训练步数)。


class torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=-1)
#根据epoch数和gamma调整学习率,每个epoch都在改变,调整公式:lr∗gamma^epoch。
# 参数:
## optimizer (Optimizer) – 包装的优化器。
## gamma (float) – 学习率衰减的乘积因子。
## last_epoch (int) – 最后一个epoch的指数。这个变量用来指示学习率是否需要调整。当last_epoch 符合设定的间隔时,就会对学习率进行调整。当为-1 时,学习率设置为初始值。


  • 余弦退火函数调整学习率CosineAnnealingLR():余弦退火指的就是按照弦函数的曲线进行衰减,每训练一步,学习率呈余弦函数型衰减。


torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max, eta_min=0, last_epoch=-1)
# 参数:
## T_max(int) – 一次学习率周期的迭代次数,即 T_max 个 epoch 之后重新设置学习率。
## eta_min(float) – 最小学习率,即在一个周期中,学习率最小会下降到 eta_min,默认值为 0。


  • 根据指标调整学习率ReduceLROnPlateau:当某指标(loss或accuracy)在最近几次训练中均没有变化(下降或升高超过给定阈值)时,调整学习率。


  • 自定义调整学习率LambdaLR:将每个参数组的学习速率设置为初始的lr乘以一个给定的函数。


class torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=-1)
#参数:
##optimizer (Optimizer) – 包装的优化器。
##lr_lambda (function or list) – 一个函数来计算一个乘法因子给定一个整数参数的epoch,或列表等功能,为每个组optimizer.param_groups。
##last_epoch (int) – 最后一个epoch的指数。这个变量用来指示学习率是否需要调整。当last_epoch 符合设定的间隔时,就会对学习率进行调整。当为-1 时,学习率设置为初始值。


3.2.3 多种学习率衰减总结


LambdaLR最为灵活,可以根据需求指定任何策略的学习率变化。它在fne-tune(微调模型的一种方法)中特别有用,不但可以为不同层设置不同的学习率,而且可以为不同层设置不同的学习率调整策略。


3.3 使用lr_scheduler接口实现多种退化学习率


MultiStepLR():在论文中使用较多,简单可控。


ReducelROnPlateau():自动化程度高,参数多。


3.3.1 使用lr_scheduler接口实现MultiStepLR


import sklearn.datasets
import torch
import numpy as np
import matplotlib.pyplot as plt
from LogicNet_fun import LogicNet, plot_losses, predict, plot_decision_boundary
# 准备数据
np.random.seed(0)  # 设置随机种子
X, Y = sklearn.datasets.make_moons(200, noise=0.2)  # 生成两组半圆形数据
arg = np.squeeze(np.argwhere(Y == 0), axis=1)  # 获取第1组数据索引
arg2 = np.squeeze(np.argwhere(Y == 1), axis=1)  # 获取第2组数据索引
plt.title("moons data")  # 设置可视化标题
plt.scatter(X[arg, 0], X[arg, 1], s=100, c='b', marker='+', label='data1')  # 显示第一组数据索引
plt.scatter(X[arg2, 0], X[arg2, 1], s=40, c='r', marker='o', label='data2')  # 显示第二组数据索引
plt.legend()  # 显示图例
plt.show()
# 搭建网络模型
model = LogicNet(inputdim=2,hiddendim=3,outputdim=2) #实例化模型 输入数据的维度、隐藏节点的数量、模型最终结果的分类数
optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定义优化器 在反向传播时使用
# 训练模型
xt = torch.from_numpy(X).type(torch.FloatTensor) #将数据转化为张量形式
yt = torch.from_numpy(Y).type(torch.LongTensor)
epochs = 1000 #训练次数
losses = [] # 损失值列表:用来接受每一步的损失值
lr_list = [] # 学习率列表:用来接受每一步的学习率
scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer,milestones=[200,700,900],gamma=0.99) #在100 700 900 次时,调整学习率
for i in range(epochs):
    loss = model.getloss(xt,yt)
    losses.append(loss.item()) # 保存中间状态的损失值
    optimizer.zero_grad() # 清空之前的梯度
    loss.backward() # 反向传播损失值
    optimizer.step() # 更新参数
    scheduler.step() # 调用退化学习率对象
    lr_list.append(optimizer.state_dict()['param_groups'][0]['lr'])
# 学习率可视化
plt.plot(range(epochs),lr_list,color='r')
plt.show()


fb088dd58fe34c618f04854e911f5f71.png


3.3.2 使用lr_scheduler接口实现ReduceLROnPlateau


import sklearn.datasets
import torch
import numpy as np
import matplotlib.pyplot as plt
from LogicNet_fun import LogicNet, plot_losses, predict, plot_decision_boundary
# 准备数据
np.random.seed(0)  # 设置随机种子
X, Y = sklearn.datasets.make_moons(200, noise=0.2)  # 生成两组半圆形数据
arg = np.squeeze(np.argwhere(Y == 0), axis=1)  # 获取第1组数据索引
arg2 = np.squeeze(np.argwhere(Y == 1), axis=1)  # 获取第2组数据索引
plt.title("moons data")  # 设置可视化标题
plt.scatter(X[arg, 0], X[arg, 1], s=100, c='b', marker='+', label='data1')  # 显示第一组数据索引
plt.scatter(X[arg2, 0], X[arg2, 1], s=40, c='r', marker='o', label='data2')  # 显示第二组数据索引
plt.legend()  # 显示图例
plt.show()
# 搭建网络模型
model = LogicNet(inputdim=2,hiddendim=3,outputdim=2) #实例化模型 输入数据的维度、隐藏节点的数量、模型最终结果的分类数
optimizer = torch.optim.Adam(model.parameters(),lr=0.01) # 定义优化器 在反向传播时使用
# 训练模型
xt = torch.from_numpy(X).type(torch.FloatTensor) #将数据转化为张量形式
yt = torch.from_numpy(Y).type(torch.LongTensor)
epochs = 1000 #训练次数
losses = [] # 损失值列表:用来接受每一步的损失值
lr_list = [] # 学习率列表:用来接受每一步的学习率
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(
    optimizer,
    mode='min', # 要监控模型的最大值or最小值
    factor= 0.5, # 退化学习率参数 gamma
    patience=5, # 不再减少/增加的累计次数
    verbose=True, # 触发规则时是否打印信息
    threshold=0.001, # 监控值触发规则的阈值
    threshold_mode='abs', # 计算触发条件的规则
    cooldown=0, # 触发规则后的停止监控步数,避免lr下降过快
    min_lr=0, # 允许的最小退化学习率
    eps=1e-08 # 当退化学习率小于该值时,停止调整
)
for i in range(epochs):
    loss = model.getloss(xt,yt)
    losses.append(loss.item()) # 保存中间状态的损失值
    scheduler.step(loss.item()) # 调用退化学习率对象,需要传入被监控的值,否则代码出错 【ReduceLROnPlateau()特别的地方】
    optimizer.zero_grad() # 清空之前的梯度
    loss.backward() # 反向传播损失值
    optimizer.step() # 更新参数
    lr_list.append(optimizer.state_dict()['param_groups'][0]['lr'])
# 学习率可视化
plt.plot(range(epochs),lr_list,color='r')
plt.show()


93c239c731404787acdc1f9868bf17fd.png


上述代码 参数Threshold_mode有两种取值:


'rel':在参数mode为max时,如果监控值超过best(1+threshold),则触发规则;在参数mode为min时,如果监控值低于best(1 - threshold),则触发规则。【best为训练过程中的历史最好值】


'abs':在参数mode为max时,如果监控值超过best + threshold,则触发规则;在参数mode为min时,如果监控值低于best - threshold,则触发规则。【best为训练过程中的历史最好值】

目录
相关文章
|
2月前
|
机器学习/深度学习 存储 PyTorch
PyTorch自定义学习率调度器实现指南
本文将详细介绍如何通过扩展PyTorch的 ``` LRScheduler ``` 类来实现一个具有预热阶段的余弦衰减调度器。我们将分五个关键步骤来完成这个过程。
63 2
|
3月前
|
机器学习/深度学习 PyTorch 算法框架/工具
PyTorch 中的动态计算图:实现灵活的神经网络架构
【8月更文第27天】PyTorch 是一款流行的深度学习框架,它以其灵活性和易用性而闻名。与 TensorFlow 等其他框架相比,PyTorch 最大的特点之一是支持动态计算图。这意味着开发者可以在运行时定义网络结构,这为构建复杂的模型提供了极大的便利。本文将深入探讨 PyTorch 中动态计算图的工作原理,并通过一些示例代码展示如何利用这一特性来构建灵活的神经网络架构。
217 1
|
2月前
|
机器学习/深度学习 PyTorch 调度
在Pytorch中为不同层设置不同学习率来提升性能,优化深度学习模型
在深度学习中,学习率作为关键超参数对模型收敛速度和性能至关重要。传统方法采用统一学习率,但研究表明为不同层设置差异化学习率能显著提升性能。本文探讨了这一策略的理论基础及PyTorch实现方法,包括模型定义、参数分组、优化器配置及训练流程。通过示例展示了如何为ResNet18设置不同层的学习率,并介绍了渐进式解冻和层适应学习率等高级技巧,帮助研究者更好地优化模型训练。
97 4
在Pytorch中为不同层设置不同学习率来提升性能,优化深度学习模型
|
2月前
|
机器学习/深度学习 算法 调度
AdEMAMix: 一种创新的神经网络优化器
9月发布的一篇论文中,Pagliardini等人提出了AdEMAMix,一种新的优化算法,旨在克服Adam及其变体(如AdamW)在利用长期梯度信息方面的局限性。通过结合两种不同衰减率的指数移动平均(EMA),AdEMAMix能够更有效地利用历史梯度信息。实验结果显示,AdEMAMix在语言建模和视觉任务中均显著优于AdamW,不仅能加速模型收敛,还能提高学习稳定性。尽管引入了额外计算步骤,但开销极小,展示了在大规模神经网络训练中的潜力。论文详细探讨了其核心思想、实验设置及未来研究方向。
60 8
AdEMAMix: 一种创新的神经网络优化器
|
20天前
|
机器学习/深度学习 算法 数据可视化
如果你的PyTorch优化器效果欠佳,试试这4种深度学习中的高级优化技术吧
在深度学习领域,优化器的选择对模型性能至关重要。尽管PyTorch中的标准优化器如SGD、Adam和AdamW被广泛应用,但在某些复杂优化问题中,这些方法未必是最优选择。本文介绍了四种高级优化技术:序列最小二乘规划(SLSQP)、粒子群优化(PSO)、协方差矩阵自适应进化策略(CMA-ES)和模拟退火(SA)。这些方法具备无梯度优化、仅需前向传播及全局优化能力等优点,尤其适合非可微操作和参数数量较少的情况。通过实验对比发现,对于特定问题,非传统优化方法可能比标准梯度下降算法表现更好。文章详细描述了这些优化技术的实现过程及结果分析,并提出了未来的研究方向。
19 1
|
20天前
|
PyTorch 算法框架/工具
Pytorch学习笔记(一):torch.cat()模块的详解
这篇博客文章详细介绍了Pytorch中的torch.cat()函数,包括其定义、使用方法和实际代码示例,用于将两个或多个张量沿着指定维度进行拼接。
38 0
Pytorch学习笔记(一):torch.cat()模块的详解
|
19天前
|
机器学习/深度学习 算法 PyTorch
Pytorch的常用模块和用途说明
肆十二在B站分享PyTorch常用模块及其用途,涵盖核心库torch、神经网络库torch.nn、优化库torch.optim、数据加载工具torch.utils.data、计算机视觉库torchvision等,适合深度学习开发者参考学习。链接:[肆十二-哔哩哔哩](https://space.bilibili.com/161240964)
23 0
|
24天前
|
机器学习/深度学习 PyTorch 算法框架/工具
探索PyTorch:自动微分模块
探索PyTorch:自动微分模块
|
2月前
|
机器学习/深度学习
小土堆-pytorch-神经网络-损失函数与反向传播_笔记
在使用损失函数时,关键在于匹配输入和输出形状。例如,在L1Loss中,输入形状中的N代表批量大小。以下是具体示例:对于相同形状的输入和目标张量,L1Loss默认计算差值并求平均;此外,均方误差(MSE)也是常用损失函数。实战中,损失函数用于计算模型输出与真实标签间的差距,并通过反向传播更新模型参数。
|
3月前
|
机器学习/深度学习 PyTorch 数据处理
PyTorch数据处理:torch.utils.data模块的7个核心函数详解
在机器学习和深度学习项目中,数据处理是至关重要的一环。PyTorch作为一个强大的深度学习框架,提供了多种灵活且高效的数据处理工具
28 1