1. 标签平滑处理的必要性
在深度学习样本训练的过程中,我们采用one-hot标签去进行计算交叉熵损失时,只考虑到训练样本中正确的标签位置(one-hot标签为1的位置)的损失,而忽略了错误标签位置(one-hot标签为0的位置)的损失。这样一来,模型可以在训练集上拟合的很好,但由于其他错误标签位置的损失没有计算,导致预测的时候,预测错误的概率增大。为了解决这一问题,标签平滑的正则化方法便应运而生。
2. 什么是Label Smoothing
Lable Smoothing
是分类问题中错误标注的一种解决方法。
对于分类问题,特别是多分类问题,常常把向量转换成one-hot-vector
对于损失函数,我们需要用预测概率去拟合真实概率,而拟合one-hot的真实概率函数会带来两个问题:
- 无法保证模型的泛化能力,容易造成过拟合;
- 全概率和0概率鼓励所属类别和其他类别之间的差距尽可能加大,而由梯度有界可知,这种情况很难适应。会造成模型过于相信预测的类别。
(1). 传统的softmax公式如下
其中
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)损失:
通过上面两个公式,我们可以很轻松的得到m mm个样本的损失
(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 ,即
则我们可以求得当前单个样本的
l
o
s
s
loss
loss ,即
计算结果为:
可以发现没有标签平滑计算的损失只考虑正确标签位置的损失,而不考虑其他标签位置的损失,这就会出现一个问题,即不考虑其他错误标签位置的损失,这会使得模型过于关注增大预测正确标签的概率,而不关注减少预测错误标签的概率,最后导致的结果是模型在自己的训练集上拟合效果非常良好,而在其他的测试集结果表现不好,即过拟合,也就是说模型泛化能力差。
(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
y
y 就是我们经过平滑操作后得到的标签,接着我们就可以求平滑后该样本的交叉熵损失了
计算结果为:
此时可以看出,平滑过后的样本交叉熵损失就不仅考虑到了训练样本中正确的标签位置(one-hot标签为1的位置)的损失,也稍微考虑到其他错误标签位置(one-hot标签为0的位置)的损失,导致最后的损失增大,导致模型的学习能力提高,即要下降到原来的损失,就得学习的更好,也就是迫使模型往增大正确分类概率并且同时减小错误分类概率的方向前进。
如果分类准确,交叉熵损失函数的结果是0(即上式中p和y一致的情况),否则交叉熵为无穷大。也就是说交叉熵对分类正确给的是最大激励。换句话说,对于标注数据来说,这个时候我们认为其标注结果是准确的(不然这个结果就没意义了)。但实际上,有一些标注数据并不一定是准确的。那么这时候,使用交叉熵损失函数作为目标函数并不一定是最优的。
对于这个问题,我们还可以这么去理解。在分类任务中,我们通常对类别标签的编码使用[0,1,2,…]这种形式。在深度学习中,通常在全连接层的最后一层,加入一个softmax来计算输入数据属于每个类别的概率,并把概率最高的作为这个类别的输入,然后使用交叉熵作为损失函数。这会导致模型对正确分类的情况奖励最大,错误分类惩罚最大。如果训练数据能覆盖所有情况,或者是完全正确,那么这种方式没有问题。但事实上,这不可能。所以这种方式可能会带来泛化能力差的问题,即过拟合。
(三)、标签平滑的公式
假设
y
y
y 为当前样本one-hot后的标签,则标签平滑公式可表述为:
其中
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概率小),即错误的分类概率输出小。