深度学习之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日
    浏览(24)
  • 深度学习: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日
    浏览(32)
  • PyTorch各种损失函数解析:深度学习模型优化的关键(2)

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

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

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

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

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

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

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

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

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

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

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

    2024年02月04日
    浏览(27)
  • PyTorch内置损失函数汇总 !!

    文章目录 一、损失函数的概念 二、Pytorch内置损失函数 1. nn.CrossEntropyLoss 2. nn.NLLLoss 3. nn.NLLLoss2d 4. nn.BCELoss 5. nn.BCEWithLogitsLoss 6. nn.L1Loss 7. nn.MSELoss 8. nn.SmoothL1Loss 9. nn.PoissonNLLLoss 10. nn.KLDivLoss 11. nn.MarginRankingLoss 12. nn.MultiLabelMarginLoss 13. nn.SoftMarginLoss 14. nn.MultilabelSoftMarginLoss 15. n

    2024年01月25日
    浏览(29)
  • Pytorch损失函数

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

    2023年04月25日
    浏览(26)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包