在 Keras 中使用具有多个二进制输出的类权重,这些输出不是简单的单热编码

数据挖掘 分类 喀拉斯 阶级失衡
2021-09-21 16:30:58

我的标签是长度为 5 的二进制向量,例如[0, 0, 1, 1, 1].

我的标签集非常有偏差,从 1 到 50,其中 [0, 0, 0, 0, 0] 的情况很常见,而所有其他组合则不然。我想使用 Keras 函数中的class_weight参数来衡量不常见的版本model.fit()我收到一条错误消息,上面写着class_weight必须包含数据中的所有类。

The classes {0, 1, 2, 3, 4} exist in the data but not in class_weight.

基于此,我怀疑 Keras 期望我只有 、 、 等形式的类[1, 0, 0, 0, 0][0, 1, 0, 0, 0][0, 0, 1, 0, 0]向量中的每个条目中只有 1 个。我应该按如下方式提供权重:

weight_classes = {
    0: 50.0,        # for [1, 0, 0, 0, 0]
    1: 1.0,         # for [0, 1, 0, 0, 0]
    # etc.
}

有没有办法告诉 Keras 以这种方式赋予权重:

weight_classes = {
    (0, 0, 0, 0, 0): 1.0,
    (0, 0, 1, 1, 1): 50.0,
    (0, 0, 0, 0, 1): 50.0,
    # etc.
}

还是有其他方法可以说全零情况不那么重要?

我考虑只是转换标签集以符合单热编码类型的表示。但我宁愿不这样做,因为标签会变得非常大,并且标签之间存在相互依赖关系,我认为通过像我所做的那样对它们进行编码可能会更好地表示它们。它们是相互依赖的,类似于句子中的单词是相互依赖的,但其中个别预测是独立有价值的。

我还考虑只使用子/超级采样,并跳过整个班级的加权。

1个回答

这个问题的解决方案是sample_weight在函数中使用,(如果你正在使用它model.fit(),作为第三个元组条目)。validation_data对于每个标签样本,您只需使用某种算法对其稀有或常见进行分类,并相应地设置权重。

对我来说,这可以通过以下方式完成:

sample_weight = np.max(label_data, axis=1)) * 49 + 1

在这里,我利用了每个标签行的常见情况全为零的事实,例如:

     label_rows                             weights   label type
max([0, 0, 0, 0, 0])*49+1 = 0*49+1 =  0+1 =  1      # common
max([0, 0, 1, 1, 1])*49+1 = 1*49+1 = 49+1 = 50      # rare
max([0, 0, 0, 0, 0])*49+1 = 0*49+1 =  0+1 =  1      # common
max([0, 0, 0, 0, 1])*49+1 = 1*49+1 = 49+1 = 50      # rare
max([0, 0, 0, 1, 1])*49+1 = 1*49+1 = 49+1 = 50      # rare
...

也就是说,我最终重新编码了我的标签,以便每个标签行中只有一个正面条目,从而可以设置类权重。不是因为对样本进行加权,而是因为它可以更好地解释为概率输出(使用 softmax)。以下函数进行加权:

def create_class_weights(label_dim, rare_weight=10.0, common_weight=1.0):
    class_weight = {
        idx: rare_weight for idx in range(label_dim)
    }
    class_weight[label_dim-1] = common_weight
    return class_weight

它假设常见情况是每个标签行的最后一个。