标签平滑 Label Smoothing:缓解过自信的预测分布
什么是标签平滑
标签平滑是一种正则化技术,主要用于缓解分类模型在训练过程中产生的过度自信问题。在标准分类任务中,我们使用独热编码标签训练模型,这会促使网络对正确类别输出极高的概率,而对其他类别输出极低的概率。这种过置信的预测不仅容易导致过拟合,还会降低模型的泛化能力和校准度。
标签平滑通过软化真实标签,将原本为 1 的正确类别概率从 1.0 降低一点,并将原本为 0 的错误类别概率略微提高,从而在目标分布中引入一定的不确定性。这迫使模型学习更加平滑的判断边界,输出的概率分布更接近真实的置信度。
为什么需要标签平滑
过自信预测的危害
当模型对某个预测极度自信时,可能出现以下问题:
- 过拟合训练数据:模型只记住样本特征与类别之间的硬性映射,对噪声或对抗样本鲁棒性差。
- 校准能力下降:模型输出的置信度无法真实反映其预测正确的概率,在需要可靠概率估计的任务中表现糟糕。
- 泛化误差增大:极度自信的 softmax 输出梯度很小,训练后期容易陷入局部最优,导致测试性能不升反降。
标签平滑的核心思想
标签平滑最初在 Inception-v2 论文中提出,其核心是将真实标签分布替换为一个混合分布:
[ y' = (1 - \alpha) \cdot y + \alpha \cdot u ]
其中 ( y ) 是原始的独热向量,( u ) 是均匀分布(或任何先验分布),( \alpha ) 是平滑系数,通常取一个很小的值(如 0.1)。这样,真实类别不再独占全部概率质量,而是与所有类别共享一小部分概率。
标签平滑的数学原理
标准交叉熵损失
对于 ( K ) 类分类问题,标准交叉熵损失定义为:
[ L = -\sum_{k=1}^{K} y_k \log(p_k) ]
其中 ( y_k ) 是真实标签的独热表示(正确类别对应的分量为 1,其余为 0),( p_k ) 是模型预测的概率。这让正确类别的对数概率最大化,错误类别完全不参与损失计算。
加入标签平滑后的损失
使用平滑系数 ( \alpha ) 后,新的目标标签变为:
[ y_k^{\text{LS}} = \begin{cases} 1 - \alpha + \frac{\alpha}{K}, & \text{if } k = \text{true_class} \[4pt] \frac{\alpha}{K}, & \text{otherwise} \end{cases} ]
标签平滑后的交叉熵损失为:
[ L_{\text{LS}} = -\sum_{k=1}^{K} y_k^{\text{LS}} \log(p_k) ]
展开可得:
[ L_{\text{LS}} = -(1 - \alpha) \log(p_{\text{true}}) - \frac{\alpha}{K} \sum_{k=1}^{K} \log(p_k) ]
第一项与标准交叉熵类似,但权重变为 ( (1-\alpha) )。第二项是所有类别对数概率的平均,相当于一个熵正则项,鼓励模型对所有类别保留一定的不确定性。
梯度视角下的平滑效应
未平滑时,当正确类别的预测概率接近 1 时,损失梯度几乎为零,模型会停止学习其他类别之间的区分。而标签平滑引入的均匀分布分量会产生一个恒定的梯度,推动错误类别的概率也略微升高,从而防止 logit 的值趋于无穷大。这等效于对 logit 施加了权重衰减或范数约束。
标签平滑的实际效果
改善模型校准
校准度(calibration)衡量预测置信度与真实准确率的一致性。标签平滑可显著降低预期校准误差,使模型输出的概率可以直接解释为可信度。实验表明,使用平滑训练的模型在保留准确率的同时,置信度分布更合理。
提高泛化能力
在 ImageNet、CIFAR-100 等基准测试中,添加标签平滑通常能带来一定的准确率提升。更关键的是,模型对对抗样本的鲁棒性增强,网络特征的类内间距被压缩,类间间距更明显。
充当强正则化器
标签平滑可以看作是一种知识蒸馏的特例,它将均匀分布视为一种简单的教师信号。它抑制了最大 logit 的增长,相当于为 softmax 温度缩放提供了隐式修正。
不同框架中的实现
PyTorch 实现
PyTorch 的 CrossEntropyLoss 自 1.10 版本起内置了 label_smoothing 参数:
import torch.nn as nn
criterion = nn.CrossEntropyLoss(label_smoothing=0.1)
# 使用时直接传入原始整数标签即可,无需手动构造平滑标签
如果你使用的版本较低,可以手动实现:
import torch
import torch.nn.functional as F
def cross_entropy_with_label_smoothing(logits, targets, smoothing=0.1):
n_classes = logits.size(-1)
# 构造平滑标签
with torch.no_grad():
true_dist = torch.zeros_like(logits)
true_dist.fill_(smoothing / (n_classes - 1))
true_dist.scatter_(1, targets.unsqueeze(1), 1.0 - smoothing)
return torch.mean(torch.sum(-true_dist * F.log_softmax(logits, dim=-1), dim=-1))
TensorFlow / Keras 实现
在 TensorFlow 中,可以直接使用 CategoricalCrossentropy 并设置 label_smoothing 参数:
import tensorflow as tf
loss_fn = tf.keras.losses.CategoricalCrossentropy(label_smoothing=0.1)
# 注意:标签需要是独热编码形式,或使用 sparse 版本
Keras 模型编译时直接传入即可:
model.compile(loss='categorical_crossentropy', # 但不支持参数
...)
# 建议使用:
model.compile(loss=tf.keras.losses.CategoricalCrossentropy(label_smoothing=0.1),
optimizer='adam')
手动实现(通用算法)
无论何种框架,核心都是构造平滑后的目标向量。下面给出 NumPy 风格的伪代码:
def smooth_labels(labels, factor, num_classes):
# labels: 整数类标索引数组
smooth_labels = np.full((len(labels), num_classes), factor / num_classes)
smooth_labels[np.arange(len(labels)), labels] = 1 - factor + factor / num_classes
return smooth_labels
然后使用标准的 softmax 交叉熵计算损失即可。
超参数选择指南
平滑系数 α 的取值
- 常用值:0.05 ~ 0.1。在 ImageNet 分类中,0.1 被广泛使用并验证有效。
- 太大(如 0.3 以上):会过度模糊标签,导致模型无法充分学习类别间的区分特征,准确率下降。
- 太小(如 0.01):正则化效果微弱,几乎等同于不使用平滑。
- 策略:建议从 0.1 开始实验,根据验证集校准误差和准确率进行调整。
平滑分布的选择
默认使用均匀分布是最简单合理的选择。但在某些场景下,可以使用先验知识构造非均匀的平滑分布,例如类别之间的相似性矩阵,或从另一个预训练模型中获得的软标签,这便演化为知识蒸馏方法。
常见问题与误区
标签平滑会导致准确率下降吗?
在训练集上准确率可能会轻微下降,因为模型不再完全拟合硬标签。但在验证集和测试集上,准确率通常持平或提升,更为关键的是模型校准度和鲁棒性的改善。
能否与 mixup 等数据增强同时使用?
完全可以,而且效果往往更好。Mixup 和标签平滑分别从输入空间和输出空间引入扰动,具有一定的互补性。
二分类问题如何使用标签平滑?
对于二分类,通常输出单个 sigmoid 概率。标签平滑可类比操作:将正例标签平滑为 ( 1 - \alpha ),负例标签平滑为 ( \alpha )(假设适当缩放)。也可以在 BCEWithLogitsLoss 类方法中手动构建平滑后的概率目标。
标签平滑是否会与早停冲突?
不会直接冲突,但平滑后的损失数值通常比硬标签损失略大,且下降过程更平稳。建议保持同样的早停标准(如验证损失)即可。
拓展思考
标签平滑看似简单,却揭示了模型训练中的一个深刻现象:硬目标会使模型过于关注正确类别的置信度,而忽略了类别之间的结构关系。通过软化目标,我们实际上引入了一种结构先验——不同类别之间并非完全独立,模型应当在预测时保留适度的怀疑。这一思想在现代深度学习的正则化技术中反复出现,包括知识蒸馏、对抗训练、以及最新的视觉语言模型对齐方法。