损失函数的使用

(一) nn.L1Loss()

平均绝对误差(mean absolute error, MAE) ,即输出与输入的平均绝对差值(作差、取绝对值、求平均,最后一步求和也行)。

torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')
  • size_average 和 reduce 两个参数基本废弃,不使用了;
  • reduction 参数可以是 'mean''sum' ,对应了作差取绝对值之后,是求平均还是求和。默认是 'mean'
  • 其输入和输出,需要指明并具有相同的 batch_size 。

(二) nn.MSELoss()

均方误差(mean squared error, MSE),即输出与输入的平均方差值(作差、求平方、求平均,最后一步求和也行)。

torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')
  • size_average 和 reduce 两个参数基本废弃,不使用了;
  • reduction 参数可以是 'mean''sum' ,对应了作差求平方之后,是求平均还是求和。默认是 'mean'
  • 其输入和输出,什么维度的都行。

(三) nn.CrossEntropyLoss()

交叉熵(CrossEntropyLoss, CE),适用于处理多分类问题,包括二分类。
官网链接:https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html#torch.nn.CrossEntropyLoss

①数学上的交叉熵公式:

用于描述两个概率分布之间的差异性大小,两者完全相等,则交叉熵为 0 :
H ( P , Q ) = − ∑ j N P ( x ) ⋅ l o g [ Q ( x ) ] H(P,Q)=-\sum_{j}^{N}{P(x)·log[Q(x)]} H(P,Q)=jNP(x)log[Q(x)]

其中, P ( x ) P(x) P(x) 为真实概率分布, Q ( x ) Q(x) Q(x) 为预测概率分布。 l o g log log 其实是中文的 l n ln ln 函数。


②pytorch 中的 softmax 函数:

s o f t m a x ( x j ) = e x j ∑ j C e x p ( x [ j ] ) softmax(x_j)=\frac{e^{x_j}}{\sum_{j}^{C}{exp(x[j])}} softmax(xj)=jCexp(x[j])exj
Softmax 函数是一种在多分类(假设C个)问题中常用的激活函数,能够将一个实数向量转换为概率分布(通过指数函数使概率大于零,且概率和等于1)。


③pytorch 中的交叉熵计算公式:

pytorch 会先将输入应用 softmax 函数,再应用交叉熵公式。

单个样本的交叉熵求法:

l o s s ( x , t a r g e t ) = − w ⋅ 1 ⋅ l o g ( s o f t m a x ( x [ t a r g e t ] ) ) = − w ⋅ 1 ⋅ l o g ( e x p ( x [ t a r g e t ] ) ∑ j C e x p ( x [ j ] ) ) = w ⋅ 1 ⋅ ( − x [ t a r g e t ] + l o g ( ∑ j C e x p ( x [ j ] ) ) ) − − − − − − − − − − − − − − − − 换种写法,并省略 w 之后: − − − − − − − − − − − − − − − − − l o s s ( x , t a r g e t ) = − x [ t a r g e t ] + l o g ( ∑ j C e x p ( x [ j ] ) ) loss(x,target)=-w·1·log(softmax(x[target]))=-w·1·log(\frac{exp(x[target])}{\sum_{j}^{C}{exp(x[j])}})=w·1·(-x[target]+log(\sum_{j}^{C}{exp(x[j])}))\\ ----------------换种写法,并省略w之后:-----------------\\ loss(x,target)=-x[target]+log(\sum_{j}^{C}{exp(x[j]))} loss(x,target)=w1log(softmax(x[target]))=w1log(jCexp(x[j])exp(x[target]))=w1(x[target]+log(jCexp(x[j])))换种写法,并省略w之后:loss(x,target)=x[target]+log(jCexp(x[j]))

  • 这里的 l o g log log 其实是中文的 l n ln ln 函数。

  • 其中的 x x x 即为网络模型的输出向量(其元素值为概率), t a r g e t target target 表示的是输入图像的正确类别的索引, C C C 为类别数, j j j 是一般类别索引。

    一般的训练网络模型输出层,都用索引来表示是哪一类。

  • 可选参数 w w w 是此类别的权重。这在处理不平衡的训练集时特别有用(不给出的就可直接忽略)。

④公式使用详解:

假设有一个三分类网络,用来识别“人、狗、猫”三个物种,网络模型如下:

在这里插入图片描述

输出的三个值,分别代表了识别为 人、狗、猫 的概率,其索引分别是0、1、2,这三个值分别用 x [ 0 ] 、 x [ 1 ] 、 x [ 2 ] x[0]、x[1]、x[2] x[0]x[1]x[2] 表示。

现有特例:

对一张人的图片进行分类(则 t a r g e t = 0 target=0 target=0 ),一次训练的结果是 [ 0.8 , 0.1 , 0.2 ] [0.8,0.1,0.2] [0.8,0.1,0.2] ,识别成人、狗、猫的概率则分别是 x [ 0 ] = 0.8 、 x [ 1 ] = 0.1 、 x [ 2 ] = 0.2 x[0]=0.8、x[1]=0.1、x[2]=0.2 x[0]=0.8x[1]=0.1x[2]=0.2

则损失为(可选参数 w y n w_{y_n} wyn 未提供):
l o s s ( x , t a r g e t ) = l o s s ( x , 0 ) = − l o g ( e x p ( x [ 0 ] ) e x p ( x [ 0 ] ) + e x p ( x [ 1 ] ) + e x p ( x [ 2 ] ) ) = − l o g ( e x [ 0 ] e x [ 0 ] + e x [ 1 ] + e x [ 2 ] ) = − 0.8 + l n ( e 0.8 + e 0.1 + e 0.2 ) \begin{align*} loss(x,target)=loss(x,0)&=-log(\frac{exp(x[0])}{exp(x[0])+exp(x[1])+exp(x[2])})\\ &=-log(\frac{e^{x[0]}}{e^{x[0]}+e^{x[1]}+e^{x[2]}})\\ &=-0.8+ln(e^{0.8}+e^{0.1}+e^{0.2}) \end{align*} loss(x,target)=loss(x,0)=log(exp(x[0])+exp(x[1])+exp(x[2])exp(x[0]))=log(ex[0]+ex[1]+ex[2]ex[0])=0.8+ln(e0.8+e0.1+e0.2)

⑤代码:

torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, 
                          reduction='mean', label_smoothing=0.0)
  • 参数(基本都不用知道,不用管):

    • weight:处理不平衡的训练集时,为每个类别分配的权重(一般都不给出,都是 None),应该是一个一维张量(Tensor),长度为类别数。

    • reduction:可以是 none'mean'默认)和 'sum' ,表示计算完单个损失后,对 batch_size 个图像的损失取平均还是求和(正在被弃用) 。

    • 其他的几乎不用,或者是已经被弃用的参数。

  • 输入和输出的形状(这个注意就行):

    • 输入 input :①对于未批量的输入,形状是 ( C ) (C) (C) 即可, C C C 为训练类别数;②对于批量的输入,形状是 ( N , C ) (N,C) (N,C) N N Nbatch_size
    • 标签 target :①对于未批量的输入,形状是 ( ) () () ,即标量(scalar);   ②对于批量的输入,形状是 ( N ) (N) (N) N N Nbatch_size
    • 输出 output :①对于未批量的输入,形状是 ( ) () () ,即标量(scalar);   ②对于批量的输入,形状是 ( N ) (N) (N) N N Nbatch_size

⑥示例:

 import torch
 from sympy.codegen.cnodes import sizeof
 from torch import nn
 import torchvision
 from torchvision import transforms
 from torch.utils.data import DataLoader
 import math
 
 
 dataclass_transform = transforms.Compose([
 	transforms.ToTensor(),
 ])
 
 test_dataset = torchvision.datasets.CIFAR10(root='E:\\4_Data_sets\\species recognition', train=False,transform=dataclass_transform, download=True)
 test_dataloader = DataLoader(dataset=test_dataset,batch_size=2)
 
 class CIFAR10_NET(nn.Module):
 	def __init__(self):
 		super(CIFAR10_NET, self).__init__()
 		self.model = nn.Sequential(
 			nn.Conv2d(3, 32, 5, padding=2),  # 输入输出尺寸相同,故根据公式计算出padding的值
 			nn.MaxPool2d(2, 2),
 			nn.Conv2d(32, 32, 5, padding=2),
 			nn.MaxPool2d(2, 2),
 			nn.Conv2d(32, 64, 5, padding=2),
 			nn.MaxPool2d(2, 2),
 			nn.Flatten(),
 			nn.Linear(1024, 64),
 			nn.Linear(64, 10)
 		)
 
 	def forward(self, x):
 		x = self.model(x)
 		return x
 
 CIFAR10_NET_Instance = CIFAR10_NET()
 loss = nn.CrossEntropyLoss()
 
 step = 0
 for data in test_dataloader:
 	imgs,targets = data
 	outputs = CIFAR10_NET_Instance(imgs)
 	loss = loss(outputs, targets)
 	print(outputs)
 	print(targets)
 	print(loss)
 
 	step = step + 1
 	if step == 1:
 		break
 ------------------------------------------------------------------------------------------------------------------
 # 运行结果:
 
 # 以batch_size=2为例,CIFAR10训练网络模型的输出层有10个值,分别对应了图片被识别成这10个类的概率。
 # 取第一个batch_size识别的结果
 tensor([[-0.0729, -0.0768, -0.1316, -0.1054,  0.0700,  0.1325,  0.0323,  0.1132,  0.1797,  -0.0037],
         [-0.0830, -0.0798, -0.1405, -0.1147,  0.0607,  0.1272,  0.0178,  0.1276,  0.2022,  -0.0107]], 
        grad_fn=<AddmmBackward0>)
 tensor([3, 8]) # 两张图片对应的target
 tensor(2.2721, grad_fn=<NllLossBackward0>) # 两张图片的loss的平均值。

上述代码中,并未将最终的输出概率变成 0~1 之间,不过这里不影响其功能展示。

计算详情如下:

在这里插入图片描述


(四) nn.BCELoss()

二元交叉熵(Binary Cross Entropy, BCE),只适用于二元分类问题(是/否问题)。

这个就是吴恩达视频里用于解决二分类问题的逻辑回归方法中用到的损失函数。

二元交叉熵计算公式:
l o s s ( x , y ) = − w ⋅ [ y ⋅ l o g x + ( 1 − y ) l o g ( 1 − x ) ] loss(x,y)=-w·[y·logx+(1-y)log(1-x)] loss(x,y)=w[ylogx+(1y)log(1x)]

  • 这里的 l o g log log 其实是中文的 l n ln ln 函数。
  • 其中的 x x x 表示网络训练模型的输出结果(一个处于0~1之间的概率), y y y 表示这一个输入图像是否属于目标类别(1:是,0:不是)。
  • w w w 一般可忽略,看成 1 也行。

代码:

torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean')
  • 参数:

    • reduction :可以是 none'mean' (默认)和 'sum'

      batch_size 不为 1 时,表示计算完单个输入图像的损失后,对batch_size个图像的损失取平均(默认)还是求和

      • 示例:

        下图表示测试图像是否为苹果的案例,其中 batch_size=3 ;三个图像中,前两个是苹果(1),第三个不是(0),对它们求BCE损失,并进行取平均。

        在这里插入图片描述

    • 其他参数基本不用管。

  • 输入和输出的形状:

    • 输入:什么形状的都行;

      此输入,即网络模型的输出。

    • target :和输入形状相同;

    • 输出:默认是标量(但仍是tensor类型),如果 reduction'none' ,那么输出就和输入的形状相同。


上一篇 下一篇
神经网络入门实战(十四) 神经网络入门实战(十六)
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐