1

深度学习(十三)——损失函数与反向传播 - 码头牛牛

 1 year ago
source link: https://www.cnblogs.com/zoubilin/p/17655184.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一、损失函数:Loss Function#

官网文档:torch.nn — PyTorch 2.0 documentation

1. Loss Function的作用#

  • 每次训练神经网络的时候都会有一个目标,也会有一个输出。目标和输出之间的误差,就是用LossFunction来衡量的。所以,误差Loss是越小越好的。

  • 此外,我们可以根据误差Loss,指导输出output接近目标target。即我们可以以Loss为依据,不断训练神经网络,优化神经网络中各个模块,从而优化output。

LossFunction的作用:

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

(2)为我们更新输出提供一定的依据,这个提供依据的过程也叫反向传播

2. Loss Function中的函数介绍#

(1)nn.L1Loss#

计算MAE (mean absolute error),即假设输入为xi,目标为yi,特征数量为n。在默认情况下,nn.L1Loss通过下面公式计算误差:

∑i=1n|xi−yi|n
class torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')

参数说明:

  • reduction:默认为 ‘mean’ ,可选meansum

    • reduction='mean'时,计算误差采用公式:

      ∑i=1n|xi−yi|n
    • reduction='sum'时,计算误差采用公式:

      ∑i=1n|xi−yi|
  • 需要注意的是,计算的数据必须为浮点数

代码栗子:

import torch
from torch.nn import L1Loss

input=torch.tensor([1,2,3],dtype=torch.float32)
target=torch.tensor([1,2,5],dtype=torch.float32)

input=torch.reshape(input,(1,1,1,3))
target=torch.reshape(target,(1,1,1,3))

loss1=L1Loss()  #reduction='mean'
loss2=L1Loss(reduction='sum')  #reduction='mean'
result1=loss1(input,target)
result2=loss2(input,target)

print(result1,result2)

(2)nn.MSELoss#

计算MSE (mean squared error),即假设输入为xi,目标为yi,特征数量为n。在默认情况下,nn.MSELoss通过下面公式计算误差:

∑i=1n(xi−yi)2n
class torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')

参数说明:

  • reduction:默认为 ‘mean’ ,可选meansum

    • reduction='mean'时,计算误差采用公式:

      ∑i=1n(xi−yi)2n
    • reduction='sum'时,计算误差采用公式:

      ∑i=1n(xi−yi)2

代码栗子:

import torch
from torch.nn import L1Loss,MSELoss

input=torch.tensor([1,2,3],dtype=torch.float32)
target=torch.tensor([1,2,5],dtype=torch.float32)

input=torch.reshape(input,(1,1,1,3))
target=torch.reshape(target,(1,1,1,3))

loss_mse1=MSELoss()  #reduction='mean'
loss_mse2=MSELoss(reduction='sum')  #reduction='mean'
result_mse1=loss_mse1(input,target)
result_mse2=loss_mse2(input,target)

print(result_mse1,result_mse2)

(3)nn.CrossEntropyLoss(交叉熵)#

当训练一个分类问题的时候,假设这个分类问题有C个类别,那么有:

loss(x,class)=−log(exp(x[class])∑jexp(x[j]))=−x[class]+log(∑jexp(x[j])

*注意:其中的log在数学中表示的是ln,即以10为底的对数函数

举个栗子:

  • 我们对包含了人、狗、猫的图片进行分类,其标签的索引分别为0、1、2。这时候将一张的图片输入神经网络,即目标(target)为1(对应标签索引)。输出结果为[0.1,0.2,0.3],该列表中的数字分别代表分类标签对应的概率。

  • 根据上述分类结果,图片为的概率更大,即0.3。对于该分类的LossFunction,我们可以通过交叉熵去计算,即:

    ;;x=[0.1,0.2,0.3];x[class]=x[1]=0.2
    loss(x,class)=−0.2+log[exp(0.1)+exp(0.2)+exp(0.3)]

那么如何验证这个公式的合理性呢?根据上面的栗子,分类结果越准确,Loss应该越小。这条公式由两个部分组成:

  • log(∑jexp(x[j]):主要作用是控制或限制预测结果的概率分布。比如说,预测出来的人、狗、猫的概率均为0.9,每个结果概率都很高,这显然是不合理的。此时log(∑jexp(x[j])的值会变大,误差loss(x,class)也会随之变大。同时该指标也可以作为分类器性能评判标准。

  • −x[class]:在已知图片类别的情况下,预测出来对应该类别的概率x[class]越高,其预测结果误差越小。

参数说明:

  • Input: (N,C),其中N代表batch_size,C代表分类的数量(或者叫标签数量),即数据要分成几类(或有几个标签)。

  • Target: (N),对于每个数据:0≤target[i]≤C−1

代码栗子:

  • 仍然以上面图片分类栗子的结果为例,编写程序
import torch
from torch.nn import L1Loss,MSELoss,CrossEntropyLoss

x=torch.tensor([0.1,0.2,0.3])
y=torch.tensor([1])

x=torch.reshape(x,(1,3))

loss_cross=CrossEntropyLoss()
result_cross=loss_cross(x,y)
print(result_cross)
  • 直接用CIFAR 10数据进行实战分类:
import torchvision
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader

dataset=torchvision.datasets.CIFAR10("./dataset",train=False,download=True,transform=torchvision.transforms.ToTensor())
dataloder=DataLoader(dataset,batch_size=1)

class Demo(nn.Module):
    def __init__(self):
        super(Demo,self).__init__()

        self.model1=Sequential(
            Conv2d(3,32,5,padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

    def forward(self,x):
        x=self.model1(x)
        return x

demo=Demo()
loss=nn.CrossEntropyLoss()
for data in dataloder:
    imgs,targets=data
    output=demo(imgs)

    # print(output)
    #[Run] 一共输出10个数据,分别代表该图像为各个标签的概率.具体如下:
    # tensor([[-0.0151, -0.0990, 0.0908, 0.0354, 0.0731, -0.0313, -0.0329, 0.1006,
    #          -0.0953, 0.0449]], grad_fn= < AddmmBackward0 >)

    # print(targets)
    #[Run] 输出该图像真实的标签,具体如下:
    # tensor([7])

    result_loss=loss(output,targets)
    print(result_loss)

二、反向传播#

如何根据LossFunction为更新神经网络数据提供依据?

  • 对于每个卷积核当中的参数,设置一个grad(梯度)。

  • 当我们进行反向传播的时候,对每一个节点的参数都会求出一个对应的梯度。之后我们根据梯度对每一个参数进行优化,最终达到降低Loss的一个目的。比较典型的一个方法——梯度下降法

代码举例:

  • 在上面的代码for循环的最后,加上:
result_loss.backward()
  • 上面就是反向传播的使用方法,它的主要作用是计算一个grad。使用debug功能并删掉上面这行代码,会发现单纯由result_loss=loss(output,targets)计算出来的结果,是没有grad这个参数的。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK