目录
标签平滑(label smoothing)出自GoogleNet v3
关于one-hot编码的详细知识请见:One-hot编码
1.标签平滑主要解决什么问题?
传统的one-hot编码会带来的问题:无法保证模型的泛化能力,使网络过于自信会导致过拟合。
全概率和0概率鼓励所属类别和其他类别之间的差距尽可能加大,而由梯度有界可知,这种情况很难adapt。会造成模型过于相信预测的类别。而标签平滑可以缓解这个问题。
2.标签平滑是怎么操作的?
标签平滑是把one-hot中概率为1的那一项进行衰减,避免过度自信,衰减的那部分的自信被平均分到每一个类别中。
例如:
一个4分类任务,label = (0,1,0,0)
labeling smoothing = (,1-0.001+
,
,
)=(0.00025,0.99925,0.00025,0.00025)
其中,概率加起来等于1。
3.标签平滑公式
交叉熵(Cross Entropy):
其中,q为标签值,p为预测结果,k为类别。即q为one-hot编码结果。
labeling smothing:将q进行标签平滑变为q',让模型输出的p分布去逼近q'。
,其中u(k)为一个概率分布,这里采用均匀分布(
),则得到
其中,为原分布q, ϵ ∈(0,1)是一个超参数。
由以上公式可以看出,这种方式使label有 ϵ 概率来自于均匀分布, 1−ϵ 概率来自于原分布。这就相当于在原label上增加噪声,让模型的预测值不要过度集中于概率较高的类别,把一些概率放在概率较低的类别。
故标签平滑后的交叉熵损失函数为:
那这个公式是怎么得来的呢?
将q'(k|x)带入交叉熵损失函数:
这样就得到了标签平滑公式。
4.代码实现
class LabelSmoothingCrossEntropy(nn.Module):
def __init__(self, eps=0.1, reduction='mean', ignore_index=-100):
super(LabelSmoothingCrossEntropy, self).__init__()
self.eps = eps
self.reduction = reduction
self.ignore_index = ignore_index
def forward(self, output, target):
c = output.size()[-1]
log_pred = torch.log_softmax(output, dim=-1)
if self.reduction == 'sum':
loss = -log_pred.sum()
else:
loss = -log_pred.sum(dim=-1)
if self.reduction == 'mean':
loss = loss.mean()
return loss * self.eps / c + (1 - self.eps) * torch.nn.functional.nll_loss(log_pred, target,
reduction=self.reduction,
ignore_index=self.ignore_index)