目录
1.标签平滑主要解决什么问题?
2.标签平滑是怎么操作的?
3.标签平滑公式
4.代码实现
标签平滑(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):![H(q,p)=-\sum_{k=1}^{k}log(p_k)q_k](https://latex.csdn.net/eq?H%28q%2Cp%29%3D-%5Csum_%7Bk%3D1%7D%5E%7Bk%7Dlog%28p_k%29q_k)
其中,q为标签值,p为预测结果,k为类别。即q为one-hot编码结果。
labeling smothing:将q进行标签平滑变为q',让模型输出的p分布去逼近q'。
,其中u(k)为一个概率分布,这里采用均匀分布(
),则得到![q'(k|x)=(1-\varepsilon )\delta _{k,y} +\frac{\varepsilon }{k}](https://latex.csdn.net/eq?q%27%28k%7Cx%29%3D%281-%5Cvarepsilon%20%29%5Cdelta%20_%7Bk%2Cy%7D%20+%5Cfrac%7B%5Cvarepsilon%20%7D%7Bk%7D)
其中,
为原分布q, ϵ ∈(0,1)是一个超参数。
由以上公式可以看出,这种方式使label有 ϵ 概率来自于均匀分布, 1−ϵ 概率来自于原分布。这就相当于在原label上增加噪声,让模型的预测值不要过度集中于概率较高的类别,把一些概率放在概率较低的类别。
故标签平滑后的交叉熵损失函数为:![H(q',p)=-\sum_{k=1}^{k}logp(k)q'(k)=(1-\varepsilon )H(q,p)+\varepsilon H(u,p)](https://latex.csdn.net/eq?H%28q%27%2Cp%29%3D-%5Csum_%7Bk%3D1%7D%5E%7Bk%7Dlogp%28k%29q%27%28k%29%3D%281-%5Cvarepsilon%20%29H%28q%2Cp%29+%5Cvarepsilon%20H%28u%2Cp%29)
那这个公式是怎么得来的呢?
将q'(k|x)带入交叉熵损失函数:
![H(q',p)=-\sum_{k=1}^{k}log(p_k)q'_k](https://latex.csdn.net/eq?H%28q%27%2Cp%29%3D-%5Csum_%7Bk%3D1%7D%5E%7Bk%7Dlog%28p_k%29q%27_k)
![=-\sum_{k=1}^{k}log(p_k)[(1-\varepsilon )\delta _{k,y}+\frac{\varepsilon }{k}]](https://latex.csdn.net/eq?%3D-%5Csum_%7Bk%3D1%7D%5E%7Bk%7Dlog%28p_k%29%5B%281-%5Cvarepsilon%20%29%5Cdelta%20_%7Bk%2Cy%7D+%5Cfrac%7B%5Cvarepsilon%20%7D%7Bk%7D%5D)
![=-\sum_{k=1}^{k}log(p_k)(1-\varepsilon )\delta _{k,y}+[-\sum_{k=1}^{k}log(p_k)\frac{\varepsilon }{k}]](https://latex.csdn.net/eq?%3D-%5Csum_%7Bk%3D1%7D%5E%7Bk%7Dlog%28p_k%29%281-%5Cvarepsilon%20%29%5Cdelta%20_%7Bk%2Cy%7D+%5B-%5Csum_%7Bk%3D1%7D%5E%7Bk%7Dlog%28p_k%29%5Cfrac%7B%5Cvarepsilon%20%7D%7Bk%7D%5D)
![=(1-\varepsilon )*[-\sum_{k=1}^{k}log(p_k)\delta _{k,y}]+\varepsilon *[-\sum_{k=1}^{k}log(p_k)\frac{1}{k}]](https://latex.csdn.net/eq?%3D%281-%5Cvarepsilon%20%29*%5B-%5Csum_%7Bk%3D1%7D%5E%7Bk%7Dlog%28p_k%29%5Cdelta%20_%7Bk%2Cy%7D%5D+%5Cvarepsilon%20*%5B-%5Csum_%7Bk%3D1%7D%5E%7Bk%7Dlog%28p_k%29%5Cfrac%7B1%7D%7Bk%7D%5D)
![=(1-\varepsilon )*H(q,p)+\varepsilon *H(u,p)](https://latex.csdn.net/eq?%3D%281-%5Cvarepsilon%20%29*H%28q%2Cp%29+%5Cvarepsilon%20*H%28u%2Cp%29)
这样就得到了标签平滑公式。
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)