数据决定了模型的上限,而我们所建立的模型只不过是在不断逼近这个上限。但是对于我们在各个地方收集到的数据,总的不会是十分的完美,要么是存在缺失值、异常值,要么是样本数据差距过大。比如一个二分类问题,训练集中有98个正样本,但只有2个负样本,这种类别数据不均衡的情况下,如果不做不平衡样本的处理,会导致模型在数目较少的类别上出现“欠学习”现象,即可能在测试集上完全丧失对负样本的预测能力。
解决不平衡样本问题一般有两种方法:
1.数据层面处理方法
数据扩充:我最开始的接触机器学习的时候,这是我最经常用的一个办法。对于样本不平衡问题,最简单的办法就是多加一点那些样本少的数据呗,如果有就再去找一些数据,没有就自己通过一些合理的操作做一些数据。对于图像数据,像翻转、旋转、随机裁剪、随机缩放等都可以增加数据,并且可能在不同的应用场景还会提高模型的泛化能力。但是要注意对图像数据操作的场景,否则可能会丢失一些图片潜在信息(比如不合理的旋转、低分辨率的图像加入噪声)。
数据(重)采样:简单的数据重采样方法分为数据上采样(over-sampling
、up-sampling
,也叫数据过采样) 或 也叫数据欠采样数据下采样(under-sampling
、down-sampling
)。对于样本数目较少的类别,可用数据过采样方法,即通过复制方法使得该类图像数目增至与样本最多类的样本数一致。对于深度学习和计算机视觉领域的任务来说,下采样并不是直接随机丢弃一部分图像,正确的下采样策略是: 在批处理训练时(数据加载阶段 dataloader
),对于样本较多的类别,严格控制每批batch随机抽取的图像数目,使得每批读取的数据中正负样本是均衡的(类别均衡)。以二分类任务为例,假设原始数据分布情况下每批处理训练正负样本平均数量比例为 9:1
,如仅使用下采样策略,则可在每批随机挑选训练样本时每 9
个正样本只取 1
个作为该批训练集的正样本,负样本选择策略不变,这样可使得每批读取的训练数据中正负样本时平衡的。
2.算法层面处理方法
修改损失函数:类别不平衡问题的本质是导致样本数目较少的类别出现“欠学习”这一机器学习现象,直观表现是较小样本的损失函数权重占比也较少。一个很自然的解决办法是增加小样本错分的惩罚代价,并将此代价直接体现在目标函数(损失函数)里,这就是“代价敏感”的方法。“代价敏感”方法的本质可以理解为调整模型在小类别上的注意力。
Focal Loss:Focal Loss 是在二分类问题的交叉熵(CE)损失函数的基础上引入的,主要是为了解决 one-stage
目标检测中正负样本比例严重失衡的问题,该损失函数降低了大量简单负样本在训练中所占的权重,也可理解为一种困难样本挖掘,经实践证明 Focal Loss
在 one-stage
目标检测中还是很有效的,但是在多分类中不一定有效。如果不在意边界上的过拟合,Focal Loss可以一定程度上处理不易学习样本,但是并不能解决样本不均衡。
损失函数加权:除了 Focal Loss
这种高明的损失函数策略外,针对图像分类问题,还有一种简单直接的损失函数加权方法,即在计算损失函数过程中,对每个类别的损失做加权处理
weights = torch.FloatTensor([1, 1, 8, 8, 4]) # 类别权重分别是 1:1:8:8:4
# pos_weight_weight(tensor): 1-D tensor,n 个元素,分别代表 n 类的权重,
# 为每个批次元素的损失指定的手动重新缩放权重,
# 如果你的训练样本很不均衡的话,是非常有用的。默认值为 None。
criterion = nn.BCEWithLogitsLoss(pos_weight=weights).cuda()
到目前对与样本不平衡问题也有一些争论,比如有人认为当某类的样本数严重不足时,基本没有任何可能训练出一个靠谱的模型。如果样本无法补充,则应考虑其他方法。另外样本量如果不均衡,很可能说明这些类别的比例就是如此。如果强行拉到一致,那些区分并不明显的样品可能造成严重误判。如果98%是正样本,2%是负样本,那么只需全判为正样本,就能得到98%的高准确率。实际上,在经过充分训练后,那些区分比较明显的负样本也是可以准确识别的。不能识别的是区分不明显的样本,那么这些样本是否是标注正确,应该要重新考证,再行研讨方案。
部分引用: