zl程序教程

您现在的位置是:首页 >  其他

当前栏目

Pytorch模型训练实用教程学习笔记:三、损失函数汇总

训练笔记学习PyTorch 函数 模型 汇总 损失
2023-09-14 09:15:11 时间

前言

最近在重温Pytorch基础,然而Pytorch官方文档的各种API是根据字母排列的,并不适合学习阅读。
于是在gayhub上找到了这样一份教程《Pytorch模型训练实用教程》,写得不错,特此根据它来再学习一下Pytorch。
仓库地址:https://github.com/TingsongYu/PyTorch_Tutorial

损失函数汇总

Pytorch中,有下列一些损失函数.

L1loss

torch.nn.L1Loss(size_average=None, reduce=None)
功能:
计算 output 和 target 之差的绝对值,可选返回同维度的 tensor 或者是一个标量。
计算公式:
在这里插入图片描述
参数:
reduce(bool)- 返回值是否为标量,默认为 True
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False时,返回的各样本的 loss 之和。

调用实例:

import torch
import torch.nn as nn

# 生成网络输出 以及 目标输出
output = torch.ones(2, 2, requires_grad=True)*0.5
target = torch.ones(2, 2)

# 设置三种不同参数的L1Loss
reduce_False = nn.L1Loss(size_average=True, reduce=False)
size_average_True = nn.L1Loss(size_average=True, reduce=True)
size_average_False = nn.L1Loss(size_average=False, reduce=True)

o_0 = reduce_False(output, target)
o_1 = size_average_True(output, target)
o_2 = size_average_False(output, target)

print('\nreduce=False, 输出同维度的loss:\n{}\n'.format(o_0))
print('size_average=True,\t求平均:\t{}'.format(o_1))
print('size_average=False,\t求和:\t{}'.format(o_2))

MSELoss

torch.nn.MSELoss(size_average=None, reduce=None, reduction=‘elementwise_mean’)
功能:
计算 output 和 target 之差的平方,可选返回同维度的 tensor 或者是一个标量。
计算公式:
在这里插入图片描述
参数:
reduce(bool)- 返回值是否为标量,默认为 True
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False时,返回的各样本的 loss 之和。

调用实例:

# coding: utf-8

import torch
import torch.nn as nn

# ----------------------------------- MSE loss

# 生成网络输出 以及 目标输出
output = torch.ones(2, 2, requires_grad=True) * 0.5
target = torch.ones(2, 2)

# 设置三种不同参数的L1Loss
reduce_False = nn.MSELoss(size_average=True, reduce=False)
size_average_True = nn.MSELoss(size_average=True, reduce=True)
size_average_False = nn.MSELoss(size_average=False, reduce=True)


o_0 = reduce_False(output, target)
o_1 = size_average_True(output, target)
o_2 = size_average_False(output, target)

print('\nreduce=False, 输出同维度的loss:\n{}\n'.format(o_0))
print('size_average=True,\t求平均:\t{}'.format(o_1))
print('size_average=False,\t求和:\t{}'.format(o_2))

CrossEntropyLoss

torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-
100, reduce=None, reduction=‘elementwise_mean’)
功能:
将输入经过 softmax 激活函数之后,再计算其与 target 的交叉熵损失。即该方法将nn.LogSoftmax()和 nn.NLLLoss()进行了结合。严格意义上的交叉熵损失函数应该是nn.NLLLoss()。
计算公式:
在这里插入图片描述
参数:
weight(Tensor)- 为每个类别的 loss 设置权值,常用于类别不均衡问题。weight 必须是 float类型的 tensor,其长度要于类别 C 一致,即每一个类别都要设置有 weight。
带 weight 的计算公式:
在这里插入图片描述
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为False时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True
ignore_index(int)- 忽略某一类别,不计算其 loss,其 loss 会为 0,并且,在采用size_average 时,不会计算那一类的 loss,除的时候的分母也不会统计那一类的样本。

调用实例:

import torch
import torch.nn as nn
import numpy as np
import math

# ----------------------------------- CrossEntropy loss: base

loss_f = nn.CrossEntropyLoss(weight=None, size_average=True, reduce=False)
# 生成网络输出 以及 目标输出
output = torch.ones(2, 3, requires_grad=True) * 0.5      # 假设一个三分类任务,batchsize=2,假设每个神经元输出都为0.5
target = torch.from_numpy(np.array([0, 1])).type(torch.LongTensor)

loss = loss_f(output, target)

print('--------------------------------------------------- CrossEntropy loss: base')
print('loss: ', loss)
print('由于reduce=False,所以可以看到每一个样本的loss,输出为[1.0986, 1.0986]')


# 熟悉计算公式,手动计算第一个样本
output = output[0].detach().numpy()
output_1 = output[0]              # 第一个样本的输出值
target_1 = target[0].numpy()

# 第一项
x_class = output[target_1]
# 第二项
exp = math.e
sigma_exp_x = pow(exp, output[0]) + pow(exp, output[1]) + pow(exp, output[2])
log_sigma_exp_x = math.log(sigma_exp_x)
# 两项相加
loss_1 = -x_class + log_sigma_exp_x
print('---------------------------------------------------  手动计算')
print('第一个样本的loss:', loss_1)


# ----------------------------------- CrossEntropy loss: weight

weight = torch.from_numpy(np.array([0.6, 0.2, 0.2])).float()
loss_f = nn.CrossEntropyLoss(weight=weight, size_average=True, reduce=False)
output = torch.ones(2, 3, requires_grad=True) * 0.5  # 假设一个三分类任务,batchsize为2个,假设每个神经元输出都为0.5
target = torch.from_numpy(np.array([0, 1])).type(torch.LongTensor)
loss = loss_f(output, target)
print('\n\n--------------------------------------------------- CrossEntropy loss: weight')
print('loss: ', loss)  #
print('原始loss值为1.0986, 第一个样本是第0类,weight=0.6,所以输出为1.0986*0.6 =', 1.0986*0.6)

# ----------------------------------- CrossEntropy loss: ignore_index

loss_f_1 = nn.CrossEntropyLoss(weight=None, size_average=False, reduce=False, ignore_index=1)
loss_f_2 = nn.CrossEntropyLoss(weight=None, size_average=False, reduce=False, ignore_index=2)

output = torch.ones(3, 3, requires_grad=True) * 0.5  # 假设一个三分类任务,batchsize为2个,假设每个神经元输出都为0.5
target = torch.from_numpy(np.array([0, 1, 2])).type(torch.LongTensor)

loss_1 = loss_f_1(output, target)
loss_2 = loss_f_2(output, target)

print('\n\n--------------------------------------------------- CrossEntropy loss: ignore_index')
print('ignore_index = 1: ', loss_1)     # 类别为1的样本的loss为0
print('ignore_index = 2: ', loss_2)     # 类别为2的样本的loss为0

NLLLoss

torch.nn.NLLLoss(weight=None, size_average=None, ignore_index=-100, reduce=None,reduction=‘elementwise_mean’)
功能:
常用于多分类任务,但是 input 在输入 NLLLoss()之前,需要对 input 进行 log_softmax 函数激活,即将 input 转换成概率分布的形式,并且取对数。这些步骤隐含在了CrossEntropyLoss中。

参数:
weight(Tensor)- 为每个类别的 loss 设置权值,常用于类别不均衡问题。weight 必须是 float类型的 tensor,其长度要于类别 C 一致,即每一个类别都要设置有 weight。
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为除以权重之和的平均值;为 False 时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True。
ignore_index(int)- 忽略某一类别,不计算其 loss,其 loss 会为 0,并且,在采用
size_average 时,不会计算那一类的 loss,除的时候的分母也不会统计那一类的样本。

调用实例:

# coding: utf-8

import torch
import torch.nn as nn
import numpy as np

# ----------------------------------- log likelihood loss

# 各类别权重
weight = torch.from_numpy(np.array([0.6, 0.2, 0.2])).float()

# 生成网络输出 以及 目标输出
output = torch.from_numpy(np.array([[0.7, 0.2, 0.1], [0.4, 1.2, 0.4]])).float()  
output.requires_grad = True
target = torch.from_numpy(np.array([0, 0])).type(torch.LongTensor)


loss_f = nn.NLLLoss(weight=weight, size_average=True, reduce=False)
loss = loss_f(output, target)

print('\nloss: \n', loss)
print('\n第一个样本是0类,loss = -(0.6*0.7)={}'.format(loss[0]))
print('\n第二个样本是0类,loss = -(0.6*0.4)={}'.format(loss[1]))

PoissonNLLLoss

torch.nn.PoissonNLLLoss(log_input=True, full=False, size_average=None, eps=1e^8, reduce=None, reduction=‘elementwise_mean’)
功能:
用于 target 服从泊松分布的分类任务。
参数:
log_input(bool)- 为 True 时,计算公式为:loss(input,target)=exp(input) - target * input; 为 False 时,loss(input,target)=input - target * log(input+eps)
full(bool)- 是否计算全部的 loss。例如,当采用斯特林公式近似阶乘项时,此为target*log(target) - target+0.5∗log(2πtarget)
eps(float)- 当 log_input = False 时,用来防止计算 log(0),而增加的一个修正项。即loss(input,target)=input - target * log(input+eps)
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True

调用实例:

# coding: utf-8

import torch
import torch.nn as nn
import numpy as np

# ----------------------------------- Poisson NLLLoss

# 生成网络输出 以及 目标输出
log_input = torch.randn(5, 2, requires_grad=True)
target = torch.randn(5, 2)

loss_f = nn.PoissonNLLLoss()
loss = loss_f(log_input, target)
print('\nloss: \n', loss)

KLDivLoss

torch.nn.KLDivLoss(size_average=None, reduce=None, reduction=‘elementwise_mean’)

功能:
计算 input 和 target 之间的 KL 散度。
参数:
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值,平均值为element-wise 的,而不是针对样本的平均;为 False 时,返回是各样本各维度的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True。

注意事项:
要想获得真正的 KL 散度,需要如下操作:

  • reduce = True ;size_average=False
  • 计算得到的 loss 要对 batch 进行求平均

调用实例:

# coding: utf-8

import torch
import torch.nn as nn
import numpy as np

# -----------------------------------  KLDiv loss

loss_f = nn.KLDivLoss(size_average=False, reduce=False)
loss_f_mean = nn.KLDivLoss(size_average=True, reduce=True)

# 生成网络输出 以及 目标输出
output = torch.from_numpy(np.array([[0.1132, 0.5477, 0.3390]])).float()
output.requires_grad = True
target = torch.from_numpy(np.array([[0.8541, 0.0511, 0.0947]])).float()

loss_1 = loss_f(output, target)
loss_mean = loss_f_mean(output, target)

print('\nloss: ', loss_1)
print('\nloss_mean: ', loss_mean)


# 熟悉计算公式,手动计算样本的第一个元素的loss,注意这里只有一个样本,是 element-wise计算的

output = output[0].detach().numpy()
output_1 = output[0]           # 第一个样本的第一个元素
target_1 = target[0][0].numpy()

loss_1 = target_1 * (np.log(target_1) - output_1)

print('\n第一个样本第一个元素的loss:', loss_1)

BCELoss

torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction=‘elementwise_mean’)

功能:
二分类任务时的交叉熵计算函数。此函数可以认为是 nn.CrossEntropyLoss 函数的特例。其分类限定为二分类,y 必须是{0,1}。还需要注意的是,input 应该为概率分布的形式,这样才符合交叉熵的应用。所以在 BCELoss 之前,input 一般为 sigmoid 激活层的输出。

计算公式:
在这里插入图片描述

参数:
weight(Tensor)- 为每个类别的 loss 设置权值,常用于类别不均衡问题。
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True

BCEWithLogitsLoss

torch.nn.BCEWithLogitsLoss(weight=None, size_average=None, reduce=None, reduction=‘elementwise_mean’, pos_weight=None)
功能:
将 Sigmoid 与 BCELoss 结合,类似于 CrossEntropyLoss(将 nn.LogSoftmax()和 nn.NLLLoss()进行结合)。即 input 会经过 Sigmoid 激活函数,将 input 变成概率分布的形式。

计算公式:
在这里插入图片描述

参数:
weight(Tensor)- : 为 batch 中单个样本设置权值,If given, has to be a Tensor of size “nbatch”.
pos_weight-: 正样本的权重, 当 p>1,提高召回率,当 P<1,提高精确度。可达到权衡召回率(Recall)和精确度(Precision)的作用。 Must be a vector with length equal to the number of classes.
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True

MarginRankingLoss

torch.nn.MarginRankingLoss(margin=0, size_average=None, reduce=None, reduction=‘elementwise_mean’)
功能:
计算两个向量之间的相似度,当两个向量之间的距离大于 margin,则 loss 为正,小于
margin,loss 为 0。
计算公式:
在这里插入图片描述
参数:
margin(float)- x1 和 x2 之间的差异。
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True。

HingeEmbeddingLoss

torch.nn.HingeEmbeddingLoss(margin=1.0, size_average=None, reduce=None, reduction=‘elementwise_mean’)
功能:
折页损失的拓展,主要用于衡量两个输入是否相似。
参数:
margin(float)- 默认值为 1,容忍的差距。
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True。

MultiLabelMarginLoss

torch.nn.MultiLabelMarginLoss(size_average=None, reduce=None, reduction=‘elementwise_mean’)
功能:
用于一个样本属于多个类别时的分类任务。
计算公式:
在这里插入图片描述
参数:
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False
时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True。

SmoothL1Loss

torch.nn.SmoothL1Loss(size_average=None, reduce=None, reduction=‘elementwise_mean’)

功能:
计算平滑 L1 损失.
参数:
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True。

SoftMarginLoss

torch.nn.SoftMarginLoss(size_average=None, reduce=None, reduction=‘elementwise_mean’)
功能:
计算二分类损失(和前面的BCELoss有什么区别未知)
参数:
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False
时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True。

MultiLabelSoftMarginLoss

torch.nn.MultiLabelSoftMarginLoss(weight=None, size_average=None, reduce=None, reduction=‘elementwise_mean’)
功能:
SoftMarginLoss 多标签版本。
参数:
weight(Tensor)- 为每个类别的 loss 设置权值。weight 必须是 float 类型的 tensor,其长度要于类别 C 一致,即每一个类别都要设置有 weight。

CosineEmbeddingLoss

torch.nn.CosineEmbeddingLoss(margin=0, size_average=None, reduce=None, reduction=‘elementwise_mean’)
功能:
衡量两个输入是否相似。
参数:
margin(float)- : 取值范围[-1,1], 推荐设置范围 [0, 0.5]
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True。

MultiMarginLoss

torch.nn.MultiMarginLoss(p=1, margin=1, weight=None, size_average=None, reduce=N
one, reduction=‘elementwise_mean’)

功能:
计算多分类的折页损失。

参数:
p(int)- 默认值为 1,仅可选 1 或者 2。
margin(float)- 默认值为 1
weight(Tensor)- 为每个类别的 loss 设置权值。weight 必须是 float 类型的 tensor,其长度要于类别 C 一致,即每一个类别都要设置有 weight。
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True。

TripletMarginLoss

torch.nn.TripletMarginLoss(margin=1.0, p=2, eps=1e-06, swap=False, size_average=None,reduce=None, reduction=‘elementwise_mean’)

功能:
计算三元组损失,人脸验证中常用。
参数:
margin(float)- 默认值为 1
p(int)- The norm degree ,默认值为 2
swap(float)–是否swap
size_average(bool)- 当 reduce=True 时有效。为 True 时,返回的 loss 为平均值;为 False时,返回的各样本的 loss 之和。
reduce(bool)- 返回值是否为标量,默认为 True。