【学习笔记】损失函数与反向传播

直观比喻:

因此,损失函数的主要作用:

1.计算实际输出和目标之间的差距

2.为我们更新输出提供一定的依据(反向传播)

常见的几种Loss Functions:

  1. nn.L1Loss

官方文档公式如下: 

 其中,

Shape:

  • Input: (∗)(∗), where ∗∗ means any number of dimensions.

  • Target: (∗)(∗), same shape as the input.

  • Output: scalar. If reduction is 'none', then (∗)(∗), same shape as the input.

 代码示例:

import torch
from torch.nn import L1Loss, MSELoss, CrossEntropyLoss

inputs=torch.tensor([1,2,3],dtype=torch.float32)
targets=torch.tensor([1,2,5],dtype=torch.float32)
#
loss = L1Loss()
result=loss(inputs,targets)

loss1= L1Loss(reduction="sum")
result1=loss1(inputs,targets)

print(result)             #tensor(0.6667) (0+0+2)/3=0.6667
print(result1)            #tensor(2.) 0+0+2

     2.nn.MSELoss(平方差)

官方文档:

Shape:

  • Input: (∗)(∗), where ∗∗ means any number of dimensions.

  • Target: (∗)(∗), same shape as the input.

 代码示例:


import torch
from torch.nn import L1Loss, MSELoss, CrossEntropyLoss

inputs=torch.tensor([1,2,3],dtype=torch.float32)
targets=torch.tensor([1,2,5],dtype=torch.float32)

#均方差
loss_mse=MSELoss()
result=loss_mse(inputs,targets)

print(result) #tensor(1.3333)   MSE=(0*0+0*0+2*2)/3

3.nn.CrossEntropyLoss (交叉熵)

适用于训练一个具有C个类别的分类问题 

计算公式并举例,便于理解: 

 

 示例代码:

import torch
from torch.nn import  CrossEntropyLoss

#交叉熵损失函数
x=torch.tensor([0.1,0.2,0.3])
y=torch.tensor([1])
#input(N,C)or(C)...
x=torch.reshape(x,(1,3))

loss_cross=CrossEntropyLoss()
result=loss_cross(x,y)
print(result)

结果:tensor(1.1019) 

之前博文中有创建了CIFAR10 network structure,下面代码直接调用过来,并下载CIFAR10的测试集(10000张),利用上面所学的交叉熵函数计算实际输出与目标之间的误差,代码如下

import torch
import torchvision
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

datasets=torchvision.datasets.CIFAR10("./datasets",train=False,transform=transforms.ToTensor(),download=True)

dataloader=DataLoader(datasets,batch_size=1)

class Tudui(nn.Module):
    def __init__(self):
        super(Tudui,self).__init__()
        self.model1=Sequential(
            Conv2d(in_channels=3,out_channels=32,kernel_size=5,padding=2),
            MaxPool2d(kernel_size=2),
            Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding=2),
            MaxPool2d(kernel_size=2),
            Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding=2),
            MaxPool2d(kernel_size=2),
            Flatten(),
            Linear(in_features=1024, out_features=64),
            Linear(in_features=64, out_features=10)
        )


    def forward(self,x):
        # x=self.conv1(x)
        #         # x=self.maxpool1(x)
        #         # x=self.conv2(x)
        #         # x=self.maxpool2(x)
        #         # x=self.conv3(x)
        #         # x=self.maxpool3(x)
        #         # x=self.flatten(x)
        #         # x=self.linear1(x)
        #         # x=self.linear2(x)
        x=self.model1(x)  #简化代码
        return x

tudui=Tudui()
loss=nn.CrossEntropyLoss()

for data in dataloader:
    imgs,targets = data
    outputs = tudui(imgs)
    # print(outputs)
    # print(targets)
    """
    tensor([[ 0.0837, -0.0653, -0.0284,  0.1285,  0.0409,  0.0547,  0.1032,  0.1266,
         -0.0809, -0.1192]], grad_fn=<AddmmBackward>)  10个输出,每个数字代表预测该类别的概率
    tensor([3]) 代表真实的target是3
    
    """

    # 求交叉熵
    result_loss = loss(outputs, targets)
    print(result_loss)  # 神经网络输出与真实输出之间的误差
    

误差部分结果如下:

为什么说损失函数能为我们更新输出提供一定的依据 ?

因为它能给我们神经网络中每一个需要调节的参数,对卷积层来说,其中的每一个卷积核中的参数,为每一个卷积核参数设置了一个grad(梯度),当使用反向传输时,每一个节点都有一个梯度,优化的时候根据梯度对参数优化,最终使loss下降,就是所谓的梯度下降法。

  在上面代码下面加上两行代码:

result_loss.backward()  #反向传输,注意是result_loss,不是loss
print("ok")  #为了debug

 在代码result_loss.backward()所在行添加断点,debug一下,找到conv1下梯度,此时还未计算梯度,因为没有执行result_loss.backward()这行代码

点击 按钮,发现grad有计算值了,说明为每一个卷积层参数设置了一个grad(梯度)

 

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`sigprocmask()` 函数是用于修改进程的信号屏蔽字的函数,它可以阻塞或允许特定的信号。下面是关于 `sigprocmask()` 函数的一些学习笔记: 1. `sigprocmask()` 函数的头文件为 `<signal.h>`。 2. `sigprocmask()` 函数的原型为: ``` int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); ``` - `how` 表示如何修改信号屏蔽字,有三个取值:`SIG_BLOCK`、`SIG_UNBLOCK` 和 `SIG_SETMASK`。分别表示阻塞、解除阻塞和设置信号屏蔽字。 - `set` 表示要修改的信号集合。 - `oldset` 表示原来的信号集合。 3. `sigprocmask()` 函数可以修改进程的信号屏蔽字,控制是否允许或阻塞某些信号的处理。 4. 信号屏蔽字是一个二进制位向量,每个位代表一个信号,如果该位为 1,则表示该信号被屏蔽,不会被处理;如果该位为 0,则表示该信号是允许的,可以被处理。 5. `sigprocmask()` 函数可以使用 `sigemptyset()`、`sigfillset()`、`sigaddset()`、`sigdelset()` 等函数来创建和修改信号集合。 6. `sigprocmask()` 函数可以用于防止信号的竞争条件,例如在多线程程序中使用信号处理函数时,可以使用信号屏蔽字来防止多个线程同时处理同一个信号。 7. `sigprocmask()` 函数还可以用于实现临界区保护,即在进入临界区时,屏蔽某些信号,以防止信号处理函数中断临界区代码的执行。 总之,`sigprocmask()` 函数是一个非常重要且常用的函数,可以用于控制信号的处理,保护临界区等。在学习和使用该函数时,需要注意其参数的含义和使用方法,以及信号屏蔽字的概念和使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值