zoukankan      html  css  js  c++  java
  • 交叉熵损失,softmax函数和 torch.nn.CrossEntropyLoss()中文

    背景

    多分类问题里(单对象单标签),一般问题的setup都是一个输入,然后对应的输出是一个vector,这个vector的长度等于总共类别的个数。输入进入到训练好的网络里,predicted class就是输出层里值最大的那个entry对应的标签。

    交叉熵在多分类神经网络训练中用的最多的loss function(损失函数)。 举一个很简单的例子,我们有一个三分类问题,对于一个input (x),神经网络最后一层的output ((y))是一个((3 imes 1))的向量。然后这个(x)对应的ground-truth((y^{'}) )也是一个((3 imes 1))的向量。

    交叉熵

    来举一个例子,让三个类别分别是类别0,1和2。这里让input (x)属于类别0。所以ground-truth((y^{'}) ) 就等于((1,0,0)), 让网络的预测输出((y))等于((3,1,-3))

    [y = (3,1,-3), space y^{'} = (1,0,0) ]

    交叉熵损失的定义如下公式所示(在上面的列子里,i是从0到2的):

    [H (y,y^{'})= -sum_i {y_i^{'}}log(softmax(y_i)) ]

    Softmax

    softmax的计算可以在下图找到。注意在图里,softmax的输入((3,1,-3)) 是神经网络最后一个fc层的输出((y))。(y)经过softmax层之后,就变成了(softmax(y)=(0.88,0.12,0))(y)的每一个entry可以看作每一个class的预测得分,那么(softmax(y))的每一个entry就是每一个class的预测概率。

    [H (y,y^{'})= -{y_j^{'}}log(softmax(y_j)) ]

    对于上面的列子,当前(x)的分类loss就是(H(y,y^{'})=-1 imes log(0.88)=0.12) (注意,这里(log)的base是(e))

    softmax常用于多分类过程中,它将多个神经元的输出,归一化到((0, 1)) 区间内,因此Softmax的输出可以看成概率,从而来进行多分类。

    nn.CrossEntropyLoss() in Pytorch

    其实归根结底,交叉熵损失的计算只需要一个term。这个term就是在softmax输出层中找到ground-truth里正确标签对应的那个entry (j) ,也就是((log(softmax(y_j))))。(当然咯,在计算(softmax(y_j))的时候,我们是需要y里所有的term的值的。)

    [H (y,y^{'})= -{y_j^{'}}log(softmax(y_j)) ]

    因为entry (j)对应的是ground-truth里正确的class。只有在(i=j)的时候才(y^{'}_i = 1),其他时候都等于0。

    在下面的代码里,我们把python中torch.nn.CrossEntropyLoss() 的计算结果和用公式计算出的交叉熵结果进行比较. 结果显示,torch.nn.CrossEntropyLoss()的input只需要是网络fc层的输出(y), 在torch.nn.CrossEntropyLoss()里它会自己把(y) 转化成(softmax(y)) 然后再进行交叉熵loss的运算.

    所以当我们用PyTorch搭建分类网络的时候,不需要再在最后一个fc层后再手动添加一个softmax层。

    注意,在用PyTorch做分类问题的时候,在网络搭建时(假设全连接层的output是y),在之后加一个 y = torch.nn.functional.log_softmax (y),并在训练时,用torch.nn.functional.nll_loss(y, labels)。这样达到的效果和不用log_softmax层,并用torch.nn.CrossEntropyLoss(y,labels)做损失函数是一模一样的。

    import torch
    import torch.nn as nn
    import math
    
    output = torch.randn(1, 5, requires_grad = True) #假设是网络的最后一层,5分类
    label = torch.empty(1, dtype=torch.long).random_(5) # 0 - 4, 任意选取一个分类
    
    print ('Network Output is: ', output)
    print ('Ground Truth Label is: ', label)
    
    score = output [0,label.item()].item() # label对应的class的logits(得分)
    print ('Score for the ground truth class = ', label)
    
    first = - score
    second = 0
    for i in range(5):
        second += math.exp(output[0,i])
    second = math.log(second)
    
    loss = first + second
    print ('-' * 20)
    print ('my loss = ', loss)
    
    loss = nn.CrossEntropyLoss()
    print ('pytorch loss = ', loss(output, label))
    

    下面这段新增代码分别用nn.functional.nll_loss()和nn.CrossEntropyLoss()对一个神经网络输出(fc_output)和其label进行了交叉熵损失计算

    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    
    # raw output from the net, a 10d vector
    fc_output = torch.randn(1, 5, requires_grad = True)  # tensor of shape 1x10
    label = torch.empty(1, dtype=torch.long).random_(5)  # tensor of shape 1
    
    # output element being softmaxed
    softmax_output = F.softmax(fc_output, dim=1) 
    
    # output element being softmaxed and apply log to it
    log_softmax_output = F.log_softmax(fc_output, dim=1)
    
    print('               label = ', label)
    print('         output(raw) = ', fc_output.detach())
    print('     softmax(output) = ', softmax_output.detach())
    print('log(softmax(output)) = ', log_softmax_output.detach())  # can use ln() to check
    
    loss1 = F.nll_loss(log_softmax_output, label)
    
    cross_entropy_loss = nn.CrossEntropyLoss()
    loss2 = cross_entropy_loss(fc_output, label)
    print()
    print('loss from nn.functional.nll_loss() = ', loss1)
    print('loss from    nn.CrossEntropyLoss() = ', loss2)
    

    第二段代码的运行结果为:

    label =  tensor([1])
    output(raw) =  tensor([[-0.7707,  0.1843,  0.2211,  0.4185, -0.3662]])
    softmax(output) =  tensor([[0.0903, 0.2346, 0.2434, 0.2965, 0.1353]])
    log(softmax(output)) =  tensor([[-2.4050, -1.4500, -1.4131, -1.2157, -2.0005]])
    
    loss from nn.functional.nll_loss() =  tensor(1.4500, grad_fn=<NllLossBackward>)
    loss from    nn.CrossEntropyLoss() =  tensor(1.4500, grad_fn=<NllLossBackward>)
    
  • 相关阅读:
    ML、DL及RL介绍和区别
    ros工作空间中文件夹结构
    C算法,已知结构体成员地址,如何得出结构体的基地址?
    循*迹小车轨道识别算法
    树莓派ssh卡顿之双机互联解决
    楼宇对讲自动开门的设计与实现
    JavaJSONArray jsonArray = JSONArray.fromObject()使用
    Java虚拟机详解JVM常见问题总结
    git 修改commit信息 Dawa
    通过commit_id找回文件 Dawa
  • 原文地址:https://www.cnblogs.com/fledlingbird/p/10718096.html
Copyright © 2011-2022 走看看