总结
  • 文章来源:CSDN_LawsonAbs
  • 持续更新~
  • 切记:在使用这个函数之前,不要对logits取softmax,否则无法训练收敛

1 CrossEntropyLoss()函数解析

1.1 适用情况

单一标签的分类问题,即所谓的 one-hot 情形

1.2 数学基础

文章

2 使用方法

先看一下这个函数的文档,里面有这么一个公式:
pytorch中的CrossEntropyLoss()函数解析_nlp
那么这个公式是怎么来的呢?

  • x是一个向量 x = ( x 1 , x 2 , . . . , x n ) x=(x_1,x_2,...,x_n) x=(x1,x2,...,xn),其中的每个值 x i x_i xi都代表对每类的预测值,即每个标签的值,在作为参数传入 CrossEntropy 的之前,这个值是尚未经过softmax函数处理
  • class是一个值,表示这个样本本身的类别

由交叉熵的公式可知
L o s s = − ∑ i = 1 n y i l o g ( y ^ i ) Loss = - \sum_{i=1}^{n}y_i log(\hat y_i) Loss=i=1nyilog(y^i)

但是由于是 one-hot型,所以上式就等于:
L o s s = − l o g y t ^ Loss = -log \hat{y_t} Loss=logyt^ 其中 y t ^ \hat{y_t} yt^表示真实标签概率不为0的那个标签对应的预测值。

所以就得出下面这个公式:
loss ( x , c l a s s ) = − log ⁡ ( exp ⁡ ( x [ c l a s s ] ) ∑ j exp ⁡ ( x [ j ] ) ) = − x [ c l a s s ] + log ⁡ ( ∑ j exp ⁡ ( x [ j ] ) ) \text{loss}(x, class) = -\log\left(\frac{\exp(x[class])}{\sum_j \exp(x[j])}\right) = -x[class] + \log\left(\sum_j \exp(x[j])\right) loss(x,class)=log(jexp(x[j])exp(x[class]))=x[class]+log(jexp(x[j]))

中的 − l o g ( e x p ( x [ c l a s s ] ) ∑ j e x p ( x [ j ] ) ) -log(\frac{exp(x[class])}{\sum_j exp(x[j])}) log(jexp(x[j])exp(x[class])) 就是通过softmax求概率的过程。

3 避坑 3.1 计算的维度

pytorch中的CrossEntropyLoss()函数解析_nlp_02
上面这个三个红框中的类别是下面的2【按照列的角度出发,而不是行的角度】
上面这句话的说法是存在问题的,代码中,你既可以按照行,也可以按照列。官方的说明文档中给出的代码示例就是从行维度计算的。

import torch
import torch.nn as nn
# 如果在构造器中添加了 reduction = "none" 参数,则不再返回一个 scalar,也无法反向更新
loss = nn.CrossEntropyLoss()
input = torch.randn(3,5, requires_grad=True)

# 取3个数
# 需要注意,因为 input 的shape 是(3,5),就表明只有5类,所以下面的类别只能是5,否则会报 “IndexError: Target 5 is out of bounds.” 错
# random_() 中的数的含义应该是指定一个到其范围内的数,这里就是生成大小为[0,5) 的整数
target = torch.empty(3, dtype=torch.long).random_(5)
print(input)
print(target)
output = loss(input, target)
print(output.size())
output.backward() 
print(output)

pytorch中的CrossEntropyLoss()函数解析_# pytorch_03