解决类别不平衡:对损失和 sgd 的贡献比例缩放
Posted
技术标签:
【中文标题】解决类别不平衡:对损失和 sgd 的贡献比例缩放【英文标题】:Tackling Class Imbalance: scaling contribution to loss and sgd 【发布时间】:2015-08-09 17:59:36 【问题描述】:(已添加对此问题的更新。)
我是比利时根特大学的研究生;我的研究是关于深度卷积神经网络的情绪识别。我正在使用 Caffe 框架来实现 CNN。
最近我遇到了一个关于班级不平衡的问题。我正在使用大约 9216 个训练样本。 5% 标记为阳性 (1),其余样本标记为阴性 (0)。
我正在使用SigmoidCrossEntropyLoss 层来计算损失。训练时,即使经过几个 epoch,损失也会减少,准确率非常高。这是由于不平衡造成的:网络总是简单地预测负数(0)。 (准确率和召回率都为零,支持这一说法)
为了解决这个问题,我想根据预测-真值组合来衡量对损失的贡献(严厉惩罚假阴性)。我的导师/教练还建议我在通过随机梯度下降 (sgd) 进行反向传播时使用比例因子:该因子与批次中的不平衡有关。仅包含负样本的批次根本不会更新权重。
我只为 Caffe 添加了一个定制层:用于报告其他指标,例如准确率和召回率。我对 Caffe 代码的经验有限,但我在编写 C++ 代码方面拥有丰富的专业知识。
任何人都可以帮助我或指出正确的方向,了解如何调整 SigmoidCrossEntropyLoss 和 Sigmoid 层以适应以下变化:
-
根据预测-真值组合(真阳性、假阳性、真阴性、假阴性)调整样本对总损失的贡献。
根据批次中的不平衡(负数与正数)调整随机梯度下降执行的权重更新。
提前致谢!
更新
我已按照Shai 的建议合并了 InfogainLossLayer。我还添加了另一个自定义层,它根据当前批次中的不平衡构建信息增益矩阵H
。
目前,矩阵配置如下:
H(i, j) = 0 if i != j
H(i, j) = 1 - f(i) if i == j (with f(i) = the frequency of class i in the batch)
我计划在未来尝试不同的矩阵配置。
我已经在 10:1 的不平衡情况下对此进行了测试。结果表明网络现在正在学习有用的东西:(30 epochs 后的结果)
准确度约为。 ~70%(低于 ~97%); 精度约为。 ~20%(从 0% 上调); 召回是大约。 ~60%(从 0% 上调)。这些数字是在大约 20 个 epoch 时达到的,之后没有显着变化。
!!上述结果只是一个概念证明,它们是通过在 10:1 不平衡数据集上训练一个简单的网络获得的。 !!
【问题讨论】:
干得好!您能否详细说明您添加到每批次计算H
的自定义层?
当然,这很简单。该层将一个 blob 作为输入:该批次的地面实况标签;并产生一个 blob 作为输出:信息增益矩阵H
。每个类别的频率是根据标签计算的,然后根据更新中提到的公式填充矩阵(我不声称这是唯一一个有效的公式,我'正在计划尝试不同的值)。
Maarten,你把这些层放到 github 上了吗?
@RockridgeKid 我没有公开我的调整,因为它们更像是一种破解,而不是对 Caffe 代码库的真正改进。
@MaartenBamelis 两个问题:1. 你有没有尝试给样本不同的权重而不是改变损失类型,如图here? 2.看起来很明显,但要确认的是,您不必为H
矩阵计算层实现反向计算,对吧?
【参考方案1】:
为什么不使用InfogainLoss 层来补偿训练集的不平衡?
Infogain 损失是使用权重矩阵 H
定义的(在您的情况下为 2×2)其条目的含义是
[cost of predicting 1 when gt is 0, cost of predicting 0 when gt is 0
cost of predicting 1 when gt is 1, cost of predicting 0 when gt is 1]
因此,您可以设置H
的条目以反映预测0 或1 的错误之间的差异。
您可以在 this thread 中找到如何为 caffe 定义矩阵 H
。
关于样本权重,您可能会发现this post 很有趣:它展示了如何修改 SoftmaxWithLoss 层以考虑样本权重。
最近,Tsung-Yi Lin, Priya Goyal, Ross Girshick, Kaiming He, Piotr Dollár Focal Loss for Dense Object Detection, (ICCV 2017) 提出了对交叉熵损失的修改。
焦点损失背后的想法是根据预测该示例的相对难度(而不是基于班级规模等)为每个示例分配不同的权重。从我开始尝试这种损失的短暂时间开始,感觉它优于具有班级大小权重的"InfogainLoss"
。
【讨论】:
@MaartenBamelis 我自己在学习类不平衡模型时遇到了一些困难。如果您能更新您的进度以及如何克服这一困难,我将不胜感激。谢谢! 我已经用应用您的解决方案的结果更新了问题。InfogainLossLayer
是帮助解决类不平衡的好工具!更新中所述的结果仅仅是概念证明;而不是仅仅预测0
,网络正在学习来解决任务!
@Shai,您能否确认条目的含义是否如您所描述的那样。该实现更符合 Maarten Bamelis 的逻辑,除非我遗漏了什么。
这是我能找到的唯一一个真正显示 H 外观的地方。谢谢。
@Alex我仔细研究了the documentation about the InfoGainLossLayer;它指出,如果 infogain 矩阵 H
是单位矩阵,则损失层的行为类似于 MultinomialLogisticLossLayer。据我了解,这意味着H[1, 1]
适用于当基本事实也是类1
时预测类1
的情况。【参考方案2】:
我在分类任务中也遇到过这个类不平衡问题。现在我正在使用带有重量的 CrossEntropyLoss(文档here),它工作正常。这个想法是在图像数量较少的类中给样本更多的损失。
计算重量
每个类的权重与该类中的图像数量成反比。这是一个使用 numpy 计算所有类的权重的 sn-p,
cls_num = []
# train_labels is a list of class labels for all training samples
# the labels are in range [0, n-1] (n classes in total)
train_labels = np.asarray(train_labels)
num_cls = np.unique(train_labels).size
for i in range(num_cls):
cls_num.append(len(np.where(train_labels==i)[0]))
cls_num = np.array(cls_num)
cls_num = cls_num.max()/cls_num
x = 1.0/np.sum(cls_num)
# the weight is an array which contains weight to use in CrossEntropyLoss
# for each class.
weight = x*cls_num
【讨论】:
以上是关于解决类别不平衡:对损失和 sgd 的贡献比例缩放的主要内容,如果未能解决你的问题,请参考以下文章
slowfast 损失函数改进深度学习网络通用改进方案:slowfast的损失函数(使用focal loss解决不平衡数据)改进