PyTorch框架学习十二——损失函数
- 一、损失函数的作用
- 二、18种常见损失函数简述
- 1.L1Loss(MAE)
- 2.MSELoss
- 3.SmoothL1Loss
- 4.交叉熵CrossEntropyLoss
- 5.NLLLoss
- 6.PoissonNLLLoss
- 7.KLDivLoss
- 8.BCELoss
- 9.BCEWithLogitsLoss
- 10.MarginRankingLoss
- 11.HingeEmbeddingLoss
- 12.MultiLabelMarginLoss
- 13.SoftMarginLoss
- 14.MultiLabelSoftMarginLoss
- 15.nn.CosineEmbeddingLoss
- 16.MultiMarginLoss
- 17.TripletMarginLoss
- 18.CTCLoss
之前的笔记写过,一个深度学习/机器学习模型的实现过程主要来说包括五部分:数据、模型、损失函数、最优化和迭代过程。前面的笔记已经介绍了数据部分和模型部分,这次笔记主要介绍损失函数。
因为在实际使用中根据不同的实际情况会选择不同的损失函数,所以对损失函数的公式推导就不涉及了,以后具体用到什么再写什么吧,这次笔记聚焦于PyTorch中损失函数的构建与工作原理,并简单介绍常用的18种损失函数,具体公式推导应参考相关论文,这里不详细推导。
一、损失函数的作用
损失函数简单来说就是用来衡量模型输出(预测值)与真实标签(真实值)的差异的。
有三个概念很容易混淆:
- 损失函数:
- 代价函数:
- 目标函数:
其中,损失函数是关于某一个具体样本的衡量,代价函数是所有样本的损失的平均,目标函数是在代价函数的基础上加上正则化。
二、18种常见损失函数简述
1.L1Loss(MAE)
功能:计算inputs与targets之差的绝对值。
torch.nn.L1Loss(size_average=None, reduce=None, reduction: str = 'mean')
参数只需要关注reduction,因为size_average和reduce两个结合做了reduction的事,以后PyTorch会舍弃这两个参数,下面每个损失函数都有这两个参数,就不提了。
reduction是一个字符串参数,能取三个值:‘none’、‘mean’、‘sum’,因为现在计算loss基本都是一个batch的数据样本不是一个单独的样本,所以这三个值分别代表对一个batch的样本分别求loss、求所有loss的均值、求loss的和。
看一个例子:
inputs = torch.ones((2, 2))
target = torch.ones((2, 2)) * 3loss_none = nn.L1Loss(reduction='none')
loss1 = loss_none(inputs, target)
print("input:{}\n\ntarget:{}\n\nL1 loss_none:{}".format(inputs, target, loss1))loss_mean = nn.L1Loss(reduction='mean')
loss2 = loss_mean(inputs, target)
print("\nL1 loss_mean:{}".format(loss2))loss_sum = nn.L1Loss(reduction='sum')
loss3 = loss_sum(inputs, target)
print("\nL1 loss_mean:{}".format(loss3))
输出:
input:tensor([[1., 1.],[1., 1.]])target:tensor([[3., 3.],[3., 3.]])L1 loss_none:tensor([[2., 2.],[2., 2.]])L1 loss_mean:2.0L1 loss_mean:8.0
2.MSELoss
功能:计算inputs与targets之差的平方。
torch.nn.MSELoss(size_average=None, reduce=None, reduction: str = 'mean')
这个损失函数与L1Loss形式上很相似,直接举例:
inputs = torch.ones((2, 2))
target = torch.ones((2, 2)) * 3loss_f_mse = nn.MSELoss(reduction='none')
loss_mse = loss_f_mse(inputs, target)print("input:{}\n\ntarget:{}\n\nMSE loss:{}".format(inputs, target, loss_mse))
输出:
input:tensor([[1., 1.],[1., 1.]])target:tensor([[3., 3.],[3., 3.]])MSE loss:tensor([[4., 4.],[4., 4.]])
3.SmoothL1Loss
功能:平滑的L1Loss。
torch.nn.SmoothL1Loss(size_average=None, reduce=None, reduction: str = 'mean')
其公式为:
我们将真实值全部设置为0,就可以绘制出其损失函数的样子,并与L1Loss进行比较:
inputs = torch.linspace(-3, 3, steps=500)target = torch.zeros_like(inputs)loss_f = nn.SmoothL1Loss(reduction='none')loss_smooth = loss_f(inputs, target)loss_l1 = np.abs(inputs.numpy())plt.plot(inputs.numpy(), loss_smooth.numpy(), label='Smooth L1 Loss')plt.plot(inputs.numpy(), loss_l1, label='L1 loss')plt.xlabel('x_i - y_i')plt.ylabel('loss value')plt.legend()plt.grid()plt.show()
绘制的结果为:
4.交叉熵CrossEntropyLoss
功能:nn.LogSoftmax()与nn.NLLLoss()结合,进行交叉熵计算。
torch.nn.CrossEntropyLoss(weight: Optional[torch.Tensor] = None, size_average=None, ignore_index: int = -100, reduce=None, reduction: str = 'mean')
交叉熵损失是分类问题中常用的损失函数,它的计算公式如下:
若再考虑权重weight,公式为:
权重的设置在数据不平衡时非常关键。
参数如下所示:
- weight:各类别的loss设置权值。
- ignore_index:忽略某个类别。
- reduction:同上。
举个栗子:
inputs = torch.tensor([[1, 2], [1, 3], [1, 3]], dtype=torch.float)
target = torch.tensor([0, 1, 1], dtype=torch.long)loss_f_none = nn.CrossEntropyLoss(weight=None, reduction='none')
loss_none = loss_f_none(inputs, target)print("Cross Entropy Loss:\n ", loss_none)
输出:
Cross Entropy Loss:tensor([1.3133, 0.1269, 0.1269])
5.NLLLoss
功能:实现负对数似然函数中的负号功能。
torch.nn.NLLLoss(weight: Optional[torch.Tensor] = None, size_average=None, ignore_index: int = -100, reduce=None, reduction: str = 'mean')
举例:
inputs = torch.tensor([[1, 2], [1, 3], [1, 3]], dtype=torch.float)
target = torch.tensor([0, 1, 1], dtype=torch.long)weights = torch.tensor([1, 1], dtype=torch.float)
loss_f_none_w = nn.NLLLoss(weight=weights, reduction='none')
loss_none_w = loss_f_none_w(inputs, target)print("\nweights: ", weights)
print("NLL Loss", loss_none_w, loss_sum, loss_mean)
输出为:
weights: tensor([1., 1.])
NLL Loss tensor([-1., -3., -3.])
6.PoissonNLLLoss
功能:泊松分布的负对数似然损失函数。
torch.nn.PoissonNLLLoss(log_input: bool = True, full: bool = False, size_average=None, eps: float = 1e-08, reduce=None, reduction: str = 'mean')
主要参数:
- log_input:输入是否为对数形式,决定计算公式是哪一个。
- full:计算所有的loss,默认为False。
- eps:修正项,避免log(input)为nan。
- reduction:同上。
7.KLDivLoss
功能:计算KLD,KL散度。
torch.nn.KLDivLoss(size_average=None, reduce=None, reduction: str = 'mean', log_target: bool = False)
8.BCELoss
功能:二分类交叉熵。
torch.nn.BCELoss(weight: Optional[torch.Tensor] = None, size_average=None, reduce=None, reduction: str = 'mean')
注意:输入值取值在[0,1]。
9.BCEWithLogitsLoss
功能:结合Sigmoid与二分类交叉熵。
torch.nn.BCEWithLogitsLoss(weight: Optional[torch.Tensor] = None, size_average=None, reduce=None, reduction: str = 'mean', pos_weight: Optional[torch.Tensor] = None)
注意:网络最后不加sigmoid函数。
10.MarginRankingLoss
功能:计算两个向量之间的相似度,用于排序任务。
torch.nn.MarginRankingLoss(margin: float = 0.0, size_average=None, reduce=None, reduction: str = 'mean')
说明:该方法计算两组数据之间的差异,返回一个n×n的loss矩阵。
11.HingeEmbeddingLoss
功能:计算两个输入的相似性,常用于非线性embedding和半监督学习。
torch.nn.HingeEmbeddingLoss(margin: float = 1.0, size_average=None, reduce=None, reduction: str = 'mean')
12.MultiLabelMarginLoss
功能:多标签边界损失函数。
torch.nn.MultiLabelMarginLoss(size_average=None, reduce=None, reduction: str = 'mean')
13.SoftMarginLoss
功能:计算二分类的logistic损失。
torch.nn.SoftMarginLoss(size_average=None, reduce=None, reduction: str = 'mean')
14.MultiLabelSoftMarginLoss
功能:SoftMarginLoss多标签版本。
torch.nn.MultiLabelSoftMarginLoss(weight: Optional[torch.Tensor] = None, size_average=None, reduce=None, reduction: str = 'mean')
15.nn.CosineEmbeddingLoss
功能:采用余弦相似度计算两个输入的相似性。
torch.nn.CosineEmbeddingLoss(margin: float = 0.0, size_average=None, reduce=None, reduction: str = 'mean')
16.MultiMarginLoss
功能:计算多分类的折页损失。
torch.nn.MultiMarginLoss(p: int = 1, margin: float = 1.0, weight: Optional[torch.Tensor] = None, size_average=None, reduce=None, reduction: str = 'mean')
17.TripletMarginLoss
功能:三元组损失,人脸验证中常用。
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')
18.CTCLoss
功能:计算CTC损失,解决时序类数据的分类。
torch.nn.CTCLoss(blank: int = 0, reduction: str = 'mean', zero_infinity: bool = False)