深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

这篇具有很好参考价值的文章主要介绍了深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

   其实这个笔记起源于一个报错,报错内容也很简单,希望传入一个三维的tensor,但是得到了一个四维。

RuntimeError: only batches of spatial targets supported (3D tensors) but got targets of dimension: 4

  查看代码报错点,是出现在pytorch计算交叉熵损失的代码。其实在自己手写写语义分割的代码之前,我一直以为自己是对交叉熵损失完全了解的。但是实际上还是有一些些认识不足,所以这里打算复习一下,将其重新梳理一下,才算是透彻的理解了,特地记录下来。

1,交叉熵损失的定义理解

  交叉熵是信息论中的一个概念,要想完全理解交叉熵的本质,需要从基础的概念学习。

1.1 信息量

  信息量与事件发生的概率有关,某件事情越不可能发生,我们获取的信息量就越大,越可能发生,我们获取的信息量就越小。

  假设X是一个离散型随机变量,其取值集合为x,概率分布函数 p(x)=Pr(X=x),则定义事件 X=x0的信息量为:

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

   由于是概率,所以P(x0)的取值范围是[0, 1],绘图如下:

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

 

   从图像可知,函数符合我们对信息量的直觉,概率越大,信息量越小。

1.2 熵

  对于某个事件来说,有多种可能性,每一种可能性都有一个概率 p(Xi),这样就可能计算出某一种可能性的信息量。因为我们上面定义了信息量的定义,而熵就是表达所有信息量的期望,即:

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

   而有一类比较特殊的分布问题,就是0-1分布,对于这类问题你,熵的计算方式可以简化为图下算式:

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

 

 1.3 相对熵(KL散度)

  如果我们对同一个随机变量X有两个单独的概率分布 P(x) 和 Q(x)(在机器学习中,P往往是用来表示样本的真实分布,而Q是表示模型预测的分布。),我们可以使用KL散度来衡量这两个分布的差异。计算公式如下:

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

   n 为事件的所有可能性,Dkl的值越小,表示P和Q的分布越接近。

1.4 交叉熵

  对上式变形可以得到:

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

   等式的前一部分是p的熵,后一部分是交叉熵:

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

  在机器学习中,我们需要评估label和predict之间的差距,使用KL散度刚刚好。由于KL散度的前一部分 -H(y)不变,故在优化过程中,只需要关注交叉熵就可以了,所以一般在机器学习中直接用交叉熵做loss,评估模型。因为交叉熵刻画的是两个概率分布的距离,也就是说交叉熵值越小(相对熵的值越小),两个概率分布越接近。

1.5 交叉熵在单标签分类问题的使用

  这里的单标签分类,就是深度学习最基本的分类问题,每个图像只有一个标签,只能是label1或者label2。

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

   上图是一个样本loss的计算方式,n代表n种label,yi表示真实结果, yihat表示预测概率。如果是一个batch,则需要除以m(m为当前batch的样本数)。

1.6 交叉熵在多标签分类问题的使用

  这里的多标签分类是指,每一张图像样本可以有多个类别,多分类标签是n-hot,值得注意的是,这里的pred不再用softmax计算了,采用的是Sigmoid了。将每一个节点的输出归一化到0-1之间。所以pred的值的和也不再是1。比如我们的语义分割,每个像素的label都是独立分布的,相互之间没有任何影响,所以交叉熵在这里是单独对每一个节点进行计算,每一个节点只有两种可能性,所以是一个二项分布。(上面有简化后交叉熵的公式)

  每个样本的loss即为 loss = loss1 + loss2 + ... lossn。

  每一个batch的loss就是:

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

   其中m为当前batch的样本量,n为类别数。

2,Pytorch中CrossEntropy的形式

  语义分割的本质是对像素的分类。因此语义分割也是使用这个损失函数。首先看代码定义:

def cross_entropy(input, target, weight=None, size_average=None, ignore_index=-100,
                  reduce=None, reduction='mean'):
    # type: (Tensor, Tensor, Optional[Tensor], Optional[bool], int, Optional[bool], str) -> Tensor

    if size_average is not None or reduce is not None:
        reduction = _Reduction.legacy_get_string(size_average, reduce)
    return nll_loss(log_softmax(input, 1), target, weight, None, ignore_index, None, reduction)

  从上面代码可知:input和target是Tensor格式,并且先计算log_softmax,再计算nll_loss。(实际上softmax计算+ log计算 + nll_loss 计算== 直接使用CrossEntropyLoss计算)

2.1 通过softmax+log+nll_loss 计算CrossEntropyLoss

  我们直接在语义分割中应用:

  下面softmax函数肯定输出的是网络的输出预测图像,假设维度为(1,2,2,2),从左到右dim依次为0,1,2,3,也就是说类别数所在的维度表示dim=1应在的维度上计算概率。所以dim=1

temp1 = F.softmax(pred_output,dim=1)
print("temp1:",temp1)

  深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

 

 log函数:就是对输入矩阵的每个元素求对数,默认底数为e,也就是In函数

temp3 = torch.log(temp1)
print("temp3:",temp3)

 深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

nll_loss函数:这个函数的目的是把标签图像的元素值,作为索引值,在上面选择相应的值求平均。

target = target.long()
loss1 = F.nll_loss(temp3,target)
print('loss1: ', loss1)

  

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

 2.2   直接使用交叉熵损失计算

   直接使用交叉熵损失计算:

loss2 = nn.CrossEntropyLoss()
result2 = loss2(pred_output, target)
print('result2: ', result2)

  对比结果可以发现  通过  对CrossEntropyLoss函数分解并分步计算的结果,与直接使用CrossEntropyLoss函数计算的结果一致。

2.3  pytorch 和 tensorflow在损失函数计算方面的差异

  pytorch和tensorflow在损失函数计算方面有细微的差别的,为啥对比pytorch和tensorflow的差异,因为一个更符合人的想法,一个稍微有一些阉割的问题,导致我们按照常理写代码,会遇到问题。

tensorflow的模型训练:

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

 

   one-hot编码:

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习

 

   通过这两步骤,我们就可以计算标签和模型产生的预测结果之间的损失了。而在pytorch中,我们不需要对标签进行one-hot编码,且需要将通道这一维度压缩。即标签中的值为对应的类别数

  具体在代码中,如果是一个类别,就特别要注意(因为我就是没注意,所以就有开头的错):

masks_pred = model(images)
if model.n_classes == 1:
    loss = criterion(masks_pred.squeeze(1), true_masks.float())
    loss += dice_loss(F.sigmoid(masks_pred.squeeze(1)), true_masks.float(), multiclass=False)
else:
    loss = criterion(masks_pred, true_masks)
    loss += dice_loss(
        F.softmax(masks_pred, dim=1).float(),
        F.one_hot(true_masks, model.n_classes).permute(0, 3, 1, 2).float(),
        multiclass=True
    )

  

3,Pytorch中,nn与nn.functional的相同点和不同点

3.1 相同点

  首先两者的功能相同,nn.xx与nn.functional.xx的实际功能是相同的,只是一个是包装好的类,一个是可以直接调用的函数。

  比如我们这里学习的Crossentropy函数:

  在torch.nn中定义如下:

class CrossEntropyLoss(_WeightedLoss):
    __constants__ = ['ignore_index', 'reduction', 'label_smoothing']
    ignore_index: int
    label_smoothing: float

    def __init__(self, weight: Optional[Tensor] = None, size_average=None, ignore_index: int = -100,
                 reduce=None, reduction: str = 'mean', label_smoothing: float = 0.0) -> None:
        super(CrossEntropyLoss, self).__init__(weight, size_average, reduce, reduction)
        self.ignore_index = ignore_index
        self.label_smoothing = label_smoothing

    def forward(self, input: Tensor, target: Tensor) -> Tensor:
        return F.cross_entropy(input, target, weight=self.weight,
                               ignore_index=self.ignore_index, reduction=self.reduction,
                               label_smoothing=self.label_smoothing)

  在torch.nn.functional中定义如下:

def cross_entropy(
    input: Tensor,
    target: Tensor,
    weight: Optional[Tensor] = None,
    size_average: Optional[bool] = None,
    ignore_index: int = -100,
    reduce: Optional[bool] = None,
    reduction: str = "mean",
    label_smoothing: float = 0.0,
) -> Tensor:
    if has_torch_function_variadic(input, target, weight):
        return handle_torch_function(
            cross_entropy,
            (input, target, weight),
            input,
            target,
            weight=weight,
            size_average=size_average,
            ignore_index=ignore_index,
            reduce=reduce,
            reduction=reduction,
            label_smoothing=label_smoothing,
        )
    if size_average is not None or reduce is not None:
        reduction = _Reduction.legacy_get_string(size_average, reduce)
    return torch._C._nn.cross_entropy_loss(input, target, weight, _Reduction.get_enum(reduction), ignore_index, label_smoothing)

  可以看到torch.nn下面的CrossEntropyLoss类在forward时调用了nn.functional下的cross_entropy函数,当然最终的计算是通过C++编写的函数计算的。

 3.2  不同点

  不同点1:在使用nn.CrossEntropyLoss()之前,需要先实例化,再输入参数,以函数调用的方式调用实例化的对象并传入输入数据:

import torch.nn as nn

loss = torch.nn.CrossEntropyLoss()
output = loss(x, y)

  使用 F.cross_entropy()直接可以传入参数和输入数据,而且由于F.cross_entropy() 得到的是一个向量也就是对batch中每一个图像都会得到对应的交叉熵,所以计算出之后,会使用一个mean()函数,计算其总的交叉熵,再对其进行优化。

import torch.nn.functional as F

loss = F.cross_entropy(input, target).mean()

  不同点2:而且 nn.xxx 继承于nn.Module,能够很好的与nn.Sequential结合使用,而nn.functional.xxx 无法与nn.Sequential结合使用。举个例子:

layer = nn.Sequential(
            nn.Conv2d(3, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(num_features=64),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2),
            nn.Dropout(0.2)
  )

  不同点3:nn.xxx 不需要自己定义和管理weight;而nn.functional.xxx需要自己定义weight,每次调用的时候都需要手动传入weight,不利于代码复用。其实如果我们只保留了nn.functional下的函数的话,在训练或者使用时,我们就需要手动去维护weight, bias, stride 这些中间量的值;而如果只保留nn下的类的话,其实就牺牲了一部分灵活性,因为做一些简单的计算都需要创建一个类,这也与PyTorch的风格不符。

  比如使用nn.xxx定义一个网络,如下:

import torch
import torch.nn as nn
import torch.nn.functional as F

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

  以一个最简单的五层网络为例。需要维持状态的,主要是两个卷积和三个线性变换,所以在构造Module是,定义了两个Conv2d和三个nn.Linear对象,而在计算时,relu之类不需要保存状态的可以直接使用。

 

参考地址(这个只是个人笔记,不做商业):

https://blog.csdn.net/tsyccnh/article/details/79163834

https://www.zhihu.com/question/66782101

https://blog.csdn.net/weixin_39190382/article/details/114433884)

https://blog.csdn.net/Fcc_bd_stars/article/details/105158215文章来源地址https://www.toymoban.com/news/detail-408568.html

到了这里,关于深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的理解与学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 聊聊关于分类和分割的损失函数:nn.CrossEntropyLoss()

    目录 1. nn.CrossEntropyLoss() 2. 多分类中 nn.CrossEntropyLoss() 的应用 3. 分割中 nn.CrossEntropyLoss() 的应用 3.1 测试文件 3.2 输出可视化 3.3 softmax  3.4 log  3.5 CrossEntropyLoss 分类中,经常用 nn.CrossEntropyLoss() 交叉熵损失函数 y 为真实值 、 y(hat) 为预测值  这种采用了 one-hot 编码的形式,多

    2024年02月03日
    浏览(34)
  • 深度学习:Pytorch常见损失函数Loss简介

    此篇博客主要对深度学习中常用的损失函数进行介绍,并结合Pytorch的函数进行分析,讲解其用法。 L1 Loss计算预测值和真值的平均绝对误差。 L o s s ( y , y ^ ) = ∣ y − y ^ ∣ Loss(y,hat{y}) = |y-hat{y}| L oss ( y , y ^ ​ ) = ∣ y − y ^ ​ ∣ Pytorch函数: 参数: size_average (bool, optional) –

    2024年02月13日
    浏览(43)
  • PyTorch各种损失函数解析:深度学习模型优化的关键(2)

    目录 详解pytorch中各种Loss functions mse_loss 用途 用法 使用技巧 注意事项 参数 数学理论公式 代码演示  margin_ranking_loss 用途 用法 使用技巧 注意事项 参数 数学理论公式  代码演示 multilabel_margin_loss 用途 用法 使用技巧 注意事项 参数 数学理论公式 代码演示 multilabel_soft_margin_

    2024年01月19日
    浏览(67)
  • 【深度学习所有损失函数】在 NumPy、TensorFlow 和 PyTorch 中实现(2/2)

    在本文中,讨论了深度学习中使用的所有常见损失函数,并在NumPy,PyTorch和TensorFlow中实现了它们。         稀疏分类交叉熵损失类似于分类交叉熵损失,但在真实标签作为整数而不是独热编码提供时使用。它通常用作多类分类问题中的损失函数。 稀疏分类交叉熵损失的公

    2024年02月13日
    浏览(38)
  • 【深度学习所有损失函数】在 NumPy、TensorFlow 和 PyTorch 中实现(1/2)

    在本文中,讨论了深度学习中使用的所有常见损失函数,并在NumPy,PyTorch和TensorFlow中实现了它们。 我们本文所谈的代价函数如下所列:

    2024年02月13日
    浏览(47)
  • 机器学习之损失函数

    深度学习中常用的损失函数多种多样,具体选择取决于任务类型和问题的性质。以下是一些常见的深度学习任务和相应的常用损失函数: 分类任务 : 交叉熵损失函数(Cross-Entropy Loss) :用于二分类和多类别分类任务,包括二元交叉熵(Binary Cross-Entropy)和多元交叉熵(Cat

    2024年02月11日
    浏览(34)
  • 机器学习之损失函数(Loss Function)

    损失函数(Loss Function)是机器学习和深度学习中的关键概念,它用于衡量模型的预测与实际目标之间的差异或误差。损失函数的选择对于模型的训练和性能评估至关重要,不同的任务和问题通常需要不同的损失函数。 以下是一些常见的损失函数以及它们在不同任务中的应用

    2024年02月11日
    浏览(37)
  • 人工智能_机器学习065_SVM支持向量机KKT条件_深度理解KKT条件下的损失函数求解过程_公式详细推导_---人工智能工作笔记0105

    之前我们已经说了KKT条件,其实就是用来解决 如何实现对,不等式条件下的,目标函数的求解问题,之前我们说的拉格朗日乘数法,是用来对 等式条件下的目标函数进行求解. KKT条件是这样做的,添加了一个阿尔法平方对吧,这个阿尔法平方肯定是大于0的,那么 可以结合下面的文章去

    2024年02月04日
    浏览(43)
  • PyTorch损失函数(二)

    nn.L1Loss 是一个用于计算输入和目标之间差异的损失函数,它计算输入和目标之间的绝对值差异。 主要参数: reduction :计算模式,可以是 none 、 sum 或 mean 。 none :逐个元素计算损失,返回一个与输入大小相同的张量。 sum :将所有元素的损失求和,返回一个标量值。 mean :

    2024年01月17日
    浏览(39)
  • Pytorch损失函数

    基本用法 criterion = LossCriterion() #构造函数有自己的参数 loss = criterion(x, y) #调用标准时也有参数 1 L1范数损失 L1Loss 计算 output 和 target 之差的绝对值。 参数: 2 均方误差损失 MSELoss 计算 output 和 target 之差的均方差。 参数: 3 交叉熵损失 CrossEntropyLoss 当训练有 C 个类别的分类问

    2023年04月25日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包