PyTorch学习笔记:nn.CrossEntropyLoss——交叉熵损失
torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean', label_smoothing=0.0)
功能:创建一个交叉熵损失函数:
l
(
x
,
y
)
=
L
=
{
l
1
,
…
,
l
N
}
T
,
l
n
=
−
∑
c
=
1
C
w
c
log
e
x
n
,
c
∑
i
=
1
C
e
x
n
,
i
⋅
y
n
,
c
l(x,y)=L=\{l_1,\dots,l_N\}^T,l_n=-\sum^C_{c=1}w_c\log\frac{e^{x_{n,c}}}{\sum^C_{i=1}e^{x_{n,i}}}· y_{n,c}
l(x,y)=L={l1,…,lN}T,ln=−c=1∑Cwclog∑i=1Cexn,iexn,c⋅yn,c
其中
x
x
x是输入,
y
n
,
c
y_{n,c}
yn,c是标签向量元素(来自经过独热编码后的标签向量),
w
w
w是类别权重,
C
C
C是类别总数,
N
N
N表示batch size。
输入:
-
size_average
与reduce
已被弃用,具体功能由参数reduction
代替 -
weight
:赋予每个类的权重,指定的权重必须是一维并且长度为 C C C的数组,数据类型必须为tensor
格式 -
ignore_index
:指定一个被忽略,并且不影响网络参数更新的目标类别,数据类型必须是整数,即只能指定一个类别 -
reduction
:指定损失输出的形式,有三种选择:none
|mean
|sum
。none
:损失不做任何处理,直接输出一个数组;mean
:将得到的损失求平均值再输出,会输出一个数;sum
:将得到的损失求和再输出,会输出一个数注意:如果指定了ignore_index,则首先将ignore_index代表的类别损失删去,在剩下的损失数据里求均值,因此ignore_index所代表的的类别完全不会影响网络参数的更新
-
label_smoothing
:指定计算损失时的平滑量,其中0.0表示不平滑,关于平滑量可参考论文《Rethinking the Inception Architecture for Computer Vision》
注意:
- 输入应该包含原始、未经过标准化的预测值,
CrossEntropyLoss
函数已经内置softmax
处理 - 对于输入张量 x x x,尺寸必须为 ( m i n i b a t c h , C ) (minibatch,C) (minibatch,C)或者 ( m i n i b a t c h , C , d 1 , … , d K ) (minibatch,C,d_1,\dots,d_K) (minibatch,C,d1,…,dK),后者对于计算高维输入时很有用,如计算二维图像中每个像素点的交叉熵损失,注意: K ≥ 1 K≥1 K≥1
- 输入的张量 y y y,尺寸必须为 ( m i n i b a t c h ) (minibatch) (minibatch)或者 ( m i n i b a t c h , d 1 , … , d K ) (minibatch,d_1,\dots,d_K) (minibatch,d1,…,dK),与 x x x的尺寸相对应,后者也是用于高维数据的计算
- 注意 x x x的第二维度尺寸与类别数量一一对应,并且 y y y只需要输入物体类别序号即可,无需输入独热编码(该函数会自动对 y y y做独热编码), y y y里面数据的大小不能超过 x x x第二维度尺寸的大小减一(减一是因为标签 y y y是从 0 0 0开始计算)
代码案例
一般用法
import torch.nn as nn
import torch
x = torch.randn((2, 8))
# 在0-7范围内,随机生成两个数,当做标签
y = torch.randint(0, 8, [2])
ce = nn.CrossEntropyLoss()
out = ce(x, y)
print(x)
print(y)
print(out)
输出
# x
tensor([[ 1.3712, 0.4903, -1.3202, 0.1297, -1.6004, -0.1809, -2.8812, -0.3088],
[ 0.5855, -0.4926, 0.7647, -0.1717, -1.0418, -0.0381, -0.1307, -0.6390]])
# y
tensor([5, 0])
# 得到的交叉熵损失,默认返回损失的平均值
tensor(1.9324)
参数weight的用法
import torch.nn as nn
import torch
x = torch.randn((2, 2))
y = torch.tensor([0, 1])
# 不添加weight
ce = nn.CrossEntropyLoss(reduction='none')
# 添加weight
ce_w = nn.CrossEntropyLoss(weight=torch.tensor([0.5, 1.5]), reduction='none')
out = ce(x, y)
out_w = ce_w(x, y)
print(x)
print(y)
print(out)
print(out_w)
输出
# x
tensor([[-1.1011, 0.6231],
[ 0.2384, -0.3223]])
# y
tensor([0, 1])
# 不添加weight时的损失输出
tensor([1.8883, 1.0123])
# weight定义为[0.5, 1.5]时的损失
# 第一个数据(batch中第一个元素)由于标签为0
# 因此对应的损失乘以weight中第一个权重
# 第二个数据类似
tensor([0.9441, 1.5184])
参数ignore_index的用法
import torch.nn as nn
import torch
x = torch.randn((2, 2))
y = torch.tensor([0, 1])
# 不添加ignore_index
ce = nn.CrossEntropyLoss(reduction='none')
# 添加ignore_index
ce_i = nn.CrossEntropyLoss(ignore_index = 0, reduction='none')
out = ce(x, y)
out_i = ce_i(x, y)
print(x)
print(y)
print(out)
print(out_i)
输出
# x
tensor([[-0.9390, -0.6169],
[-0.7700, 0.3602]])
# y
tensor([0, 1])
# 不添加ignore_index时的损失输出
tensor([0.8671, 0.2799])
# ignore_index设置为0,表示忽略类别序号为0的损失
# 这里第一个数据标签设置为0,因此第一个损失清零
tensor([0.0000, 0.2799])
输入高维数据时
这里以对二维的预测图做损失为例
import torch.nn as nn
import torch
# 这里表示随机生成batch为1,图片尺寸为3*3
# 并且每个点有两个类别的预测图
x = torch.randn((1, 2, 3, 3))
# 这里表示预测图x对应的标签y
# 预测图x每个位置都会对应一个标签值
# x删去第二维度后的尺寸,就是标签y的尺寸
y = torch.randint(0, 2, [1, 3, 3])
ce = nn.CrossEntropyLoss(reduction='none')
out = ce(x, y)
print(x)
print(y)
print(out)
输出
# 输入的高维数据x
tensor([[[[ 0.8859, -2.0889, -0.6026],
[-1.6448, 0.7807, 0.9609],
[-0.0646, 0.2204, -0.7471]],
[[ 0.7075, -0.7013, -0.9280],
[-0.6913, 2.1507, -0.0758],
[ 0.2139, 0.8387, 0.3743]]]])
# 对应的标签,预测图x长宽为多少,标签y的长宽就为多少
tensor([[[0, 0, 1],
[0, 0, 0],
[1, 0, 1]]])
# 输出的损失
# 函数会为预测图x上每个位置都生成一个损失,这里一共生成3*3个损失(对应长乘宽)
tensor([[[0.6079, 1.6105, 0.8690],
[1.2794, 1.5964, 0.3035],
[0.5635, 1.0493, 0.2820]]])
官方文档
nn.CrossEntropyLoss:https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html#torch.nn.CrossEntropyLoss
初步完稿于:2022年1月29日