损失函数
了解损失函数的基本概念。
损失函数用于评估我们的算法对数据集的建模效果。它计算单个训练样本中模型预测输出与真实标签(ground truth)之间的差异,也被称为误差函数。
它反映了预测输出偏离期望输出的程度。我们可以将损失函数理解为未能得到正确输出所付出的“惩罚”。
大多数优化问题都会使用损失函数,其主要目标是最小化损失,从而最大化模型的准确性。损失越低,说明模型表现越好。
给定以下合成数据,我们可以通过以下步骤计算金属价格预测($/盎司)的总损失:
- 将预测值与实际值相减;
- 取差值的绝对值。
| 金属 | 预测值 | 实际值 | 总损失 |
|---|---|---|---|
| 黄金 铂金 | 1995.80 998.32 | 1998.30 999.34 | 3.52(黄金2.50,铂金1.02) |
| 黄金 铂金 | 2003.12 999.34 | 1998.30 999.34 | 4.82(黄金4.82,铂金0) |
| 黄金 铂金 | 1998.05 995.81 | 1998.30 999.34 | 3.78(黄金0.25,铂金3.53) |
注意:损失函数不关心误差的方向,仅关注偏差大小。
PyTorch Image Models 提供了以下标准损失函数:
LabelSmoothingCrossEntropySoftTargetCrossEntropy
LabelSmoothingCrossEntropy 函数
LabelSmoothingCrossEntropy 函数的工作方式与负对数似然损失(NLL Loss)相同,但多了一个 smoothing 参数。NLL 损失的公式为:
下图展示了负对数似然损失的取值范围:
以下预测及其对应的总 NLL 损失值,展示了真实标签与负对数似然损失之间的关系。
注意:加粗文字表示正确的类别(真实标签),每个类别下方的数值代表该类别的预测概率。
| 类别1 | 类别2 | 类别3 | 总损失 |
|---|---|---|---|
| 0.71 | 0.26 | 0.04 | 0.34 |
| 0.49 | 0.49 | 0.02 | 0.71 |
| 0.02 | 0.00 | 0.98 | 0.02 |
假设某图像的真实类别为类别1,模型预测结果如下:
- 类别1(真实类别):0.71
- 类别2:0.26
- 类别3:0.04
此时,负对数似然损失值为 0.34。
注意:对正确类别的预测置信度越高,总损失越低。
标签平滑(Label Smoothing)
标签平滑是机器学习中处理数据集中错误标签的一种特殊技术。
LabelSmoothingCrossEntropy 类提供了一个 smoothing 参数用于此类场景。该参数接受一个介于 0 和 1 之间的浮点数。当数据集中可能存在较多错误标签时,应设置较高的 smoothing 值。
smoothing 参数会在预测正确时增加损失,在预测错误时减少损失,从而使模型在预测出错时受到的“惩罚”更轻。以下代码通过比较 smoothing=0.0 和 smoothing=0.1 的结果来说明这一点:
1import timm 2import torch 3import torch.nn.functional as F 4from timm.loss import LabelSmoothingCrossEntropy 5 6x = torch.eye(2) 7x_i = 1 - x 8y = torch.arange(2) 9 10# smoothing 值为 0.0 11print('Tensor for smoothing value of 0.0 is:') 12print(LabelSmoothingCrossEntropy(0.0)(x,y), LabelSmoothingCrossEntropy(0.0)(x_i,y)) 13 14# smoothing 值为 0.1 15print('Tensor for smoothing value of 0.1 is:') 16print(LabelSmoothingCrossEntropy(0.1)(x,y), LabelSmoothingCrossEntropy(0.1)(x_i,y))
每次调用返回一个张量,表示经过标签平滑后的平均损失。
SoftTargetCrossEntropy 函数
SoftTargetCrossEntropy 是一种特殊的 log_softmax 函数,通常与 mixup 数据增强方法配合使用。
可通过调用 mixup_target 函数实现标签平滑,并可调节目标标签混合的程度:
1y = mixup_target(torch.tensor([1,4]), 5, lam=0.7)
target:目标张量;num_classes:类别总数;lam:Cutmix 的 lambda 值(默认为 1.0);smoothing:平滑系数(默认为 0.0);device:运行设备(GPU 或 CPU,默认为cuda)。
1import timm 2import torch 3import torch.nn.functional as F 4from timm.loss import SoftTargetCrossEntropy 5from timm.data.mixup import mixup_target 6 7x = torch.tensor([[[0,1.,0,0,1.]], [[1.,1.,1.,1.,1.]]], device='cpu') 8 9# 使用默认平滑值 0.0 10print('Tensor for smoothing value of 0.0 is:') 11y1 = mixup_target(torch.tensor([1,4], device='cpu'), 5, lam=0.7, device='cpu') 12print(y1) 13 14# 使用平滑值 0.1 15print('Tensor for smoothing value of 0.1 is:') 16y2 = mixup_target(torch.tensor([1,4], device='cpu'), 5, lam=0.7, smoothing=0.1, device='cpu') 17print(y2)
注意:如果在没有 GPU 的机器上运行,请务必设置
device='cpu'。
对于每个输入张量,该函数返回对应 MixUp 增强后的标签张量,随后可调用 SoftTargetCrossEntropy 函数进行损失计算。
1import timm 2import torch 3import torch.nn.functional as F 4from timm.loss import SoftTargetCrossEntropy 5from timm.data.mixup import mixup_target 6 7x = torch.tensor([[[0,1.,0,0,1.]], [[1.,1.,1.,1.,1.]]], device='cpu') 8 9# 使用默认平滑值 0.0 10y = mixup_target(torch.tensor([1,4], device='cpu'), 5, lam=0.7, device='cpu') 11 12# 输出张量1和张量2的平均损失 13print('The mean loss output for tensor 1 and 2 is:') 14print(SoftTargetCrossEntropy()(x[0],y),SoftTargetCrossEntropy()(x[1],y))
输出结果为一个张量,表示计算得到的平均损失值。