• Pytorch中CrossEntropyLoss()详解


    一、损失函数 nn.CrossEntropyLoss()

    交叉熵损失函数 nn.CrossEntropyLoss() ,结合了 nn.LogSoftmax() 和 nn.NLLLoss() 两个函数。 它在做分类(具体几类)训练的时候是非常有用的。

    二. 什么是交叉熵

    交叉熵主要是用来判定实际的输出与期望的输出的接近程度。举个例子:在做分类训练的时候,如果一个样本属于第 K 类,那么这个类别所对应的输出节点的输出值应该为1,而其他节点的输出都为0,即 [0,0,1,0,….0,0] ,这个数组也就是样本的 Label,是神经网络最期望的输出结果。我们用交叉熵损失函数来衡量网络的实际输出与正确标签的差异,利用这种差异经过反向传播去更新网络参数。

    交叉熵:它主要刻画的是实际输出(概率)与期望输出(概率)的距离,也就是交叉熵的值越小,两个概率分布就越接近。假设概率分布p为期望输出,概率分布q为实际输出,则交叉熵定义为:

    CE

    那么该公式如何表示,举个例子,假设N=3,期望输出为p = (1,0,0),实际输出q1 = (0.5,0.2,0.3),q2 = (0.8,0.1,0.1),那么:
    CE
    通过上面可以看出,q2与p更为接近,它的交叉熵也更小。

    三. Pytorch中的CrossEntropyLoss()函数

    Pytorch中计算的交叉熵并不是采用
    CE
    这种方式计算得到的,而是交叉熵的另外一种方式计算得到的,如下公式所示,它是交叉熵的另外一种方式。
    CE
    Pytorch中CrossEntropyLoss()函数的主要是将softmax-log-NLLLoss合并到一块得到的结果。

    1. Softmax后的数值都在0~1之间,所以ln之后值域是负无穷到0。
    2. 然后将Softmax之后的结果取log,将乘法改成加法减少计算量,同时保障函数的单调性 。
    3. NLLLoss的结果就是把上面的输出与Label对应的那个值拿出来(下面例子中就是:将log_output\logsoftmax_output中与y_target对应的值拿出来),去掉负号,再求均值。

    举例 :

    import torch
    import torch.nn as nn
    x_input=torch.randn(3,3)#随机生成输入 
    print('x_input:\n',x_input) 
    y_target=torch.tensor([1,2,0])#设置输出具体值 print('y_target\n',y_target)
    
    #计算输入softmax,此时可以看到每一行加到一起结果都是1
    softmax_func=nn.Softmax(dim=1)
    soft_output=softmax_func(x_input)
    print('soft_output:\n',soft_output)
    
    #在softmax的基础上取log
    log_output=torch.log(soft_output)
    print('log_output:\n',log_output)
    
    #对比softmax与log的结合与nn.LogSoftmaxloss(负对数似然损失)的输出结果,发现两者是一致的。
    logsoftmax_func=nn.LogSoftmax(dim=1)
    logsoftmax_output=logsoftmax_func(x_input)
    print('logsoftmax_output:\n',logsoftmax_output)
    
    #pytorch中关于NLLLoss的默认参数配置为:reducetion=True、size_average=True
    nllloss_func=nn.NLLLoss()
    nlloss_output=nllloss_func(logsoftmax_output,y_target)
    print('nlloss_output:\n',nlloss_output)
    
    #直接使用pytorch中的loss_func=nn.CrossEntropyLoss()看与经过NLLLoss的计算是不是一样
    crossentropyloss=nn.CrossEntropyLoss()
    crossentropyloss_output=crossentropyloss(x_input,y_target)
    print('crossentropyloss_output:\n',crossentropyloss_output)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    最后计算得到的结果为:

    x_input:
     tensor([[ 2.8883,  0.1760,  1.0774],
            [ 1.1216, -0.0562,  0.0660],
            [-1.3939, -0.0967,  0.5853]])
    y_target
     tensor([1, 2, 0])
    soft_output:
     tensor([[0.8131, 0.0540, 0.1329],
            [0.6039, 0.1860, 0.2102],
            [0.0841, 0.3076, 0.6083]])
    log_output:
     tensor([[-0.2069, -2.9192, -2.0178],
            [-0.5044, -1.6822, -1.5599],
            [-2.4762, -1.1790, -0.4970]])
    logsoftmax_output:
     tensor([[-0.2069, -2.9192, -2.0178],
            [-0.5044, -1.6822, -1.5599],
            [-2.4762, -1.1790, -0.4970]])
    nlloss_output:
     tensor(2.3185)
    crossentropyloss_output:
     tensor(2.3185)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    通过上面的结果可以看出,直接使用pytorch中的loss_func=nn.CrossEntropyLoss()计算得到的结果与softmax-log-NLLLoss计算得到的结果是一致的。

    四. Pytorch CrossEntropyLoss()另外一种实现方式

    交叉熵计算公式为:
    CE
    由于真实的分类任务里面,除了label那一项,其他的概率都为0,所以可以直接简写为:
    CE
    由于pytorch的交叉熵实现里包括了softmax这一步,所以可以表示为:
    CE
    化简得到:
    CE
    代码实现:

    import torch
    
    def CrossEntropyLoss(output, target):
        res = -output.gather(dim=1, index=target.view(-1, 1))
        res += torch.log(torch.exp(output).sum(dim=1).view(-1, 1))
        res = res.mean()
        return res
    
    output = torch.tensor([
        [1, 2, 3],
        [4, 5, 6]
    ], dtype=torch.float32)
    
    target = torch.tensor(
        [0, 1],
    )
    
    print(torch.nn.CrossEntropyLoss()(output, target))
    print(CrossEntropyLoss(output, target))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    结果如下:

    tensor(1.9076)
    tensor(1.9076)
    
    • 1
    • 2

    上面代码简写成一句话(表达的是相同含义):

    import torch
    import torch.nn as nn
    class CELoss(nn.Module):
        ''' Cross Entropy Loss'''
        def __init__(self):
            super().__init__()
    
        def forward(self, pred, target):
            ''' 
            Args:
                pred: prediction of model output    [N, M]
                target: ground truth of sampler [N]
            '''
            eps = 1e-12
          	# standard cross entropy loss
            loss = -1.*pred.gather(1, target.unsqueeze(-1)).reshape(-1,1) + torch.log(torch.exp(pred+eps).sum(dim=1)).reshape(-1,1)
    
            return loss.mean()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    torch.gather用法参考链接:PyTorch中torch.gather()函数

    五. 参考链接

    Pytorch常用的交叉熵损失函数CrossEntropyLoss()详解
    自己实现一个CrossEntropyLoss

  • 相关阅读:
    论文投稿指南——中文核心期刊推荐(计算机技术)
    【容器】Containerd产生及和Docker对比
    Android Killer v1.3.1版本太低无法正常反编译及回编的问题
    网页设计期末课程大作业:基于HTML+CSS+JavaScript+Bootstrap制作响应式网站信息技术交流博客(7页)
    4.Linux系统管理(组的管理,系统操作)
    ElasticSearch-查询语法(结构化查询)
    智慧应急解决方案-最新全套文件
    React fiber分片的理解和剖析
    微服务框架 SpringCloud微服务架构 15 RabbitMQ 快速入门 15.2 消息模型介绍
    每日一题·729.我的日程安排表
  • 原文地址:https://blog.csdn.net/flyingluohaipeng/article/details/128059969