CSDN独家 | 全网首发 | Pytorch深度学习·理论篇(2023版)目录本专栏将通过系统的深度学习实例,从可解释性的角度对深度学习的原理进行讲解与分析,通过将深度学习知识与Pytorch的高效结合,帮助各位新入门的读者理解深度学习各个模板之间的关系,这些均是在Pytorch上实现的,可以有效的结合当前各位研究生的研究方向,设计人工智能的各个领域,是经过一年时间打磨的精品专栏!https://v9999.blog.csdn.net/article/details/127587345欢迎大家订阅(2023版)理论篇
以下为2021版原文~~~~
反向传播的意义在于告诉模型我们需要将权重修改到什么数值可以得到最优解,在开始探索合适权重的过程中,正向传播所生成的结果与实际标签的目标值存在误差,反向传播通过这个误差传递给权重,要求权重进行适当的调整来达到一个合适的输出,最终使得正向传播所预测的结果与标签的目标值的误差达到最小,以上即为反向传播的核心思想
正向结构与损失函数获取完毕之后,通过优化器模块中优化函数来实现对学习参数的优化,其内部原理主要是梯度下降的方法实现的
优化器是指通过算法帮助模型在训练过程中更快更好地将参数调整到位,梯度下降主要在损失函数求解出损失值时,它利用梯度下降的方向为前进方向,沿着梯度下降的方向求解最小值,帮助模型找到最小的那个损失值,从而可以反向推算出学习参数的权重,达到优化的目的。
主要特点:遍历全部数据集计算一次损失函数,根据函数结果更新梯度。
缺点:每次都要遍历全部数据集,计算开销大,计算慢,不支持在线学习。
主要特点:每检查一个数据就进行损失函数计算,求梯度更新函数
缺点:计算速度快,收敛性不好,易在最优点附近摆动,两次参数也可能互相抵消,函数震荡剧烈。
主要特点:将数据集分成若干批,按照批次来实现更新参数,一批中的一组数据共同决定梯度的反向,梯度下降方向不易跑偏,减少随机性,计算量小。
缺点:————————
较为常用,学习率设为3e-4
基于RAdam与Lookhead优化器基础上融合而来,兼顾两者的优点,综合性能占优,使得其在各种模型中都具有较高的精度、收敛速度快、使用方便、无需手动调参。
在Adam优化器基础上使用二阶冲量,在计算机视觉模型上表现更为出色
在带有词向量的自然语言处理模型中表现得更好
一般先使用Adam优化器训练模型,在模型无法进一步收敛后,再使用SGD优化器进行手动调节学习率,进一步提升模型性能。
一般以Adam优化器为最常用,在收敛速度、模型训练精度都具有较好的效果,对于学习率设置较为宽松,更易于使用。
优化器在工作时,先算出梯度(根据损失值对某个参数求偏导),再沿着该梯度的方向算出一段距离(由学习率决定),该差值作为变化值更新到原有参数上。
import torch
### Adam()是优化器方法
#model.parameters():待优化的权重参数,调用模型的parameters(),将返回值传入
#lr:学习率,学习率越大收敛越快!
optimizer = torch.optim.Adam(model.parameters(),lr = lreaning_rate)
Pytorch中的每个优化器类中均有param_groups属性,该属性包括每个待优化权重的配置参数,是一个列表对象
list(optimizer.param_group[0].keys())
#返回: ['params','lr','eps','weight_deacy','amsgrad']
#返回: ['优化器要作用的权重参数','学习率','','权重参数的衰减率','是否使用二阶冲量的方式']
### 权重参数的衰减率weight_deacy是指模型在训练过程中使用L2郑泽华的衰减参数,L2正则化是一种防止过拟合的方法
退化学习率/学习率衰减,即在刚训练开始时,使用大的学习率加速,训练到一定程度后使用小的学习率来提高精度。
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()
在Ptorch的optim模块中,将退化学习率的多种实现方法封装到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()
#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。
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 时,学习率设置为初始值。
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。
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 时,学习率设置为初始值。
LambdaLR最为灵活,可以根据需求指定任何策略的学习率变化。它在fne-tune(微调模型的一种方法)中特别有用,不但可以为不同层设置不同的学习率,而且可以为不同层设置不同的学习率调整策略。
MultiStepLR():在论文中使用较多,简单可控。
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.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()
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()
上述代码 参数Threshold_mode有两种取值:
'rel':在参数mode为max时,如果监控值超过best(1+threshold),则触发规则;在参数mode为min时,如果监控值低于best(1 - threshold),则触发规则。【best为训练过程中的历史最好值】
'abs':在参数mode为max时,如果监控值超过best + threshold,则触发规则;在参数mode为min时,如果监控值低于best - threshold,则触发规则。【best为训练过程中的历史最好值】