前言
最近在重温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 之和。
调用实例:
代码语言:javascript复制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 之和。
调用实例:
代码语言:javascript复制# 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,除的时候的分母也不会统计那一类的样本。
调用实例:
代码语言:javascript复制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('nn--------------------------------------------------- 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('nn--------------------------------------------------- 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,除的时候的分母也不会统计那一类的样本。
调用实例:
代码语言:javascript复制# 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
调用实例:
代码语言:javascript复制# 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 进行求平均
调用实例:
代码语言:javascript复制# 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。