1.20.PyTorch的十九个损失函数
1.20.1.L1Loss(L1范数损失)
1.20.2.MSELoss(均方误差损失)
1.20.3.CrossEntropyLoss (交叉熵损失)
1.20.4.CTCLoss(连接时序分类损失)
1.20.5.NLLLoss(负对数似然损失)
1.20.6.PoissonNLLLoss (目标泊松分布的负对数似然损失)
1.20.7.KLDivLoss(KL散度损失)
1.20.8.BCELoss(二进制交叉熵损失)
1.20.9.BCEWithLogitsLoss
1.20.10.MarginRankingLoss
1.20.11.HingeEmbeddingLoss
1.20.12.MultiLabelMarginLoss(多标签分类损失)
1.20.13.SmoothL1Loss(平滑版L1损失)
1.20.14.SoftMarginLoss (2分类的logistic损失)
1.20.15.MultiLabelSoftMarginLoss (多标签one-versus-all损失)
1.20.16.CosineEmbeddingLoss (cosine损失)
1.20.17.MultiMarginLoss (多类别分类的hinge损失)
1.20.18.TripletMarginLoss(三元组损失)
1.20.19.TripletMarginWithDistanceLoss
1.20.PyTorch的十九个损失函数
本文截取自《PyTorch 模型训练实用教程》,获取全文pdf请点击:https://github.com/TingsongYu/PyTorch_Tutorial/tree/master/Data
PyTorch中的Loss Functions (https://pytorch.org/docs/stable/nn.html)
1.20.1.L1Loss(L1范数损失)
创建一个标准来度量输入x和目标y中每个元素之间的平均绝对误差(MAE)。
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.L1Loss.html#torch.nn.L1Loss
CLASS torch.nn.L1Loss(size_average=None, reduce=None, reduction: str = ‘mean’)
创建一个标准来度量输入x和目标y中每个元素之间的平均绝对误差(MAE)。
The unreduced (将reduction设置成’none’) loss 可以描述成如下:
N是batch size。如果reduction不是’none’(这个值默认是’mean’),那么损失值:
x和y是任意形状的张量,各有n个元素。
平均值(mean)操作仍然对所有元素进行操作,并除以n。
如果设置成reduction = ‘sum’,则可以避免除以n。
参数:
size_average (bool, optional):过时的(可以查看reduction)。默认情况下,损失是批处理中每个损失元素的平均值。请注意,对于某些损失,每个样本有多个元素。如果该字段size_average 设置为False,相反,这些损失是对每一批小批量元素的总和,当reduce为False时被忽略。默认值:True。
reduce (bool, 可选操作):过时(可以查看reduction)。默认情况下,根据size_average,通过每个小批的观察来对损失进行平均或求和。当reduce是False的时候,取而代之的是返回每批元素的损失并且忽略size_average。默认值是:True。
reduction (string, 可选):指定要应用到输出的reduction:‘none’ | ‘mean’ | ‘sum’。‘none’:不会进行任何的reduction。‘mean’:输出的总和将除以输出中的元素数。‘sum’:输出将被求和。注意:size_average和reduce正在被弃用的过程中,同时,指定这两个参数中的任何一个都将覆盖reduction。默认值:‘mean’。
Shape:
Input:(N, ): 其中表示任意数量的附加维度。
Target:(N, *): 和输入的shape是一样的。
Output: scalar。如果reduction是’none’,那么(N, *),和input的shape是一样的。
例子:
# -*- coding: UTF-8 -*-
import torch
loss = torch.nn.L1Loss()
input = torch.randn(2, 2, requires_grad=True)
target = torch.randn(2, 2)
output = loss(input, target)
print(input)
"""
输出结果:
tensor([[-0.0255, 0.7973],
[ 1.2952, -0.2776]], requires_grad=True)
"""
print(target)
"""
输出结果:
tensor([[ 0.9511, -0.5646],
[-1.4324, 2.4195]])
"""
print(output)
"""
输出结果:
tensor(1.9408, grad_fn=<L1LossBackward>)
"""
print(output.backward())
"""
输出结果:
None
"""
"""
分析结果(差值的绝对值 -->求和 --> 然后再求平均值):
|input11 - target11| = 0.9766
|input12 - target12| = 1.3619
|input21 - target21| = 2.7276
|input22 - target22| = 2.6971
(0.9766 + 1.3619 + 2.7276 + 2.6971) / 4 = 1.9408
说明使用的是 mean(L) if reduction=’mean’ 的算法。
"""
再如:
# -*- coding: UTF-8 -*-
import torch
loss = torch.nn.L1Loss(reduction='sum')
input = torch.randn(2, 2, requires_grad=True)
target = torch.randn(2, 2)
output = loss(input, target)
print(input)
"""
输出结果:
tensor([[ 0.0869, 1.2738],
[-1.2305, 1.2949]], requires_grad=True)
"""
print(target)
"""
输出结果:
tensor([[ 0.6978, -0.1851],
[-0.8179, -0.5523]])
"""
print(output)
"""
输出结果:
tensor(4.3296, grad_fn=<L1LossBackward>)
"""
print(output.backward())
"""
输出结果:
None
"""
"""
分析结果 (插的绝对值,最后求和):
|input11 - target11| = 0.6109
|input12 - target12| = 1.4589
|input21 - target21| = 0.4126
|input22 - target22| = 1.8472
(0.6109 + 1.4589 + 0.4126 + 1.8472) = 4.3296
说明使用的是 sum(L) if reduction=’sum’ 的算法。
"""
1.20.2.MSELoss(均方误差损失)
创建一个标准来测量输入x和目标y中每个元素之间的均方误差(L2范数的平方)。
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.MSELoss.html#torch.nn.MSELoss
CLASS torch.nn.MSELoss(size_average=None, reduce=None, reduction: str =‘mean’)
创建一个标准来测量输入x和目标y中每个元素之间的均方误差(L2范数的平方)
The unreduced (将reduction设置成’none’)损失可描述为:
N是batch size。如果reduction 不是’none’(默认是’mean’),那么损失值是:
x和y是任意形状的张量,各有n个元素。
mean运算仍然适用于所有元素,并除以n
如果reduction = ‘sum’,则可以避免n除法
参数:
size_average (bool, 可选) : 过时的(可参阅reduction)。默认情况下,损失是批次中每个损失元素的平均数。请注意,对于某些损失,每个样本有多个元素。如果该字段size_average 设置为False,则为每个小批量的损失总和。当reduce为时被忽略False。默认:True
reduce(bool,可选)–已弃用(请参阅reduction)。默认情况下,根据size_average,通过每个小批的观察来对损失进行平均或求和。当reduce为False时,返回每个批处理元素的损失值,并忽略size_average。默认值:True。
reduction(string,可选):指定要应用到输出的reduction : ‘none’ | ‘mean’ | ‘sum’。‘none’:不会进行任何的reduction。‘mean’:输出的总和将除以输出元素的数量。‘sum’:输出将被求和。注意:size_average和reduce正在被弃用的过程中。同时,指定这两个参数中的任何一个都将覆盖reduction。默认是’mean’
Shape:
Input: (N, ) 其中*表示任意数量的附加维度。
Target: (N, *)*, 和 input 有相同的shape。
# -*- coding: UTF-8 -*-
import torch
import torch.nn as nn
loss = nn.MSELoss()
input = torch.randn(2, 2, requires_grad=True)
print(input)
"""
输出结果:
tensor([[-0.4661, -0.5551],
[ 0.5901, -0.1945]], requires_grad=True)
"""
target = torch.randn(2, 2)
print(target)
"""
输出结果:
tensor([[ 2.7104, 0.0058],
[-0.5086, -0.7360]])
"""
output = loss(input, target)
print(output)
"""
输出结果:
tensor(2.9762, grad_fn=<MseLossBackward>)
"""
print(output.backward())
"""
输出结果:
None
"""
"""
分析结果 (sum(差值的平方) / 4) :
(-0.4661 - 2.7104) ** 2 = 10.09015225
(-0.5551 - 0.0058) ** 2 = 0.31460881
(0.5901 - (-0.5086)) ** 2 = 1.20714169
(-0.1945 - (-0.7360)) ** 2 = 0.29322225
(10.09015225 + 0.31460881 + 1.20714169 + 0.29322225) / 4 = 11.90512525 / 4 = 2.9762813125
"""
1.20.3.CrossEntropyLoss (交叉熵损失)
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html#torch.nn.CrossEntropyLoss
这个准则将n. LogSoftmax()和n.NLLLoss()组合在一个类中。
关于交叉熵损失函数
交叉熵损失(cross-entropy Loss)又称为对数似然损失(Log-likelihood Loss)、对数损失;二分类时还可称之为逻辑斯谛回归损失(Logistic Loss)。交叉熵损失函数表达式为 L = - sigama(y_i * log(x_i))。pytroch这里不是严格意义上的交叉熵损失函数,而是先将input经过softmax激活函数,将向量“归一化”成概率形式,然后再与target计算严格意义上交叉熵损失。
在多分类任务中,经常采用softmax激活函数 + 交叉熵损失函数,因为交叉熵描述了两个概率分布的差异,然而神经网络输出的是向量,并不是概率分布的形式。所以需要softmax激活函数将一个向量进行”归一化”成概率分布的形式,再采用交叉熵损失函数计算loss。
再回顾PyTorch的CrossEntropyLoss(),官方文档中提到时将nn.LogSoftmax()和 nn.NLLLoss()进行了结合,nn.LogSoftmax() 相当于激活函数 ,nn.NLLLoss()是损失函数。
交叉熵是直接用交叉熵公式去评估两个分布之间的差异,和log似然殊途同归,同源不同源
在PyTorch中,CrossEntropyLoss其实是LogSoftMax和NLLLoss的合体,也就是所有的loss都会先经历一次log SoftMax之后再进入交叉熵公式。
什么时候使用?
1.分类任务
2.向更高精度和召回值优化。
torch.nn.CrossEntropyLoss(weight: Optional[torch.Tensor] = None, size_average=None, ignore_index: int = -100, reduce=None, reduction: str = ‘mean’)
将输入经过softmax激活函数之后,在计算其与target的交叉熵损失。这个准则将nn.LogSoftmax()和nn.NLLLoss()组合在一个类中。严格意义上的交叉熵
它在用C类训练分类问题时很有用。如果提供,可选参数weight应该是一个一维张量,它将权重赋给每个类。当你有一个不平衡的训练集时,这是特别有用的。
输入应该包含每个类的原始的、未标准化的分数。
该准则期望一个范围为[0,C -1][0,C−1]的类索引作为一维大小小批张量的每个值的目标。如果ignore_index被指定,这个标准也接受这个类索引(这个索引不一定在类范围内)
这种损失可以描述为(exp(x)表示:e的x次方,是一个指数函数):
或者在指定了weight参数的情况下:
对每个小批量的观测所得的损失取平均值。如果指定了weight参数,则这是一个加权平均值:
参数:
weight(Tensor, 可选): 给每个类的手动调整权重。如果给定,它的张量是C。
size_average(bool, 可选):弃用(见减少)。默认情况下,损失是批处理中每个损失元素的平均值。注意,对于某些损失,每个样品有多个元素。如果size_average字段设置为False,则对每个小批处理的损失进行求和。当reduce为False时被忽略。默认值:true
ignore_index (int, 可选):指定一个目标值,该目标值将被忽略,并且不会影响输入梯度。当size_average为True时,对非忽略目标的损失进行平均。
reduce (bool,可选)-已弃用(参见reduce)。默认情况下,根据size_average,通过每个小批的观察来对损失进行平均或求和。当reduce为False时,返回每个批处理元素的损失值,并忽略size_average。默认值:True.
reduction (字符串,可选)-指定应用于输出的reduction: ‘none’ | ‘mean’ | ‘sum’。‘none’:不进行reduction ,‘mean’:取输出的加权平均值,‘sum’:将输出求和。注意:size_average和reduce正在被弃用的过程中,同时,指定这两个参数中的任何一个都将覆盖reduce。默认值:‘mean’
shape:
example:
# -*- coding: UTF-8 -*-
import torch
import torch.nn as nn
loss = nn.CrossEntropyLoss()
input = torch.randn(3, 5, requires_grad=True)
print(input)
"""
输出结果:
tensor([[-0.1618, -0.3454, -0.0239, 0.4111, -0.0067],
[ 1.8492, 0.3351, -0.4480, -1.3461, -0.9416],
[-0.9352, 1.5032, -1.6051, 0.2360, -0.0167]], requires_grad=True)
"""
target = torch.empty(3, dtype=torch.long).random_(5)
print(target)
"""
输出结果:
tensor([1, 1, 4])
"""
output = loss(input, target)
print(output)
"""
输出结果:
tensor(1.9463, grad_fn=<NllLossBackward>)
"""
print(output.backward())
"""
输出结果:
None
"""
再如案例:
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
1.20.4.CTCLoss(连接时序分类损失)
CTC连接时序分类损失,可以对没有对齐的数据进行自动对齐,主要用在没有事先对齐的序列化数据训练上。比如语音识别、ocr识别等等。
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.CTCLoss.html#torch.nn.CTCLoss
CLASS torch.nn.CTCLoss(blank: int = 0, reduction: str = ‘mean’, zero_infinity: bool = False)
The Connectionist Temporal Classification loss. (连接主义者的时间分类损失。)
计算连续(unsegmented)时间序列与目标序列之间的损失。CTCLoss计算输入与目标可能对齐的概率之和,从而产生相对于每个输入节点可区分的损耗值。假定输入与目标的比对是“many-to-one”,这限制了目标序列的长度,因此必须<= 输入长度。
参数:
blank (int, 可选) – blank label. Default 0 .
reduction (字符串,可选)-指定应用于输出的reduction :‘none’ | ‘mean’ | ‘sum’。‘none’:不进行reduction,‘mean’:输出损耗除以目标长度,然后取批的平均值。默认值:‘mean’
zero_infinity (bool,可选)-是否为零的无限损失和相关的梯度。默认为零。无限损耗主要发生在输入太短而不能对准目标时。
Shape
Log_probs : 张量的大小(T,N,C),T = input的长度,N = batch size, C = number of classes(包括blank)。输出概率的对数化(例如:通过torch.nn.functional.log_softmax() 获得)。
Targets: 张量的大小为(N,S)或(sum(target_lengths)),N = batch size,S = target的最大长度。如果shape是(N,S),它表示目标序列。目标序列中的每个元素都是一个类索引。并且目标索引不能为空(默认为0)。在(N,S) 形式中,将目标填充到最长序列的长度,然后进行堆叠。在(sum(target_lenghts))形式中,假设目标在一维内没有填充和连接。
input_length:大小(N)的元组或张量,其中N=batch size。它表示输入的长度。
Output: scalar。如果reduction是’none’,则为(N),其中N=batch size。
例子:
# -*- coding: UTF-8 -*-
import torch
import torch.nn as nn
# Target are to be padded
T = 50 # Input sequence length
C = 20 # Number of classes (including blank)
N = 16 # Batch size
S = 30 # Target sequence length of longest target in batch (padding length)
S_min = 10 # Minimum target length, for demonstration purposes
# Initialize random batch of input vectors, for *size = (T,N,C)
input = torch.randn(T, N, C).log_softmax(2).detach().requires_grad_()
# Initialize random batch of targets (0 = blank, 1:C = classes)
target = torch.randint(low=1, high=C, size=(N, S), dtype=torch.long)
input_lengths = torch.full(size=(N,), fill_value=T, dtype=torch.long)
target_lengths = torch.randint(low=S_min, high=S, size=(N,), dtype=torch.long)
ctc_loss = nn.CTCLoss()
loss = ctc_loss(input, target, input_lengths, target_lengths)
loss.backward()
# Target are to be un-padded
T = 50 # Input sequence length
C = 20 # Number of classes (including blank)
N = 16 # Batch size
# Initialize random batch of input vectors, for *size = (T,N,C)
input = torch.randn(T, N, C).log_softmax(2).detach().requires_grad_()
input_lengths = torch.full(size=(N,), fill_value=T, dtype=torch.long)
# Initialize random batch of targets (0 = blank, 1:C = classes)
target_lengths = torch.randint(low=1, high=T, size=(N,), dtype=torch.long)
target = torch.randint(low=1, high=C, size=(sum(target_lengths),), dtype=torch.long)
ctc_loss = nn.CTCLoss()
loss = ctc_loss(input, target, input_lengths, target_lengths)
print(loss.backward())
1.20.5.NLLLoss(负对数似然损失)
https://pytorch.org/docs/stable/generated/torch.nn.NLLLoss.html#torch.nn.NLLLoss
CLASS torch.nn.NLLLoss(weight: Optional[torch.Tensor] = None, size_average=None, ignore_index: int = -100, reduce=None, reduction: str = ‘mean’)
负对数似然损失。对于带有C类的训练一个分类问题很有用。
如果提供了,可选参数weight应该是一个给每个类赋权的一维张量。当你有一个不平衡的训练集时,这是特别有用的。
通过在网络的最后一层添加LogSoftmax层,可以很容易地获得神经网络中的对数概率。如果您不想添加额外的层,您可以使用CrossEntropyLoss代替。
这个损失的目标应该是在[0,C -1]范围内的类索引,其中C = number of classes. 如果指定了ignore_index,这个损失也接受这个类索引(这个索引不一定在类范围内)
the unreduced (即缩减为“无”)损失可描述为:
其中x为input,y为target,w为权重,N为批大小。如果reduction不是’none’(默认的’mean’),那么:
实际应用:
常用于多分类任务,但是input在输入NLLLoss()之前,需要对input进行log_softmax函数激活,即将input转换成概率分布的形式,并且取对数。其实这些步骤在CrossEntropyLoss中就有,如果不想让网络的最后一层是log_softmax层的话,就可以采用CrossEntropyLoss完全代替此函数。
例子:
# -*- coding: UTF-8 -*-
import torch
import torch.nn as nn
m = nn.LogSoftmax(dim=1)
loss = nn.NLLLoss()
# input is of size N x C = 3 x 5
input = torch.randn(3, 5, requires_grad=True)
# each element in target has to have 0 <= value < C
target = torch.tensor([1, 0, 4])
output = loss(m(input), target)
output.backward()
# 2D loss example (used, for example, with image inputs)
N, C = 5, 4
loss = nn.NLLLoss()
# input is of size N x C x height x width
data = torch.randn(N, 16, 10, 10)
conv = nn.Conv2d(16, C, (3, 3))
m = nn.LogSoftmax(dim=1)
# each element in target has to have 0 <= value < C
target = torch.empty(N, 8, 8, dtype=torch.long).random_(0, C)
output = loss(m(conv(data)), target)
output.backward()
1.20.6.PoissonNLLLoss (目标泊松分布的负对数似然损失)
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.PoissonNLLLoss.html#torch.nn.PoissonNLLLoss
CLASS torch.nn.PoissonNLLLoss(log_input: bool = True, full: bool = False, size_average=None, eps: float = 1e-08, reduce=None, reduction: str = ‘mean’)
损失可以描述成如下:
最后一项可以省略,也可以用斯特林公式近似。近似值用于大于1的目标值。对于小于或等于1个0的目标,损失会增加。
例子:
# -*- coding: UTF-8 -*-
import torch
import torch.nn as nn
loss = nn.PoissonNLLLoss()
log_input = torch.randn(5, 2, requires_grad=True)
target = torch.randn(5, 2)
output = loss(log_input, target)
print(output.backward())
1.20.7.KLDivLoss(KL散度损失)
计算input和target之间的KL散度。KL散度可用于衡量不同的连续分布之间的距离,在连续的输出分布的的空间上(离散采样)上进行直接回归时,很有效。
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.KLDivLoss.html#torch.nn.KLDivLoss
CLASS torch.nn.KLDivLoss(size_average=None, reduce=None, reduction: str = ‘mean’, log_target: bool = False)
Kullback-Leibler散度损失度量
Kullback-Leibler散度是连续分布的一种有用的距离度量,在(离散采样的)连续输出分布空间上执行直接回归时通常很有用。
与NLLLoss一样,给定的输入被期望包含对数概率,并且不局限于2D张量。默认情况下,目标被解释为概率,但可以将其视为log_target设置为True的log- probability。
这个准则要求目标张量与输入张量大小相同。
未unreduced (即reduction为“none”)损失可描述为:
其中索引N跨越所有input的维度,L的形状与输入相同。如果reduction不是’none’(默认是’mean’),则:
在默认reduction模式“mean”中,每个小批的损失在观测值和维度上取平均值。'batchmean’模式给出了正确的KL散度,其中损失仅在批维度上平均。'mean’模式的行为将在下一个主要版本中被更改为和’batchmean’一样。
其它介绍:
KLDivLoss的全称是Kullback-Leibler divergence,它也叫做相对熵。
看名字就知道它和交叉熵都是熵的计算,有一定联系,我们看一下它的公式:
可以看到相对熵就是交叉熵减去(信息熵)
通俗一点来讲就是:
1.信息熵是该label完美编码所需的信息量。
2.交叉熵是该label不完美编码(用观察值编码所需的信息量)。
3.相对熵是交叉熵和信息熵的差值,也就是所需额外的信息量。
什么时候使用?
1.分类任务
2.和交叉熵计算差不多,通常使用交叉熵。
补充:KL散度
KL散度(Kullback-Leibler divergence)又称为相对熵(Relative Entropy),用于描述两个概率分布之间的差异。
案例:
# -*- 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)
输出结果:
D:\installed\Anaconda3\lib\site-packages\torch\nn\_reduction.py:44: UserWarning: size_average and reduce args will be deprecated, please use reduction='none' instead.
warnings.warn(warning.format(ret))
D:\installed\Anaconda3\lib\site-packages\torch\nn\_reduction.py:44: UserWarning: size_average and reduce args will be deprecated, please use reduction='mean' instead.
warnings.warn(warning.format(ret))
D:\installed\Anaconda3\lib\site-packages\torch\nn\functional.py:2398: UserWarning: reduction: 'mean' divides the total loss by both the batch size and the support size.'batchmean' divides only by the batch size, and aligns with the KL div math definition.'mean' will be changed to behave the same as 'batchmean' in the next major release.
warnings.warn("reduction: 'mean' divides the total loss by both the batch size and the support size."
loss: tensor([[-0.2314, -0.1800, -0.2553]], grad_fn=<KlDivBackward>)
loss_mean: tensor(-0.2222, grad_fn=<KlDivBackward>)
第一个样本第一个元素的loss: -0.23138168
1.20.8.BCELoss(二进制交叉熵损失)
二分类任务时的交叉熵计算函数。用于测量重构的误差,例如自动编码机。注意目标的值t[i]的范围为0到1之间。
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.BCELoss.html#torch.nn.BCELoss
功能:
二分类任务时的交叉熵计算函数。此函数可以认为是nn.CrossEntropyLoss函数的特例。其分类限定为二分类,y必须是{0,1}。还需要注意的是,input应该为概率分布的形式,这样才符合交叉熵的应用。所以在BCELoss之前,input一般为sigmoid激活层的输出,官方例子也是这样给的。该损失函数在自编码器中常用。
CLASS torch.nn.BCELoss(weight: Optional[torch.Tensor] = None, size_average=None, reduce=None, reduction: str = ‘mean’)
创建一个标准来度量目标和输出之间的二分类的交叉熵:
未unreduced (即reduction为“none”)损失可描述为:
其中N为批大小。如果reduce不是’none’(默认的’mean’),那么:
这用于测量例如自动编码器中的重建误差。注意目标y 应为0到1之间的数字。
例子:
# -*- coding: UTF-8 -*-
import torch
import torch.nn as nn
m = nn.Sigmoid()
loss = nn.BCELoss()
input = torch.randn(3, requires_grad=True)
print(input)
"""
输出结果为:tensor([ 0.9469, 0.0443, -0.2868], requires_grad=True)
"""
target = torch.empty(3).random_(2)
print(target)
"""
输出结果为:
tensor([1., 0., 0.])
"""
output = loss(m(input), target)
print(output)
"""
输出结果为:
tensor(0.5344, grad_fn=<BinaryCrossEntropyBackward>)
"""
print(output.backward())
"""
输出结果为:
None
"""
1.20.9.BCEWithLogitsLoss
功能:
将Sigmoid与BCELoss结合,类似于CrossEntropyLoss(将nn.LogSoftmax()和 nn.NLLLoss()进行结合)。即input会经过Sigmoid激活函数,将input变成概率分布的形式。
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.BCEWithLogitsLoss.html#torch.nn.BCEWithLogitsLoss
CLASS torch.nn.BCEWithLogitsLoss(weight: Optional[torch.Tensor] = None, size_average=None, reduce=None, reduction: str = ‘mean’, pos_weight: Optional[torch.Tensor] = None)
这个损失将Sigmoid层和BCELoss合并在一个单独的类中。这个版本在数值上比使用简单的Sigmoid和BCELoss as更加稳定,通过将操作合并到一个层,我们利用了log-sum-exp技巧来实现数值稳定性.
The unreduced(即reduction为“none”)损失可描述为:
其中N为batch size。如果reduction不是’none’(默认的’mean’),那么:
这用于测量例如auto-encoder中的重建误差。请注意,目标t [i]应为0到1之间的数字。
通过为正面示例增加权重,可以在召回率和准确性之间进行权衡。对于多标签分类,损失可描述为:
例子1:
# -*- coding: UTF-8 -*-
import torch
import torch.nn as nn
# 64 classes, batch size = 10
target = torch.ones([10, 64], dtype=torch.float32)
# A prediction (logit)
output = torch.full([10, 64], 1.5)
# All weights are equal to 1
pos_weight = torch.ones([64])
criterion = torch.nn.BCEWithLogitsLoss(pos_weight=pos_weight)
# -log(sigmoid(1.5))
print(criterion(output, target))
"""
输出结果:tensor(0.2014)
"""
再如案例:
# -*- coding: UTF-8 -*-
import torch
import torch.nn as nn
loss = nn.BCEWithLogitsLoss()
input = torch.randn(3, requires_grad=True)
print(input)
"""
输出结果:tensor([ 2.0453, 0.5157, -0.4684], requires_grad=True)
"""
target = torch.empty(3).random_(2)
print(target)
"""
输出结果:tensor([1., 0., 0.])
"""
output = loss(input, target)
print(output)
"""
输出结果:
tensor(0.5305, grad_fn=<BinaryCrossEntropyWithLogitsBackward>)
"""
print(output.backward())
"""
输出结果:None
"""
1.20.10.MarginRankingLoss
功能:
计算两个向量之间的相似度,当两个向量之间的距离大于margin,则loss为正,小于margin,loss为0。
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.MarginRankingLoss.html#torch.nn.MarginRankingLoss
CLASS torch.nn.MarginRankingLoss(margin: float = 0.0, size_average=None, reduce=None, reduction: str = ‘mean’)
创建一个标准来度量给定输入x1, x2,两个一维小批量张量,和一个标签一维小批量张量y(包含1或-1)的损失。
如果 y = 1, 则假定第一个输入的排名应高于第二个输入(具有更大的值),反之亦然 y = -1。
小批中每对样品的损失函数为:
例子:
# -*- coding: UTF-8 -*-
import torch
import torch.nn as nn
loss = nn.MarginRankingLoss()
input1 = torch.randn(3, requires_grad=True)
print(input1)
"""
输出结果:
tensor([ 0.0561, 2.0191, -0.2548], requires_grad=True)
"""
input2 = torch.randn(3, requires_grad=True)
print(input2)
"""
输出结果:
tensor([ 0.5791, -1.3004, -0.5878], requires_grad=True)
"""
target = torch.randn(3).sign()
print(target)
"""
输出结果:
tensor([ 1., -1., -1.])
"""
output = loss(input1, input2, target)
print(output)
"""
输出结果:
tensor(1.6031, grad_fn=<MeanBackward0>)
"""
print(output.backward())
"""
输出结果:
None
"""
1.20.11.HingeEmbeddingLoss
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.HingeEmbeddingLoss.html#torch.nn.HingeEmbeddingLoss
CLASS torch.nn.HingeEmbeddingLoss(margin: float = 1.0, size_average=None, reduce=None, reduction: str = ‘mean’)
测量给定输入张量x和标签张量y(包含1或-1)的损失。这通常用于衡量两个输入是否相似或不相似,例如使用L1成对距离作为x,通常用于学习非线性嵌入或半监督学习。
小批量中第n个样本的损失函数为:
总的损失函数是:
1.20.12.MultiLabelMarginLoss(多标签分类损失)
用于一个样本属于多个类别时的分类任务。例如一个四分类任务,样本x属于第0类,第1类,不属于第2类,第3类。再比如:输入图像中具有蓝天,白云,草地三个元素,而没有人物元素。此时模型输出中蓝天,白天,草地元素对应的输出值相比于人物元素对应的输出值至大于1,也就是模型蓝天,白天,草地元素预测值更大。注意,标签维度为N,且各元素为当前具备元素对应索引,不足用-1补充。
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.MultiLabelMarginLoss.html#torch.nn.MultiLabelMarginLoss
CLASS torch.nn.MultiLabelMarginLoss(size_average=None, reduce=None, reduction: str = ‘mean’)
创建一个准则,在输入x (一个2D mini-batch张量)和输出y(目标类指标的2D张量)之间优化一个多类多分类铰链损失(margin-based损失)。对于mini-batch中的每个样品:
y和x必须有相同的size。
该标准仅考虑从前面开始的非负目标的连续块。
这允许不同的样本具有可变数量的目标类别。
例子:
# -*- coding: UTF-8 -*-
import torch
import torch.nn as nn
loss = nn.MultiLabelMarginLoss()
x = torch.FloatTensor([[0.1, 0.2, 0.4, 0.8]])
# for target y, only consider labels 3 and 0, not after label -1
y = torch.LongTensor([[3, 0, -1, 1]])
print(loss(x, y))
# 0.25 * ((1-(0.1-0.2)) + (1-(0.1-0.4)) + (1-(0.8-0.2)) + (1-(0.8-0.4)))
"""
输出结果为:
tensor(0.8500)
"""
1.20.13.SmoothL1Loss(平滑版L1损失)
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.SmoothL1Loss.html#torch.nn.SmoothL1Loss
CLASS torch.nn.SmoothL1Loss(size_average=None, reduce=None, reduction: str = ‘mean’, beta: float = 1.0)
创建一个标准,如果绝对元素误差低于beta,则使用平方项,否则使用L1项。它对异常值不像MSELoss那么敏感,并且在某些情况下防止了爆炸梯度式增长(例如,参见Ross Girshick的Fast R-CNN论文)。也被称为Huber损失:
x和y任意形状,每一个都有n元素,求和操作仍然对所有元素进行操作,并除以n。
beta是一个可选参数,默认值为1。
注意:当beta设置为0时,这相当于L1Loss。将负值传递给beta将导致异常。
如果reduction = 'sum’可以避免除以n.
1.20.14.SoftMarginLoss (2分类的logistic损失)
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.SoftMarginLoss.html#torch.nn.SoftMarginLoss
CLASS torch.nn.SoftMarginLoss(size_average=None, reduce=None, reduction: str = ‘mean’)
创建一个准则,优化输入张量x和目标张量y(包含1或-1)之间的两类分类逻辑逻辑损失。
1.20.15.MultiLabelSoftMarginLoss (多标签one-versus-all损失)
CLASS torch.nn.MultiLabelSoftMarginLoss(weight: Optional[torch.Tensor] = None, size_average=None, reduce=None, reduction: str = ‘mean’)
在输入x和大小为(N,C) 的目标y之间建立一个基于最大熵的多标签one-versus-all损失优化准则。对于minibatch中的每个样品:
1.20.16.CosineEmbeddingLoss (cosine损失)
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.CosineEmbeddingLoss.html#torch.nn.CosineEmbeddingLoss
CLASS torch.nn.CosineEmbeddingLoss(margin: float = 0.0, size_average=None, reduce=None, reduction: str = ‘mean’)
创建一个准则来度量给定输入张量X1,X2的损失和一个张量标签y,这个y的值是-1或1。这是用来衡量两个输入是否相似或不相似,利用余弦距离,通常用于学习非线性嵌入或半监督学习。
每个样本的损耗函数为:
1.20.17.MultiMarginLoss (多类别分类的hinge损失)
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.MultiMarginLoss.html#torch.nn.MultiMarginLoss
CLASS torch.nn.MultiMarginLoss(p: int = 1, margin: float = 1.0, weight: Optional[torch.Tensor] = None, size_average=None, reduce=None, reduction: str = ‘mean’)
建立一个准则,在输入x(一个两维的mini-batch张量)和输出y(这是一个目标类指标的一维张量,0 <= y <= x.size(1) - 1) 之间优化 multi-class分类hinge损失(margin-based的损失)
对于每个小批量样本,其一维输入x和标量输出y的损失为:
可选地,您可以通过向构造函数传递一个一维权重张量来给类赋予不相等的权重。
损失函数变为:
1.20.18.TripletMarginLoss(三元组损失)
功能
计算三元组损失,人脸验证中常用。
如下图Anchor、Negative、Positive,目标是让Positive元和Anchor元之间的距离尽可能的小,Positive元和Negative元之间的距离尽可能的大。
从公式上看,Anchor元和Positive元之间的距离加上一个threshold之后,要小于Anchor元与Negative元之间的距离。
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.TripletMarginLoss.html#torch.nn.TripletMarginLoss
CLASS torch.nn.TripletMarginLoss(margin: float = 1.0, p: float = 2.0, eps: float = 1e-06, swap: bool = False, size_average=None, reduce=None, reduction: str = ‘mean’)
创建一个标准来衡量给定输入张量的三重态损失 X1,X2,X3 且边距值大于0。这是用来衡量样本之间的相对相似性。三元组由a,p和n组成(即锚,正例和负例)。所有输入张量的形状应为(N,D)。
由V.Balntas,E.Riba写的Learning shallow convolutional feature descriptors with triplet losses(http://www.bmva.org/bmvc/2016/papers/paper119/index.html)文中对距离交换进行了详细的描述。
mini-batch中每个样品的损失函数为:
则:
可以参见:TripleMarginWithDistanceLoss,它使用自定义距离函数计算输入张量的三重边界损失。
例子:
# -*- coding: UTF-8 -*-
import torch
import torch.nn as nn
triplet_loss = nn.TripletMarginLoss(margin=1.0, p=2)
print(triplet_loss)
"""
输出结果:
TripletMarginLoss()
"""
anchor = torch.randn(100, 128, requires_grad=True)
print(anchor)
"""
输出结果:
tensor([[-1.0403, -0.7441, 2.0546, ..., 0.0603, -0.3375, 0.4513],
[-0.7719, 0.3127, 0.5972, ..., -0.2020, -0.5062, -1.4393],
[-1.9228, 0.9016, 0.1328, ..., -0.8353, 0.1053, 1.3324],
...,
[ 2.0607, 0.5818, -0.4649, ..., 0.1845, -0.5550, -1.0219],
[-0.3485, 0.4270, 0.7329, ..., 0.4552, 1.7498, 1.2050],
[ 2.3201, 0.4459, -0.9079, ..., 0.7179, -1.4113, 1.3421]],
requires_grad=True)
"""
positive = torch.randn(100, 128, requires_grad=True)
print(positive)
"""
输出结果:
tensor([[ 0.2954, -0.9518, -0.1654, ..., 0.0489, -0.5601, 0.2818],
[ 1.3680, -0.0680, -2.6128, ..., 2.2886, 0.8362, 1.3002],
[-0.0395, 1.0710, 0.7697, ..., -0.5219, 0.3808, 0.3753],
...,
[ 1.0734, 0.2878, 0.4927, ..., -0.2018, -0.7396, -0.6490],
[ 1.5470, -0.2169, -0.0528, ..., 1.1892, -1.7831, -0.5778],
[ 0.3281, -1.2508, 0.4340, ..., -1.4700, 0.8975, -0.2052]],
requires_grad=True)
"""
negative = torch.randn(100, 128, requires_grad=True)
print(negative)
"""
输出结果:
tensor([[ 0.5848, 0.3988, 1.2048, ..., 0.9842, -0.6208, -1.5352],
[ 0.9891, -0.8243, -1.8682, ..., -0.4896, -0.7210, -0.3494],
[ 0.5562, 0.4406, 1.9688, ..., 0.4642, 1.0121, -0.9396],
...,
[-0.4447, -0.2257, -0.2211, ..., 0.9498, -0.1042, -0.5341],
[ 0.7808, -0.1410, -0.1129, ..., -2.6021, 0.3728, 0.1434],
[ 1.4687, -0.7502, 1.1567, ..., -1.5126, 0.4650, -0.9038]],
requires_grad=True)
"""
output = triplet_loss(anchor, positive, negative)
print(output)
"""
输出结果:
tensor(1.1500, grad_fn=<MeanBackward0>)
"""
print(output.backward())
"""
输出结果:None
"""
1.20.19.TripletMarginWithDistanceLoss
官网地址:https://pytorch.org/docs/stable/generated/torch.nn.TripletMarginWithDistanceLoss.html#torch.nn.TripletMarginWithDistanceLoss
CLASS torch.nn.TripletMarginWithDistanceLoss(*, distance_function: Optional[Callable[[torch.Tensor, torch.Tensor], torch.Tensor]] = None, margin: float = 1.0, swap: bool = False, reduction: str = ‘mean’)
创建一个标准衡量的triplet损失给定的输入张量a, p、和n(分别表示anchor、positive和negative的例子),和nonnegative,real-valued函数(“distance function”)用于计算anchor和positive之间的关系(“positive distance”)和anchor和example的例子(“negative distance”)
unreduced的损失(即reduction为’none’的损失)可描述为:
其中N为batch size; d是量化两个张量的紧密性的nonnegative, real-valued函数,称为distance_function; margin是一个non-negative margin,表示使损失为0所需的正负距离之间的最小差。每个输入张量都有N元素,并且可以是距离函数可以处理的任何形状。
如果reduce不是’none’(默认的’mean’),则:
例子:
# -*- coding: UTF-8 -*-
import torch
import torch.nn as nn
import torch.nn.functional as F
# Initialize embeddings
embedding = nn.Embedding(1000, 128)
anchor_ids = torch.randint(0, 1000, (1,), requires_grad=True)
positive_ids = torch.randint(0, 1000, (1,), requires_grad=True)
negative_ids = torch.randint(0, 1000, (1,), requires_grad=True)
anchor = embedding(anchor_ids)
positive = embedding(positive_ids)
negative = embedding(negative_ids)
# Built-in Distance Function
triplet_loss = \
nn.TripletMarginWithDistanceLoss(distance_function=nn.PairwiseDistance())
output = triplet_loss(anchor, positive, negative)
output.backward()
# Custom Distance Function
def l_infinity(x1, x2):
return torch.max(torch.abs(x1 - x2), dim=1).values
triplet_loss = \
nn.TripletMarginWithDistanceLoss(distance_function=l_infinity, margin=1.5)
output = triplet_loss(anchor, positive, negative)
output.backward()
# Custom Distance Function (Lambda)
triplet_loss = \
nn.TripletMarginWithDistanceLoss(
distance_function=lambda x, y: 1.0 - F.cosine_similarity(x, y))
output = triplet_loss(anchor, positive, negative)
output.backward()