PyTorch学习笔记-损失函数与反向传播

news2025/1/19 14:16:16

1. 损失函数

具有深度学习理论基础的同学对损失函数和反向传播一定不陌生,在此不详细展开理论介绍。损失函数是指用于计算标签值和预测值之间差异的函数,在机器学习过程中,有多种损失函数可供选择,典型的有距离向量,绝对值向量等。使用损失函数的流程概括如下:

  1. 计算实际输出和目标之间的差距。
  2. 为我们更新输出提供一定的依据(反向传播)。

损失函数的官方文档:Loss Functions。

(1)nn.L1Loss:平均绝对误差(MAE,Mean Absolute Error),计算方法很简单,取预测值和真实值的绝对误差的平均数即可,公式为: l o s s = ∣ x 1 − t 1 ∣ + ∣ x 2 − t 2 ∣ + ⋯ + ∣ x n − t n ∣ n loss=\frac{|x_1-t_1|+|x_2-t_2|+\dots +|x_n-t_n|}{n} loss=nx1t1+x2t2++xntn

PyTorch1.13中 nn.L1Loss 数据形状规定如下:

在这里插入图片描述

早先的版本需要指定 batch_size 大小,现在不需要了。可以设置参数 reduction,默认为 mean,即取平均值,也可以设置为 sum,顾名思义就是取和。

测试代码如下:

import torch.nn as nn
import torch

input = torch.tensor([1.0, 2.0, 3.0])
target = torch.tensor([4.0, -2.0, 5.0])

loss = nn.L1Loss()
result = loss(input, target)

print(result)  # tensor(3.)

loss = nn.L1Loss(reduction='sum')
result = loss(input, target)

print(result)  # tensor(9.)

(2)nn.MSELoss:均方误差(MSE,Mean Squared Error),即预测值和真实值之间的平方和的平均数,公式为: l o s s = ( x 1 − t 1 ) 2 + ( x 2 − t 2 ) 2 + ⋯ + ( x n − t n ) 2 n loss=\frac{(x_1-t_1)^2+(x_2-t_2)^2+\dots +(x_n-t_n)^2}{n} loss=n(x1t1)2+(x2t2)2++(xntn)2

该损失函数的用法与 nn.L1Loss 相似,代码如下:

import torch.nn as nn
import torch

input = torch.tensor([1.0, 2.0, 3.0])
target = torch.tensor([4.0, -2.0, 5.0])

loss = nn.MSELoss()
result = loss(input, target)

print(result)  # tensor(9.6667)

loss = nn.MSELoss(reduction='sum')
result = loss(input, target)

print(result)  # tensor(29.)

(3)nn.CrossEntropyLoss:交叉熵误差,训练分类 C C C 个类别的模型的时候较常用这个损失函数,一般用在 Softmax 层后面,假设 x x x 为某次三分类预测( C = 3 C=3 C=3)输出的结果: [ 0.1 , 0.7 , 0.2 ] [0.1,0.7,0.2] [0.1,0.7,0.2] t a r g e t = 1 target=1 target=1 为正确解的标签(下标从0开始),则损失函数的计算公式为: l o s s ( x , t a r g e t ) = − w t a r g e t l o g e x p ( x t a r g e t ) Σ i = 0 C − 1 e x p ( x c ) = w t a r g e t ( − x t a r g e t + l o g Σ i = 0 C − 1 e x p ( x i ) ) loss(x, target)=-w_{target}log\frac{exp(x_{target})}{\Sigma _{i=0}^{C-1}exp(x_c)}=w_{target}(-x_{target}+log\Sigma _{i=0}^{C-1}exp(x_i)) loss(x,target)=wtargetlogΣi=0C1exp(xc)exp(xtarget)=wtarget(xtarget+logΣi=0C1exp(xi))

PyTorch1.13中 nn.CrossEntropyLoss 数据形状规定如下:

在这里插入图片描述

测试代码如下:

import torch.nn as nn
import torch

input = torch.tensor([0.1, 0.7, 0.2])
target = torch.tensor(1)

loss = nn.CrossEntropyLoss()
result = loss(input, target)

print(result)  # tensor(0.7679)

input = torch.tensor([0.8, 0.1, 0.1])
result = loss(input, target)

print(result)  # tensor(1.3897)

2. 反向传播

接下来以 CIFAR10 数据集为例,用上一节(PyTorch学习笔记-神经网络模型搭建小实战)搭建的神经网络先设置 batch_size 为1,看一下输出结果:

from torchvision import transforms, datasets
from torch.utils.data import DataLoader
import torch.nn as nn

class CIFAR10_Network(nn.Module):
    def __init__(self):
        super(CIFAR10_Network, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, stride=1, padding=2),  # [32, 32, 32]
            nn.MaxPool2d(kernel_size=2),  # [32, 16, 16]
            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),  # [32, 16, 16]
            nn.MaxPool2d(kernel_size=2),  # [32, 8, 8]
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, stride=1, padding=2),  # [64, 8, 8]
            nn.MaxPool2d(kernel_size=2),  # [64, 4, 4]
            nn.Flatten(),  # [1024]
            nn.Linear(in_features=1024, out_features=64),  # [64]
            nn.Linear(in_features=64, out_features=10) # [10]
        )

    def forward(self, input):
        output = self.model(input)
        return output

network = CIFAR10_Network()

test_set = datasets.CIFAR10('dataset/CIFAR10', train=False, transform=transforms.ToTensor())
data_loader = DataLoader(test_set, batch_size=1)

loss = nn.CrossEntropyLoss()

for step, data in enumerate(data_loader):
    imgs, targets = data
    output = network(imgs)
    output_loss = loss(output, targets)
    print(output)
    print(targets)
    print(output_loss)

# tensor([[ 0.1252, -0.1069, -0.0747,  0.0232,  0.0852,  0.1019,  0.0688, -0.1068,
#           0.0854, -0.0740]], grad_fn=<AddmmBackward0>)

# tensor([3])

# tensor(2.2960, grad_fn=<NllLossBackward0>)

现在我们来尝试解决第二个问题,即损失函数如何为我们更新输出提供一定的依据(反向传播)。

例如对于卷积层来说,其中卷积核中的每个参数就是我们需要调整的,每个参数具有一个属性 grad 表示梯度,反向传播时每一个要更新的参数都会求出对应的梯度,在优化的过程中就可以根据这个梯度对参数进行优化,最终达到降低损失函数值的目的。

PyTorch 中对损失函数计算出的结果使用 backward 函数即可计算出梯度:

from torchvision import transforms, datasets
from torch.utils.data import DataLoader
import torch.nn as nn

class CIFAR10_Network(nn.Module):
    def __init__(self):
        super(CIFAR10_Network, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, stride=1, padding=2),  # [32, 32, 32]
            nn.MaxPool2d(kernel_size=2),  # [32, 16, 16]
            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),  # [32, 16, 16]
            nn.MaxPool2d(kernel_size=2),  # [32, 8, 8]
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, stride=1, padding=2),  # [64, 8, 8]
            nn.MaxPool2d(kernel_size=2),  # [64, 4, 4]
            nn.Flatten(),  # [1024]
            nn.Linear(in_features=1024, out_features=64),  # [64]
            nn.Linear(in_features=64, out_features=10) # [10]
        )

    def forward(self, input):
        output = self.model(input)
        return output

network = CIFAR10_Network()

test_set = datasets.CIFAR10('dataset/CIFAR10', train=False, transform=transforms.ToTensor())
data_loader = DataLoader(test_set, batch_size=1)

loss = nn.CrossEntropyLoss()

for step, data in enumerate(data_loader):
    imgs, targets = data
    output = network(imgs)
    output_loss = loss(output, targets)
    output_loss.backward()  # 反向传播

我们在计算反向传播之前设置断点,然后可以通过一下目录查看到某一层参数的梯度,在反向传播之前为 None:

在这里插入图片描述

执行反向传播的代码后可以看到 grad 处有数值了:

在这里插入图片描述

我们有了各个节点参数的梯度,接下来就可以选用一个合适的优化器,来对这些参数进行优化。

3. 优化器

优化器 torch.optim 的官方文档:TORCH.OPTIM。

优化器主要是在模型训练阶段对模型的可学习参数进行更新,常用优化器有:SGD、RMSprop、Adam等。优化器初始化时传入传入模型的可学习参数,以及其他超参数如 lrmomentum 等,例如:

import torch.optim as optim

optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
optimizer = optim.Adam([var1, var2], lr=0.0001)

在训练过程中先调用 optimizer.zero_grad() 清空梯度,再调用 loss.backward() 反向传播,最后调用 optimizer.step() 更新模型参数,例如:

for step, data in enumerate(data_loader):
    imgs, targets = data
    output = network(imgs)
    output_loss = loss(output, targets)
    optimizer.zero_grad()
    output_loss.backward()
    optimizer.step()

接下来我们来训练20轮神经网络,看看损失函数值的变化:

from torchvision import transforms, datasets
from torch.utils.data import DataLoader
import torch.nn as nn
import torch.optim as optim

class CIFAR10_Network(nn.Module):
    def __init__(self):
        super(CIFAR10_Network, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, stride=1, padding=2),  # [32, 32, 32]
            nn.MaxPool2d(kernel_size=2),  # [32, 16, 16]
            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, stride=1, padding=2),  # [32, 16, 16]
            nn.MaxPool2d(kernel_size=2),  # [32, 8, 8]
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, stride=1, padding=2),  # [64, 8, 8]
            nn.MaxPool2d(kernel_size=2),  # [64, 4, 4]
            nn.Flatten(),  # [1024]
            nn.Linear(in_features=1024, out_features=64),  # [64]
            nn.Linear(in_features=64, out_features=10) # [10]
        )

    def forward(self, input):
        output = self.model(input)
        return output

network = CIFAR10_Network()

test_set = datasets.CIFAR10('dataset/CIFAR10', train=False, transform=transforms.ToTensor())
data_loader = DataLoader(test_set, batch_size=64)

loss = nn.CrossEntropyLoss()
optimizer = optim.SGD(network.parameters(), lr=0.01)

for epoch in range(20):  # 学习20轮
    total_loss = 0.0
    for step, data in enumerate(data_loader):
        imgs, targets = data
        output = network(imgs)
        output_loss = loss(output, targets)
        total_loss += output_loss
        optimizer.zero_grad()
        output_loss.backward()
        optimizer.step()
    print(total_loss)

训练结果如下图所示,可以看到每一轮所有 batch 的损失函数值的总和确实在不断降低了:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/44274.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Oracle系列4】Oracle 数据库的层次结构,常见的GUI连接用具

【Oracle系列4】Oracle 数据库的层次结构 跟mysql不一样&#xff0c;mysql连上后能看到所有库&#xff0c;库下面直接就是表了。 跟pgsql也不一样&#xff0c;pgsql连上后&#xff0c;也是可以看到所有库&#xff0c;库下面是schema&#xff0c;schema下面才是表&#xff08;…

G1D25-蜜汁APEX-RAGA代码运行友友第一次跑模型

一、APEX 英伟达开发的&#xff0c;压缩数据的框架 &#xff08;一&#xff09;安装bug 直接安装 https://blog.csdn.net/weixin_47658790/article/details/115055505 &#xff08;二&#xff09;运行bug 然后运行又出现了bug----------------------- IndexError: tuple …

沉睡者IT - 10个问题说清楚:什么是元宇宙?

欢迎关注沉睡者IT&#xff0c;点上面关注我 ↑ ↑ 人们对于元宇宙的构想十分多元且抽象&#xff0c;这十个问题将抽象的元宇宙具象化&#xff0c;帮助人们更好地理解。 一、什么是元宇宙&#xff1f; 1)元宇宙概念的提出 元宇宙在很长一段时间内仅存在于文学与影视作品中。…

一、spring框架的演变

1.微服务架构的演进过程 1.1 单体架构单机部署 1.运行在tomcat里面&#xff0c;并发量QPS一般在200多个请求左右&#xff0c;同一个jvm进程&#xff0c;直接import就行。 2.不同的功能模块可能只用文件夹区分。 3.缺点&#xff1a;并发量太小&#xff08;如果是电商系…

【pygame游戏】用Python实现一个蔡徐坤大战篮球的小游戏,可还行?【附源码】

Python制作坤坤打篮球小游戏序言准备工作开发环境效果预览开始界面游戏规则结束游戏代码实现序言 话说在前面&#xff0c;我不是小黑子~ 我是超级大黑子&#x1f60f; 表弟大周末的跑来我家&#xff0c;没事干天天骚扰我&#xff0c;搞得我都不能跟小姐姐好好聊天了&#xf…

【813. 最大平均值和的分组】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给定数组 nums 和一个整数 k 。我们将给定的数组 nums 分成 最多 k 个相邻的非空子数组 。 分数 由每个子数组内的平均值的总和构成。 注意我们必须使用 nums 数组中的每一个数进行分组&#xff0c;…

3DMAX森林树木植物插Forest Pack Pro 预设库安装教程

Forest Pack是世界上最流行的3dMax森林树木植物散布插件。它提供了一个完整的解决方案来创建广阔的物体区域&#xff0c;从树木和植物到建筑物、人群、骨料、地面覆盖物、岩石等等。模拟大型场景总是非常困难&#xff0c;但这个插件可以帮助您以较少的难度进行模拟。 Forest P…

最近面试 Java 开发的感受:就以平时项目经验面试,通过估计很难

在上周&#xff0c;我密集面试了若干位 Java 后端的候选人&#xff0c;工作经验在 3 到 5 年间。我的标准其实不复杂&#xff1a;第一能干活&#xff0c;第二 Java 基础要好&#xff0c;第三最好熟悉些分布式框架&#xff0c;我相信其它公司招初级开发时&#xff0c;应该也照着…

CountDownLatch

目录 1 前言 2 常用方法 3 示例 4 解析 4.1 countDown() 4.2 await() 源码 1 前言 countDownLatch&#xff08; 门阀、 计数器&#xff09;是多线程控制的一种工具 &#xff0c;它用来协调各个线程之间的同步。 countDownLatch相当于一个计数器&#xff0c;能够使…

51单片机学习笔记3 C51数据类型及最小系统

51单片机学习笔记3 C51数据类型一、 C51数据类型1. 基本类型2. C51扩充数据类型3. C51运算量&#xff08;1&#xff09;常量&#xff08;2&#xff09;变量&#xff08;3&#xff09;位运算符&#xff08;4&#xff09;逗号运算符4. 数组二、51 最小系统构成1. 晶振电路2. 复位…

EIGRP_协议知识点

EIGRP协议一、汇总1.配置(接口下)2.修改AD值(全局下)二、Stub特性2.1实验配置:三、路由泄露四、控制路由更新工具-Distribute-list(分发列表)一、汇总 EIGRP的自动汇总&#xff1a;EIGRP自动汇总只能汇总本地产生的路由&#xff0c;不能汇总从邻居学习的路由&#xff0c;会自动…

聊聊雪花算法?

随便聊聊 哈喽&#xff0c;大家好&#xff0c;最近换了份工作&#xff0c;虽然后端技术栈是老了点&#xff0c;但是呢&#xff0c;这边的前端技术确是现在市面上最新的那一套技术&#xff1a;Vue3ViteTSXPinaElement-PlusNativeUI。我本人主要是学后端的&#xff0c;确被拉去做…

2022王道OS 1.2 操作系统的发展与分类

2022 王道OS 操作系统的发展与分类 文章目录2022 王道OS 操作系统的发展与分类知识总览OS的发展与分类手工操作阶段批处理阶段--单道批处理系统批处理阶段--多道批处理系统分时操作系统实时操作系统其他几种OS知识回顾与重要考点文章目录2022 王道OS 操作系统的发展与分类知识总…

【Android App】勾勒出三维立方体和球体以及它们的转动图形讲解及实战(附源码和演示视频 超详细)

需要源码或运行有问题请点赞关注收藏后评论区留言~~~ 一、轮廓勾勒 勾勒三维物体轮廓线条的步骤如下&#xff1a; &#xff08;1&#xff09;调用glEnableClientState方法启用顶点开关 &#xff08;2&#xff09;调用glVertexPointer方法指定三维物体的顶点坐标集合 &#…

单体分层应用架构剖析

分层单体架构风格是分层思想在单体架构中的应用&#xff0c;其关注于技术视角的职责分层。同时&#xff0c;基于不同层变化速率的不同&#xff0c;在一定程度上控制变化在系统内的传播&#xff0c;有助于提升系统的稳定性。但这种技术视角而非业务视角的关注点隔离&#xff0c;…

Unity-2D游戏-打击感与敌人AI

前言 最近快搞毕设了&#xff0c;学一些Unity2D游戏开发的知识&#xff0c;发现b站宝藏up主奥飒姆Awesome的两个蛮不错的教程&#xff0c;我想简单记录一下它这个游戏设计的方法。 我不一点点实现了&#xff0c;就是分析一下大致框架&#xff08;方便以后套用&#xff09; 资…

广东电子MES系统在电子厂实施的功能和流程

1、电子行业特点电子行业为典型的离散性加工企业&#xff0c;其管理核心的问题在于SN号的管理和物料追溯&#xff0c;即产品、半成品、关键部件都有SN号&#xff0c;且需要实现物料追溯。2、电子行业MES解决方案针对行业需求&#xff0c;我们提供了如下的解决方案&#xff1a;采…

【Python模块】日期时间

在平时开发工作中&#xff0c;我们经常需要用到日期时间&#xff0c;比如日志记录、日期时间的计算、时间字段的赋值等。Python 提供了 time 模块、datatime 模块及子模块、calendar 模块等内置模块&#xff0c;可实现对日期时间的设置、获取、转换等常见操作。 一、日期时间的…

基于STM32G431嵌入式学习笔记——七、定时器定时

一、题目引入 上述为第13届蓝桥杯省赛节选内容&#xff0c;为了研究定时器的机理并独立书写计时函数&#xff0c;上述内容简化为以下要求&#xff1a; ①按下B4按键&#xff0c;LD1点亮5s后熄灭 ②按下B3按键&#xff0c;LD2以0.1秒为间隔切换亮灭状态 二、基础知识 定时器相…

请问各位程序员,是我的思维方式有错误吗?

你好呀&#xff0c;我是歪歪。 前几天知乎给我推送了一个问题&#xff0c;我点进去一看&#xff0c;好家伙&#xff0c;竟然把我血压都看上来了是怎么回事。 我先把问题复述一遍&#xff0c;聊天记录比较长&#xff0c;但是看的过程中容易冲动&#xff0c;注意控制情绪&#…