总结
1 CrossEntropyLoss()函数解析
1.1 适用情况
单一标签的分类问题,即所谓的 one-hot
情形
1.2 数学基础
见文章
2 使用方法
先看一下这个函数的文档,里面有这么一个公式:
那么这个公式是怎么来的呢?
- 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=1∑nyilog(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(j∑exp(x[j]))
中的 e x p ( x [ c l a s s ] ) ∑ j e x p ( x [ j ] ) \frac{exp(x[class])}{\sum_j exp(x[j])} ∑jexp(x[j])exp(x[class]) 就是通过softmax求概率的过程。
3 避坑
3.1 计算的维度
代码中,你既可以按照行,也可以按照列。官方的说明文档中给出的代码示例就是从行维度计算的。
3.2 具体案例
import torch
import torch.nn as nn
# 如果在构造器中添加了 reduction = "none" 参数,则不再返回一个 scalar,也无法反向更新
loss = nn.CrossEntropyLoss()
# 需要注意,因为 input 的shape 是(3,5),就表明有5类,所以下面的类别只能是5,
# 否则会报 “IndexError: Target 5 is out of bounds.” 错
input = torch.randn(3,5, requires_grad=True)
# 取3个数;类型设置为torch.long;random_() 中的数的含义应该是指定一个到其范围内的数,这里就是生成大小为[0,5) 的整数
target = torch.empty(3, dtype=torch.long).random_(5)
print(input)
print(target)
output = loss(input, target)
print(output)
这里面有一点儿不合理的地方就是: randn()
得到的是随机值,随机值的取值竟然也有到负值的,这对于普通的预测结果是不合理的。