交叉熵损失(Cross Entropy Loss)学习笔记

原理

  在分类任务中,我们通常使用交叉熵作为损失函数,首先给出交叉熵的计算公式:
二分类中:
L = 1 N ∑ i L i = 1 N ∑ i − [ y i l o g ( p i ) + ( 1 − y i ) ⋅ l o g ( 1 − p i ) ] \mathcal{L}=\frac1{N}\sum_{i}L_i=\frac1{N}\sum_{i}-[y_ilog(p_i)+(1-y_i)\cdot log(1-p_i)] L=N1iLi=N1i[yilog(pi)+(1yi)log(1pi)]  其中, y i y_i yi表示样本的label, p i p_i pi表示第i个样本预测为正类的概率。
多分类中:
L = 1 N ∑ i = − 1 N ∑ i ∑ c = 1 M y i c l o g ( p i c ) \mathcal{L}=\frac1{N}\sum_{i}=-\frac1{N}\sum_{i}\sum_{c=1}^{M}y_{ic}log(p_{ic}) L=N1i=N1ic=1Myiclog(pic)  其中,M是样本类别的数量, y i c y_{ic} yic是样本i的label取等于c取1,否则取0, p i c p_{ic} pic第i个样本预测属于类别c的概率。
  那么交叉熵为什么好呢,举一个例子:

预测值label是否正确
0.3 0.3 0.40 0 1 (democrat)
0.3 0.4 0.30 1 0 (republican)
0.1 0.2 0.71 0 0 (other)

  如果使用分类误差作为损失函数,该神经网络的分类误差为 1/3,请注意,这个net只是勉强正确地完成了前两个样本,并且在第三个样本上相差甚远。看这个例子:

预测值label是否正确
0.1 0.2 0.70 0 1 (democrat)
0.1 0.7 0.20 1 0 (republican)
0.3 0.4 0.31 0 0 (other)

  这个net的分类误差也是1/3,但是它很明显比上面那两个更好,对于前两个样本它很好的完成了分类,对于第三个样本则比较勉强,我们发现,分类误差是一种非常粗略的性能度量标准。
  对于这两个net我们计算交叉熵的值分别是1.37和0.54,第二个net的损失就比较小,这是符合逻辑的,相比于分类误差,交叉熵会更精细。同样我们也可以计算均方误差(MSE)作为损失,它的公式为: M S E = 1 n ∑ i n ( y i ^ − y i ) 2 MSE=\frac1n\sum_i^n(\hat{y_i}-y_i)^2 MSE=n1in(yi^yi)2  计算出来的值分别是0.81和0.34。但是相比于交叉熵,MSE过于强调不正确的输出,如果使用softmax层进行分类,反向传播的方法训练网络,有可能出现训练停滞不前的情况。
  对交叉熵补充一个很直观的解释:对于一个相同事件,我们度量两个概率分布 p ( x ) p(x) p(x) q ( x ) q(x) q(x)的交叉熵,其中 p ( x ) p(x) p(x)是真实样本分布, q ( x ) q(x) q(x)是非自然分布(模型输出),那么交叉熵实际上是基于一个非自然分布(相对于真实分布)的概率分布q进行编码时,在时间集合中唯一标识一个事件所需的比特数(bit),如图:
在这里插入图片描述

本文的例子来自Why You Should Use Cross-Entropy Error Instead Of Classification Error Or Mean Squared Error For Neural Network Classifier Training

pytorch中的交叉熵

  pytorch有内置的torch.nn.CrossEntropyLoss计算交叉熵,当使用该方法作为损失函数时需要注意两点,一个是因为torch.nn.CrossEntropyLoss内置了Softmax运算,因此不需要在网络的最后添加Softmax层,一个是给进去函数的label应该是一个整数,而不是one-hot编码形式,因为他会自动对给进去的标签进行onehot编码,再跟网络的预测结果算交叉熵。
  示例代码:

import torch
 
'''
每一个样本都有一个标签,表示它的真实类别。在深度学习中,通常是分批进行训练。
对于一个N分类问题,样本的标签只可能是012 ... N-1
则对于一个3分类问题,样本的标签只可能是012。
当batch_size为5时,这一个batch的标签是一个形状为[batch_size]的tensor,即shape为[5]
'''
 
# 一个batch(batch_size=5)的标签
label = torch.tensor([1, 2, 0, 1, 0])
 
print(label.shape) # [5]
 
'''
对于一个3分类问题,当训练时batch_size为5,
则深度网络对每一个batch的预测值是一个形状为[batch_size, classes]的tensor,即shape为[5, 3]
以深度网络对第一个样本的预测值[0.5, 0.8, -1.2]为例,
经过Softmax层后,得到[0.3949, 0.5330, 0.0721],表示深度网络认为第一个样本属于012这三类的概率分别是0.39490.53300.0721
'''
predict = torch.tensor([[ 0.5,  0.8, -1.2],
                        [-0.2,  1.8,  0.5],
                        [ 0.3,  0.2,  0.7],
                        [ 0.6, -0.8, -0.4],
                        [-0.4,  0.2,  0.8]])
 
print(predict.shape) # [5, 3]
 
# 当reduction='none'时,输出是对每一个样本预测的损失
loss_func = torch.nn.CrossEntropyLoss(reduction='none')
loss = loss_func(predict, label)
print(loss) # tensor([0.6292, 1.6421, 1.2228, 1.8790, 1.8152])
 
# 当reduction='sum'时,输出是对这一个batch预测的损失之和
loss_func = torch.nn.CrossEntropyLoss(reduction='sum')
loss = loss_func(predict, label)
print(loss) # tensor(7.1883)
 
# 当reduction='mean'时,输出是对这一个batch预测的平均损失
loss_func = torch.nn.CrossEntropyLoss(reduction='mean')
loss = loss_func(predict, label)
print(loss) # tensor(1.4377)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一本糊涂张~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值