深度学习中的标签平滑正则化(Label Smoothing Regularization)方法原理详解

论文:https://arxiv.org/pdf/1512.00567.pdf

(一)、为什么有标签平滑正则化(Label Smoothing Regularization, LSR)的方法?
在深度学习样本训练的过程中,我们采用one-hot标签去进行计算交叉熵损失时,只考虑到训练样本中正确的标签位置(one-hot标签为1的位置)的损失,而忽略了错误标签位置(one-hot标签为0的位置)的损失。这样一来,模型可以在训练集上拟合的很好,但由于其他错误标签位置的损失没有计算,导致预测的时候,预测错误的概率增大。为了解决这一问题,标签平滑的正则化方法便应运而生。

(二)、标签平滑是如何实现的?
(1). 传统的softmax公式如下: p i = e z i ∑ i = 1 n e z i (2.1) {p_{i}=\frac{e^{z_i}}{\sum_{i=1}^n{e^{z_i}}}\tag{2.1}} pi=i=1neziezi(2.1)其中 p i p_i pi为当前样本属于类别 i i i的概率, z i z_i zi指的是当前样本的对应类别 i i i l o g i t logit logit n n n为样本类别总数,则我们可以得到交叉熵(cross entropy)损失: l o s s = − 1 m ∑ k = 1 m ∑ i = 1 n y i l o g p i (2.2) {loss=-\frac{1}{m}\sum_{k=1}^m\sum_{i=1}^n{y_ilogp_i}\tag{2.2}} loss=m1k=1mi=1nyilogpi(2.2)通过上面两个公式,我们可以很轻松的得到 m m m个样本的损失。

(2). 那么有标签平滑的损失计算与没有标签平滑的损失计算具体有什么区别呢?先举个没有标签平滑计算的例子
E x a m p l e 1 Example1 Example1:假设有一批样本,样本类别总数为5,从中取出一个样本,得到该样本的one-hot化后的标签为 [ 0 , 0 , 0 , 1 , 0 ] [0,0,0,1,0] [0,0,0,1,0],假设我们已经得到了该样本进行softmax的概率矩阵 p p p,即 p = [ p 1 , p 2 , p 3 , p 4 , p 5 ] = [ 0.1 , 0.1 , 0.1 , 0.36 , 0.34 ] (2.3) {p=[p_1,p_2,p_3,p_4,p_5]=[0.1,0.1,0.1,0.36,0.34]}\tag{2.3} p=[p1,p2,p3,p4,p5]=[0.1,0.1,0.1,0.36,0.34](2.3)则我们可以求得当前单个样本的 l o s s loss loss,即 l o s s = − ( 0 ∗ log ⁡ 0.1 + 0 ∗ log ⁡ 0.1 + 0 ∗ l o g 0.1 + 1 ∗ l o g 0.36 + 0 ∗ l o g 0.34 ) (2.4) {loss=-(0*\log0.1+0*\log0.1+0*log0.1+1*log0.36+0*log0.34)}\tag{2.4} loss=(0log0.1+0log0.1+0log0.1+1log0.36+0log0.34)(2.4)计算结果为: l o s s = − l o g 0.36 = 1.47 (2.5) {loss=-log0.36=1.47}\tag{2.5} loss=log0.36=1.47(2.5)可以发现没有标签平滑计算的损失只考虑正确标签位置的损失,而不考虑其他标签位置的损失,这就会出现一个问题,即不考虑其他错误标签位置的损失,这会使得模型过于关注增大预测正确标签的概率,而不关注减少预测错误标签的概率,最后导致的结果是模型在自己的训练集上拟合效果非常良好,而在其他的测试集结果表现不好,即过拟合,也就是说模型泛化能力差。

(3). 再举一个标签平滑的例子
E x a m p l e 2 Example2 Example2:假设还是上面那批样本,样本类别总数仍为5,我们还是取出刚才的那个样本,得到该样本的one-hot化后的标签为 [ 0 , 0 , 0 , 1 , 0 ] [0,0,0,1,0] [0,0,0,1,0],仍假设我们已经得到了该样本进行softmax的概率矩阵 p p p,即 p = [ p 1 , p 2 , p 3 , p 4 , p 5 ] = [ 0.1 , 0.1 , 0.1 , 0.36 , 0.34 ] p=[p_1,p_2,p_3,p_4,p_5]=[0.1,0.1,0.1,0.36,0.34] p=[p1,p2,p3,p4,p5]=[0.1,0.1,0.1,0.36,0.34],对于进行标签平滑该怎么做呢?我们先设一个平滑因子为 ϵ = 0.1 \epsilon=0.1 ϵ=0.1,进行如下平滑 y 1 = ( 1 − ϵ ) ∗ [ 0 , 0 , 0 , 1 , 0 ] = [ 0 , 0 , 0 , 0.9 , 0 ] (2.6) {y_1=(1-\epsilon)*[0,0,0,1,0]=[0,0,0,0.9,0]}\tag{2.6} y1=(1ϵ)[0,0,0,1,0]=[0,0,0,0.9,0](2.6) y 2 = ϵ ∗ [ 1 , 1 , 1 , 1 , 1 ] = [ 0.1 , 0.1 , 0.1 , 0.1 , 0.1 ] (2.7) {y_2=\epsilon*[1,1,1,1,1]=[0.1,0.1,0.1,0.1,0.1]}\tag{2.7} y2=ϵ[1,1,1,1,1]=[0.1,0.1,0.1,0.1,0.1](2.7) y = y 1 + y 2 = [ 0.1 , 0.1 , 0.1 , 1.0 , 0.1 ] (2.8) {y=y_1+y_2=[0.1,0.1,0.1,1.0,0.1]}\tag{2.8} y=y1+y2=[0.1,0.1,0.1,1.0,0.1](2.8) y y y就是我们经过平滑操作后得到的标签,接着我们就可以求平滑后该样本的交叉熵损失了 l o s s = − y ∗ l o g p = − [ 0.1 , 0.1 , 0.1 , 1.0 , 0.1 ] ∗ l o g ( [ 0.1 , 0.1 , 0.1 , 0.36 , 0.34 ] ) (2.9) {loss=-y*logp=-[0.1,0.1,0.1,1.0,0.1]*log([0.1,0.1,0.1,0.36,0.34])}\tag{2.9} loss=ylogp=[0.1,0.1,0.1,1.0,0.1]log([0.1,0.1,0.1,0.36,0.34])(2.9)计算结果为: l o s s = 2.63 (3.0) {loss=2.63}\tag{3.0} loss=2.63(3.0)此时可以看出,平滑过后的样本交叉熵损失就不仅考虑到了训练样本中正确的标签位置(one-hot标签为1的位置)的损失,也稍微考虑到其他错误标签位置(one-hot标签为0的位置)的损失,导致最后的损失增大,导致模型的学习能力提高,即要下降到原来的损失,就得学习的更好,也就是迫使模型往增大正确分类概率并且同时减小错误分类概率的方向前进。

(三)、标签平滑的公式
假设 y y y为当前样本one-hot后的标签,则标签平滑公式可表述为: y ′ = ( 1 − ϵ ) ∗ y + ϵ ∗ u (3.1) {y'=(1-\epsilon)*y+\epsilon*u}\tag{3.1} y=(1ϵ)y+ϵu(3.1)其中 y ′ y' y为标签平滑操作后的样本标签, ϵ \epsilon ϵ为平滑因子, u u u 是人为引入的一个固定分布(可以看作是为概率分布引入固定分布的噪声),并且由参数 ϵ \epsilon ϵ控制相对权重。这个 u u u即是对应(二) E x a m p l e 2 Example2 Example2中的 [ 1 , 1 , 1 , 1 , 1 ] [1,1,1,1,1] [1,1,1,1,1]矩阵。

(四)、进行标签平滑的softmax损失的代码实现

def cross_entropy_loss(preds, target, reduction):
    logp = F.log_softmax(preds, dim=1)
    loss = torch.sum(-logp * target, dim=1)
    if reduction == 'none':
        return loss
    elif reduction == 'mean':
        return loss.mean()
    elif reduction == 'sum':
        return loss.sum()
    else:
        raise ValueError(
            '`reduction` must be one of \'none\', \'mean\', or \'sum\'.')
        
def onehot_encoding(labels, n_classes):
    return torch.zeros(labels.size(0), n_classes).to(labels.device).scatter_(
        dim=1, index=labels.view(-1, 1), value=1)
    
def label_smoothing(preds, targets,epsilon=0.1):
	#preds为网络最后一层输出的logits
	#targets为未one-hot的真实标签
    n_classes = preds.size(1)
    device = preds.device
    
    onehot = onehot_encoding(targets, n_classes).float().to(device)
    targets = onehot * (1 - epsilon) + torch.ones_like(onehot).to(
        device) * epsilon / n_classes
    loss = cross_entropy_loss(preds, targets, reduction="mean")
    return loss

(五)、标签平滑的应用场景
只要loss损失函数中涉及到了cross entropy,都可以应用标签平滑处理。

(六)、总结
标签平滑的实质就是促使神经网络中进行softmax激活函数激活之后的分类概率结果向正确分类靠近,即正确的分类概率输出大(对应的one-hot标签为1位置的softmax概率大),并且同样尽可能的远离错误分类(对应的one-hot标签为0位置的softmax概率小),即错误的分类概率输出小。

你可能感兴趣的:(深度学习)