当前位置: 首页 > web >正文

PyTorch 中神经网络相关要点(损失函数,学习率)及优化方法总结

笔记

1 神经网络搭建和参数计算

1.1 构建神经网络模型

import torch
import torch.nn as nn  # 线性模型和初始化方法
​
​
# todo:1-创建类继承 nn.module类
class ModelDemo(nn.Module):# todo:2-定义__init__构造方法, 构建神经网络def __init__(self):# todo:2-1 调用父类的__init__方法super().__init__()# todo:2-2 创建隐藏层和输出层  定义属性# in_features: 输入特征数(上一层神经元个数)# out_features: 输出特征数(当前层神经元个数)self.linear1 = nn.Linear(in_features=3, out_features=3)self.linear2 = nn.Linear(in_features=3, out_features=2)self.output = nn.Linear(in_features=2, out_features=2)# todo:2-3 对隐藏层进行参数初始化# self.linear1.weight: 在类的内部调用对象属性nn.init.xavier_normal_(tensor=self.linear1.weight)nn.init.zeros_(tensor=self.linear1.bias)nn.init.kaiming_normal_(tensor=self.linear2.weight, nonlinearity='relu')nn.init.zeros_(tensor=self.linear2.bias)
​# todo:3-定义前向传播方法 forward(方法名固定) 得到预测y值def forward(self, x):  # x->输入样本的特征值# todo:3-1 第一层计算 加权求和值计算  激活值计算x = torch.sigmoid(input=self.linear1(x))# todo:3-2 第二层计算x = torch.relu(input=self.linear2(x))# todo:3-3 输出层计算  假设多分类问题# dim=-1: 按行计算, 一个样本一个样本算x = torch.softmax(input=self.output(x), dim=-1)# 返回预测值return x
​
​
if __name__ == '__main__':# 创建神经网络模型对象my_model = ModelDemo()

1.2 计算和查看模型参数

# 创建模型预测函数
def train():# todo:1-创建神经网络模型对象my_model = ModelDemo()print('my_model->', my_model)# todo:2-构造数据集样本, 随机生成data = torch.randn(size=(5, 3))print('data->', data)print('data.shape->', data.shape)# todo:3-调用神经网络模型对象进行模型训练output = my_model(data)print('output->', output)print('output.shape->', output.shape)# todo:4-计算和查看模型参数print(('====================计算和查看模型参数==================='))# input_size: 样本的特征数# batch_size: 批量训练的样本数# summary(model=my_model, input_size=(3,), batch_size=5)summary(model=my_model, input_size=(5, 3))for name, param in my_model.named_parameters():print('name->', name)print('param->', param)
​
​
if __name__ == '__main__':train()

2 损失函数

2.1 什么是损失函数

  • 衡量模型参数质量的函数(评估模型)

  • 对比模型预测值和真实值差异

  • 指导通过梯度下降法计算梯度, 进行参数更新 loss.backward()

2.2 分类任务损失函数

2.2.1 多分类任务损失函数
  • 适用于多分类问题

  • 计算出损失值后续结合梯度下降法和反向传播算法, 进行梯度更新

  • nn.CrossEntropyLoss()

# 适用于多分类
import torch
import torch.nn as nn
​
​
def dm01():# 手动创建样本的真实y值# y_true = torch.tensor(data=[[0, 1, 0], [1, 0, 0]], dtype=torch.float32)y_true = torch.tensor(data=[1, 2])print('y_true->', y_true.dtype)# 手动创建样本的预测y值 -> 模型预测值y_pred = torch.tensor(data=[[0.1, 0.8, 0.1], [0.7, 0.2, 0.1]], requires_grad=True, dtype=torch.float32)# 创建多分类交叉熵损失对象# reduction:损失值计算的方式, 默认mean 平均损失值criterion = nn.CrossEntropyLoss(reduction='sum')# 调用损失对象计算损失值# 预测y  真实yloss = criterion(y_pred, y_true)print('loss->', loss)
​
​
if __name__ == '__main__':dm01()
2.2.2 二分类任务损失函数
  • 适用于二分类问题

  • nn.BCEloss()

# 适用于二分类
import torch
import torch.nn as nn
​
​
def dm01():# 手动创建样本的真实y值y_true = torch.tensor(data=[0, 1, 0], dtype=torch.float32)print('y_true->', y_true.dtype)# 手动创建样本的预测y值 -> 模型预测值# 0.6901, 0.5459, 0.2469 -> sigmoid函数的激活值y_pred = torch.tensor(data=[0.6901, 0.5459, 0.2469], requires_grad=True, dtype=torch.float32)# 创建多分类交叉熵损失对象# reduction:损失值计算的方式, 默认mean 平均损失值criterion = nn.BCELoss()# 调用损失对象计算损失值# 预测y  真实yloss = criterion(y_pred, y_true)print('loss->', loss)print('loss->', loss.requires_grad)
​
​
if __name__ == '__main__':dm01()

2.3 回归任务损失函数

2.3.1 MAE回归损失函数
  • loss=(|y真实-y预测| + ...)/n

  • 导数为-1或1, 0点位置不可导

# 适用于回归任务
# MAE:导数为-1/1 0点位置不可导,一般取0作为导数
import torch
import torch.nn as nn
​
​
def dm01():# 手动创建样本的真实y值y_true = torch.tensor(data=[1.2, 1.5, 2.0], dtype=torch.float32)print('y_true->', y_true.dtype)# 手动创建样本的预测y值 -> 模型预测值# 0.6901, 0.5459, 0.2469 -> sigmoid函数的激活值y_pred = torch.tensor(data=[1.3, 1.7, 2.0], requires_grad=True, dtype=torch.float32)# 创建回归任务MAE损失对象# reduction:损失值计算的方式, 默认mean 平均损失值criterion = nn.L1Loss()# 调用损失对象计算损失值# 预测y  真实yloss = criterion(y_pred, y_true)print('loss->', loss)print('loss->', loss.requires_grad)
​
​
if __name__ == '__main__':dm01()
2.3.2 MSE损失函数
  • 数据集中有异常(噪声)样本, 影响结果, 误差放大, 容易产生梯度爆炸

  • 任意位置可导, 越接近底部, 导数越小, 符合梯度下降套路, 可以找到最小值

# 适用于回归任务, 如果数据集有异常样本, 放大误差, 有可能导致梯度爆炸
# MSE: 任意位置都可导, 越接近底部, 导数越小
import torch
import torch.nn as nn
​
​
def dm01():# 手动创建样本的真实y值y_true = torch.tensor(data=[1.2, 1.5, 2.0], dtype=torch.float32)print('y_true->', y_true.dtype)# 手动创建样本的预测y值 -> 模型预测值# 0.6901, 0.5459, 0.2469 -> sigmoid函数的激活值y_pred = torch.tensor(data=[1.3, 1.7, 2.0], requires_grad=True, dtype=torch.float32)# 创建回归任务MAE损失对象# reduction:损失值计算的方式, 默认mean 平均损失值criterion = nn.MSELoss()# 调用损失对象计算损失值# 预测y  真实yloss = criterion(y_pred, y_true)print('loss->', loss)print('loss->', loss.requires_grad)
​
​
if __name__ == '__main__':dm01()
2.3.3 Smooth L1损失函数
  • 中和MAE和MSE, w小于-1或w大于1使用MAE, w在[-1,1]范围内使用MSE

  • 不受异常值影响,不容易产生梯度爆炸,在任意位置可导,可以找到最小值

  • nn.SmoothL1()

# 适用于回归任务, 不受异常值影响
# smooth l1: 任意位置都可导, 越接近底部, 导数越小
import torch
import torch.nn as nn
​
​
def dm01():# 手动创建样本的真实y值y_true = torch.tensor(data=[1.2, 1.5, 2.0], dtype=torch.float32)print('y_true->', y_true.dtype)# 手动创建样本的预测y值 -> 模型预测值# 0.6901, 0.5459, 0.2469 -> sigmoid函数的激活值y_pred = torch.tensor(data=[1.3, 1.7, 2.0], requires_grad=True, dtype=torch.float32)# 创建回归任务smoothl1损失对象# reduction:损失值计算的方式, 默认mean 平均损失值criterion = nn.SmoothL1Loss()# 调用损失对象计算损失值# 预测y  真实yloss = criterion(y_pred, y_true)print('loss->', loss)print('loss->', loss.requires_grad)
​
​
if __name__ == '__main__':dm01()

3 神经网络优化方法

3.1 梯度下降算法回顾

  • W = W - lr * grad

  • 梯度下降算法是一种寻找最优网络参数的策略, 计算每次损失值对应的梯度, 进行参数更新

    • BGD, 使用全部样本计算梯度, 计算量大

    • SGD, 使用全部样本中随机一个样本计算梯度, 梯度可能不合理

    • Min-Batch, 使用一批样本计算梯度, 计算量相对小, 梯度更加合理

3.2 反向传播算法(BP算法)

  • 反向传播就是算当前损失值和参数的导数(梯度), 需要借助梯度连乘的方式

  • 结合梯度下降算法更新参数 W1 = W0 - LR * 梯度 -> W0和LR已知, 梯度根据BP算法计算出

3.3 梯度下降优化方法

避免遇到鞍点以及局部最小值情况

3.3.1 指数移动加权平均
  • S100 = 0.1*Y100 + 0.1*0.9*Y99 + 0.1*0.9*0.9*Y98 + ....

  • β值越大, 受当前时刻真实值越小, 一般0.9

3.3.2 动量算法Momentum
  • # 动量法计算梯度实际上计算的是当前时刻的指数移动加权平均梯度值
    import torch
    from torch import optim
    ​
    ​
    def dm01():# todo: 1-初始化权重参数w = torch.tensor([1.0], requires_grad=True, dtype=torch.float32)# 自定义损失函数, 实际工作中调用不同任务的损失函数, 交叉熵损失/MSE损失...loss = ((w ** 2) / 2.0).sum()# todo: 2-创建优化器函数对象 SGD->动量法# momentum: 动量法, 一般0.9或0.99optimizer = optim.SGD([w], lr=0.01, momentum=0.9)# todo: 3-计算梯度值optimizer.zero_grad()loss.sum().backward()# todo: 4-更新权重参数 梯度更新optimizer.step()print('w.grad->', w.grad)# 第二次计算loss = ((w ** 2) / 2.0).sum()optimizer.zero_grad()loss.backward()optimizer.step()print('w.grad->', w.grad)
    ​
    ​
    if __name__ == '__main__':dm01()
3.3.3 AdaGrad
  • 随着训练次数增加调整学习率, 开始学习率大, 后续学习率越来越小

    # adagrad优化方法调整学习率, 随着训练次数增加, 学习率越来越小, 一开始的学习率比较大
    import torch
    from torch import optim
    ​
    ​
    def dm01():# todo: 1-初始化权重参数w = torch.tensor([1.0], requires_grad=True, dtype=torch.float32)loss = ((w ** 2) / 2.0).sum()# todo: 2-创建优化器函数对象 Adagradoptimizer = optim.Adagrad([w], lr=0.01)# todo: 3-计算梯度值optimizer.zero_grad()loss.sum().backward()# todo: 4-更新权重参数 梯度更新optimizer.step()print('w.grad->', w.grad, w)# 第二次计算loss = ((w ** 2) / 2.0).sum()optimizer.zero_grad()loss.backward()optimizer.step()print('w.grad->', w.grad, w)# 第三次计算loss = ((w ** 2) / 2.0).sum()optimizer.zero_grad()loss.backward()optimizer.step()print('w.grad->', w.grad, w)
    ​
    ​
    if __name__ == '__main__':dm01()
3.3.4 RMSProp
  • 对adagrap优化, 使用指数移动加权平均梯度代替累加梯度

    # rmsprop优化方法调整学习率, 对adagrad方法进行优化, 使用指数移动加权平均梯度代替历史累加梯度
    # 避免学习率过快减小, 导致后续模型收敛速度慢
    import torch
    from torch import optim
    ​
    ​
    def dm01():# todo: 1-初始化权重参数w = torch.tensor([1.0], requires_grad=True, dtype=torch.float32)loss = ((w ** 2) / 2.0).sum()# todo: 2-创建优化器函数对象  RMSpropoptimizer = optim.RMSprop([w], lr=0.01, alpha=0.9)# todo: 3-计算梯度值optimizer.zero_grad()loss.sum().backward()# todo: 4-更新权重参数 梯度更新optimizer.step()print('w.grad->', w.grad, w)# 第二次计算loss = ((w ** 2) / 2.0).sum()optimizer.zero_grad()loss.backward()optimizer.step()print('w.grad->', w.grad, w)# 第三次计算loss = ((w ** 2) / 2.0).sum()optimizer.zero_grad()loss.backward()optimizer.step()print('w.grad->', w.grad, w)
    ​
    ​
    if __name__ == '__main__':dm01()
3.3.5 Adam
  • 修正梯度和学习率

    # adam既优化学习率又优化梯度  adam=rmsprop+momentum
    import torch
    from torch import optim
    ​
    ​
    def dm01():# todo: 1-初始化权重参数w = torch.tensor([1.0], requires_grad=True, dtype=torch.float32)loss = ((w ** 2) / 2.0).sum()# todo: 2-创建优化器函数对象# betas: 两个β值, 接收元组类型optimizer = optim.Adam([w], lr=0.01, betas=(0.9, 0.99))# todo: 3-计算梯度值optimizer.zero_grad()loss.sum().backward()# todo: 4-更新权重参数 梯度更新optimizer.step()print('w.grad->', w.grad, w)# 第二次计算loss = ((w ** 2) / 2.0).sum()optimizer.zero_grad()loss.backward()optimizer.step()print('w.grad->', w.grad, w)# 第三次计算loss = ((w ** 2) / 2.0).sum()optimizer.zero_grad()loss.backward()optimizer.step()print('w.grad->', w.grad, w)
    ​
    ​
    if __name__ == '__main__':dm01()

3.3.6 如何选择梯度下降优化方法
  • SGD和momentum适用于简单任务或浅层神经网络模型

  • Adam适用于复杂任务或数据量大

  • AdaGrad和RMSprop适用于文本数据处理 nlp

4 学习率衰减优化方法

4.1 为什么进行学习率优化

  • 根据模型训练次数, 手动调整学习率, 使模型前期收敛速度快, 后期收敛速度慢

4.2 等间隔学习率衰减

# 等间隔: 指定训练次数后修改学习率  lr=lr*gamma
import torch
from torch import optim
import matplotlib.pyplot as plt
​
​
def dm01():# todo: 1-初始化参数# lr epoch iterationlr = 0.1epoch = 200iteration = 10# todo: 2-创建数据集# y_true x wy_true = torch.tensor([0])x = torch.tensor([1.0], dtype=torch.float32)w = torch.tensor([1.0], requires_grad=True, dtype=torch.float32)# todo: 3-创建优化器对象 动量法optimizer = optim.SGD(params=[w], lr=lr, momentum=0.9)# todo: 4-创建等间隔学习率衰减对象# optimizer: 优化器对象# step_size: 间隔, 指定训练次数后修改学习率# gamma: 衰减系数 默认0.1scheduer = optim.lr_scheduler.StepLR(optimizer=optimizer, step_size=50, gamma=0.5)# todo: 5-创建两个列表, 收集训练次数, 收集每次训练lrlr_list, epoch_list = [], []# todo: 6-循环遍历训练次数for i in range(epoch):# todo: 7-获取每次训练的次数和lr保存到列表中# scheduer.get_last_lr(): 获取最后lrlr_list.append(scheduer.get_last_lr())epoch_list.append(i)# todo: 8-循环遍历, batch计算for batch in range(iteration):# 先算预测y值 wx, 计算损失值 (wx-y_true)**2y_pred = w * xloss = (y_pred - y_true) ** 2# 梯度清零optimizer.zero_grad()# 梯度计算loss.backward()# 参数更新optimizer.step()# todo: 9-更新下一次训练的学习率scheduer.step()print('lr_list->', lr_list)
​plt.plot(epoch_list, lr_list)plt.xlabel("Epoch")plt.ylabel("Learning rate")plt.legend()plt.show()
​
​
if __name__ == '__main__':dm01()

4.3 指定间隔学习率衰减

  • 前期模型训练设置比较多次数学习率更大, 中期设置相对少训练次数学习率小一些, 后期设置更少训练次数学习率更小一些

    # 指定间隔: 通过步长列表指定训练次数后修改学习率  lr=lr*gamma
    import torch
    from torch import optim
    import matplotlib.pyplot as plt
    ​
    ​
    def dm01():# todo: 1-初始化参数# lr epoch iterationlr = 0.1epoch = 200iteration = 10# todo: 2-创建数据集# y_true x wy_true = torch.tensor([0])x = torch.tensor([1.0], dtype=torch.float32)w = torch.tensor([1.0], requires_grad=True, dtype=torch.float32)# todo: 3-创建优化器对象 动量法optimizer = optim.SGD(params=[w], lr=lr, momentum=0.9)# todo: 4-创建等间隔学习率衰减对象# optimizer: 优化器对象# milestones: 指定间隔列表, 指定训练次数后修改学习率# gamma: 衰减系数 默认0.1scheduer = optim.lr_scheduler.MultiStepLR(optimizer=optimizer, milestones=[50, 100, 160], gamma=0.5, last_epoch=-1)# todo: 5-创建两个列表, 收集训练次数, 收集每次训练lrlr_list, epoch_list = [], []# todo: 6-循环遍历训练次数for i in range(epoch):# todo: 7-获取每次训练的次数和lr保存到列表中# scheduer.get_last_lr(): 获取最后lrlr_list.append(scheduer.get_last_lr())epoch_list.append(i)# todo: 8-循环遍历, batch计算for batch in range(iteration):# 先算预测y值 wx, 计算损失值 (wx-y_true)**2y_pred = w * xloss = (y_pred - y_true) ** 2# 梯度清零optimizer.zero_grad()# 梯度计算loss.backward()# 参数更新optimizer.step()# todo: 9-更新下一次训练的学习率scheduer.step()print('lr_list->', lr_list)
    ​plt.plot(epoch_list, lr_list)plt.xlabel("Epoch")plt.ylabel("Learning rate")plt.legend()plt.show()
    ​
    ​
    if __name__ == '__main__':dm01()

4.4 按指数学习率衰减

  • 根据指数衰减, lr=$$lr * gamma^{epoch}$$

  • 更符合梯度下降规律, 前期下降快, 中期缓慢, 后期更慢

    # 指数间隔: 前期学习率衰减快, 中期慢, 后期更慢  lr=lr * gamma**epoch
    import torch
    from torch import optim
    import matplotlib.pyplot as plt
    ​
    ​
    def dm01():# todo: 1-初始化参数# lr epoch iterationlr = 0.1epoch = 200iteration = 10# todo: 2-创建数据集# y_true x wy_true = torch.tensor([0])x = torch.tensor([1.0], dtype=torch.float32)w = torch.tensor([1.0], requires_grad=True, dtype=torch.float32)# todo: 3-创建优化器对象 动量法optimizer = optim.SGD(params=[w], lr=lr, momentum=0.9)# todo: 4-创建等间隔学习率衰减对象# optimizer: 优化器对象# gamma: 衰减系数 设置大一些, 初始指数大scheduer = optim.lr_scheduler.ExponentialLR(optimizer=optimizer, gamma=0.9)# todo: 5-创建两个列表, 收集训练次数, 收集每次训练lrlr_list, epoch_list = [], []# todo: 6-循环遍历训练次数for i in range(epoch):# todo: 7-获取每次训练的次数和lr保存到列表中# scheduer.get_last_lr(): 获取最后lrlr_list.append(scheduer.get_last_lr())epoch_list.append(i)# todo: 8-循环遍历, batch计算for batch in range(iteration):# 先算预测y值 wx, 计算损失值 (wx-y_true)**2y_pred = w * xloss = (y_pred - y_true) ** 2# 梯度清零optimizer.zero_grad()# 梯度计算loss.backward()# 参数更新optimizer.step()# todo: 9-更新下一次训练的学习率scheduer.step()print('lr_list->', lr_list)
    ​plt.plot(epoch_list, lr_list)plt.xlabel("Epoch")plt.ylabel("Learning rate")plt.legend()plt.show()
    ​
    ​
    if __name__ == '__main__':dm01()

4.5 如何选择学习率衰减方法

  • 优先选择指数学习率衰减方法

  • 根据经验设置间隔选择指定间隔学习率衰减方法

  • 简单模型选择等间隔学习率衰减方法

http://www.xdnf.cn/news/6148.html

相关文章:

  • 建筑IT数字化突围:建筑设计企业的生存法则重塑
  • java连数据库
  • FFmpeg视频编码的完整操作指南
  • 如何设置FFmpeg实现对高分辨率视频进行转码
  • Tailwind CSS 实战教程:从入门到精通
  • 基于开源AI大模型与S2B2C生态的个人品牌优势挖掘与标签重构研究
  • 数据库系统概论|第七章:数据库设计—课程笔记
  • 使用大语言模型从零构建知识图谱(上)
  • Kubernetes控制平面组件:Kubelet详解(三):CRI 容器运行时接口层
  • 国产 ETL 数据集成厂商推荐—谷云科技 RestCloud
  • 【C++设计模式之Decorator装饰模式】
  • 砷化镓太阳能电池:开启多元领域能源新篇
  • 什么是SparkONYarn模式?
  • 【解析:新能源汽车芯片主要玩家及技术发展】
  • 聊聊JetCache的缓存构建
  • 基于自校准分数的扩散模型在并行磁共振成像中联合进行线圈灵敏度校正和运动校正|文献速递-深度学习医疗AI最新文献
  • SVM在医疗设备故障维修服务决策中的应用:策略、技术与实践
  • NineData 社区版 V4.1.0 正式发布,新增 4 条迁移链路,本地化数据管理能力再升级
  • 不借助 Cursor,如何开发第一款 ios 产品并做到付费榜 Top 2
  • C# 通过脚本实现接口
  • C++:二叉搜索树
  • 【C++】map和set的模拟实现
  • vscode调试c/c++
  • Python笔记:在环境变量中增加了dll加载路径,python提示DLL加载失败
  • HTML:入门
  • Angular 知识框架
  • 【SQL】如何在 SQL 中统计结构化字符串的特征频率
  • 【位运算】常见算法公式使用
  • 360智语:以全栈技术重塑企业级智能体开发新标杆
  • 银行卡真伪验证助力金融合规-银行卡实名认证接口