平滑smooth
import numpy as np
import matplotlib.pyplot as plt
def smooth(y, f=0.05):
# Box filter of fraction f
nf = round(len(y) * f * 2) // 2 + 1 # number of filter elements (must be odd)
p = np.ones(nf // 2) # ones padding
yp = np.concatenate((p * y[0], y, p * y[-1]), 0) # y padded
return np.convolve(yp, np.ones(nf) / nf, mode='valid') # y-smoothed
# 创建一个带有噪声的数据
np.random.seed(0)
y = np.sin(np.linspace(0, 20, 100)) + np.random.normal(scale=0.5, size=100)
# 应用平滑函数
y_smoothed = smooth(y, f=0.1)
# 绘制原始数据和平滑后的数据
plt.figure(figsize=(10, 5))
plt.plot(y, label='Original')
plt.plot(y_smoothed, label='Smoothed', linewidth=2)
plt.legend()
plt.show()
效果:
一、什么是标签平滑(label smoothing)
标签平滑也可以称之为标签平滑归一化:Label Smoothing Regularization (LSR),通常应用于文本分类任务,像L2和 dropout 等一样,它是一种正则化的方法,只不过这种方法是通过在 label 中添加噪声,从而实现对模型的约束。目的是防止模型在训练时过于自信地预测标签,防止过拟合,提高模型的泛化能力。
有关标签可以参考如下论文(https://arxiv.org/pdf/1512.00567.pdf)
二、标签平滑(label smoothing)的作用
没有对比就没有伤害,标签平滑的提出主要是为了解决传统中one-hot标签(也可称之为hard label)形式存在的问题,结合下面这张图片进行具体说明:
假设现在是一个6分类的任务,文本的类别标签(y)是鸟,损失函数使用的是分类任务中常用的交叉熵损失函数,结合交叉熵损失函数的公式可以发现,最终的loss值就只和y为1的那一维度有关。这样会造成一些问题:
问题一:在神经网络学习的过程中,鼓励模型预测为目标类别的概率趋近1,非目标类别的概率趋近0,使得模型向预测正确与错误标签的logit差值无限增大的方向学习,而过大的logit差值会使模型缺乏适应性,对它的预测过于自信。在训练数据不足以覆盖所有情况下,这就会导致网络过拟合,泛化能力差。
问题二:面对易混淆的分类任务、有噪音(误打标)的数据集时,更容易受影响
为了解决以上问题,提出了标签平滑(label smoothing),把 one-hot 标签(hard label)转换为 soft label 的形式。
三、标签平滑(label smoothing)的数学形式
标签平滑用更新的标签向量 y i y_{i} yi 来替换传统的ont-hot编码的标签向量 y o n e − h o t y_{one-hot} yone−hot
y i = y o n e − h o t ( 1 − α ) + α / K y_{i}=y_{one-hot}(1-\alpha)+\alpha/K\\ yi=yone−hot(1−α)+α/K
其中K指类别的个数, α \alpha α 是一个较小的超参数(一般取0.1)。
四、代码实现
import torch
import torch.nn as nn
import torch.nn.functional as F
class LabelSmoothingLoss(nn.Module):
def __init__(self, classes, smoothing=0.1, dim=-1):
"""
初始化标签平滑损失函数。
:param classes: 类别的总数。
:param smoothing: 标签平滑的系数,默认为0.1。
:param dim: 计算softmax的维度,默认为最后一个维度。
"""
super(LabelSmoothingLoss, self).__init__()
self.confidence = 1.0 - smoothing # 置信度,即非平滑部分的权重
self.smoothing = smoothing # 平滑系数
self.cls = classes # 类别总数
self.dim = dim # softmax操作的维度
def forward(self, pred, target):
"""
计算标签平滑损失。
:param pred: 模型的预测输出,未经softmax处理。
:param target: 真实的标签。
:return: 平滑损失的平均值。
"""
# 对预测结果应用log softmax
pred = pred.log_softmax(dim=self.dim)
# 生成平滑的目标分布
with torch.no_grad():
true_dist = torch.zeros_like(pred) # 创建与预测相同形状的张量
# 对所有类别填充平滑值
true_dist.fill_(self.smoothing / (self.cls - 1))
# 在真实类别的位置上设置置信度
true_dist.scatter_(1, target.data.unsqueeze(1), self.confidence)
# 计算平滑损失
return torch.mean(torch.sum(-true_dist * pred, dim=self.dim))
# 测试代码
def test_label_smoothing_loss():
# 设置随机种子以获得可重复的结果
torch.manual_seed(0)
# 创建一个LabelSmoothingLoss实例
label_smoothing_loss = LabelSmoothingLoss(classes=5, smoothing=0.1)
# 随机生成一些模拟的预测值和真实标签
preds = torch.randn(3, 5) # 模拟的预测值(batch_size=3, num_classes=5)
targets = torch.tensor([1, 0, 3]) # 真实标签
# 计算标签平滑损失
loss = label_smoothing_loss(preds, targets)
print("Label Smoothing Loss:", loss.item())
# 运行测试
test_label_smoothing_loss()
五、标签平滑(label smoothing)的优缺点
1、优点
1)可以防止网络模型变得"过于自信",也有一定的抗噪能力
2)弥补了简单分类中监督信号不足(信息熵比较少)的问题,增加了信息量
3)提供了训练数据中类别之间的关系(数据增强)
4)可能增强了模型泛化能力
2、缺点
1)单纯地添加随机噪音,也无法反映标签之间的关系,因此对模型的提升有限,甚至有欠拟合的风险
2)使用标签平滑可能需要在提高泛化能力和保持高确定性预测之间进行权衡
3)由于标签平滑增加了目标标签的不确定性,模型可能需要更多的时间来学习从特征到标签的映射
六、适用
使用标签平滑(Smooth BCE)
1)真实场景下,尤其数据量大的时候数据里是会有噪音的,为了避免模型错误的学到这些噪音可以加入 label smoothing。
2)避免模型太自信了,有时候我们训练一个模型会发现给出相当高的分值,但有时候我们不希望模型太自信了(可能会导致过拟合等问题),希望提高模型的学习难度,可以引入 label smoothing。
3)分类的中会有一些模糊的case,利用soft-target可以给两类都提供监督效果(这时候对应的soft label值不是一样的)
-
过度自信的模型:
- 当模型对其预测过于自信时(即预测输出接近于0或1),可能会导致在新数据上的泛化能力降低。标签平滑可以通过减轻模型的自信度来改善这种情况。
-
训练数据中存在噪声或标签错误:
- 如果训练数据不是完全可靠,使用标签平滑可以使模型对潜在的标签错误更加鲁棒。
-
提高泛化能力:
- 在许多情况下,特别是在复杂模型和大规模数据集的场景中,标签平滑有助于提高模型的泛化性能。
-
当模型训练陷入局部最优:
- 标签平滑可以改变损失景观,有助于模型跳出局部最优,找到更好的解。
避免使用标签平滑(Smooth BCE)
在知识蒸馏时教师网络的label不建议进行标签平滑,会使效果变差
-
简单任务或数据集:
- 对于简单的分类任务或小型数据集,模型可能本身就足够泛化,此时使用标签平滑可能不会带来显著的改善。
-
需要非常精确的分类:
- 在一些需要高度精确分类的应用中(例如医学图像诊断),使用标签平滑可能会导致性能下降,因为它使模型对任何一个类别都不会过于自信。
-
评估指标对确定性敏感:
- 如果使用的性能评估指标对分类的确定性非常敏感(例如精确率或召回率),标签平滑可能会对这些指标的性能产生负面影响。
-
在最后阶段的模型微调:
-
在训练的后期阶段,尤其是在进行微调时,使用标签平滑可能不那么有效,因为此时模型已经较好地适应了训练数据。
-
如果使用的性能评估指标对分类的确定性非常敏感(例如精确率或召回率),标签平滑可能会对这些指标的性能产生负面影响。
-
-
在最后阶段的模型微调:
- 在训练的后期阶段,尤其是在进行微调时,使用标签平滑可能不那么有效,因为此时模型已经较好地适应了训练数据。