【问题标题】:Use both sample_weight and class_weight simultaneously同时使用 sample_weight 和 class_weight
【发布时间】:2018-01-09 16:59:20
【问题描述】:

我的数据集已经有加权示例。而且在这个二元分类中,与第二类相比,我也有更多的第一类。

我可以同时使用sample_weight 并在model.fit() 函数中使用class_weight 进一步重新加权它吗?

还是我先创建一个新的 new_weights 数组并将其作为 sample_weight 传递给 fit 函数?

编辑:

为了进一步澄清,我已经为数据集中的每个样本设置了单独的权重,为了进一步增加复杂性,第一类样本权重的总和远远超过第二类样本权重的总和。

例如我目前有:

y = [0,0,0,0,1,1]

sample_weights = [0.01,0.03,0.05,0.02, 0.01,0.02]

所以 class '0' 的 权重总和 是 0.11 而 class '1' 是0.03。所以我应该有:

class_weight = {0 : 1. , 1: 0.11/0.03}

我需要同时使用 sample_weight 和 class_weight 功能。如果一个覆盖另一个,那么我将不得不创建新的 sample_weights,然后使用 fit() 或 train_on_batch()。

所以我的问题是,我可以同时使用两者,还是一个覆盖另一个?

【问题讨论】:

    标签: python tensorflow keras


    【解决方案1】:

    如果你愿意,你当然可以两者兼得,关键是如果这是你需要。根据kerasdocs:

    • class_weight: 可选字典将类索引(整数)映射到权重(浮点)值,用于加权损失函数(仅在训练期间)。这对于告诉模型“更加关注”来自代表性不足的类的样本很有用。

    • sample_weight: 训练样本的可选 Numpy 权重数组,用于加权损失函数(仅在训练期间)。您可以传递一个平面 (1D) Numpy 数组与输入样本的长度相同(权重和样本之间的 1:1 映射),或者在时间数据的情况下 [...]。

    因此,鉴于您提到“与第二类相比,第一类的数量要多得多”,我认为您应该选择class_weight 参数。在那里,您可以指示您的数据集呈现的比率,以便您可以补偿不平衡的数据类。当您想为 每个 数据元素定义权重或重要性时,sample_weight 更多。

    例如,如果你通过:

    class_weight = {0 : 1. , 1: 50.}
    

    您会说 1 类中的每个样本都将计为 0 类中的 50 个样本,因此对 1 类中的元素给予更多“重要性”(因为这些样本肯定更少) .您可以自定义它以满足您自己的需求。更多关于 this 的不平衡数据集的信息很好的问题。

    注意:要进一步比较这两个参数,请记住将class_weight 传递为{0:1., 1:50.} 将等效于将sample_weight 传递为[1.,1.,1.,...,50.,50.,...],因为您有样本的类[0,0,0,...,1,1,...]。

    正如我们所看到的,在这种情况下使用class_weight 更实用,而sample_weight 可以用于更具体的情况,您实际上希望单独为每个样本赋予“重要性”。如果情况需要,也可以同时使用两者,但必须牢记其累积效应。

    编辑:根据您的新问题,挖掘 Keras source code 似乎确实 sample_weights 覆盖了 class_weights,这是一段代码在 _standarize_weigths 方法(第 499 行)上执行此操作:

    if sample_weight is not None:
        #...Does some error handling...
        return sample_weight #simply returns the weights you passed
    
    elif isinstance(class_weight, dict):
        #...Some error handling and computations...
        #Then creates an array repeating class weight to match your target classes
        weights = np.asarray([class_weight[cls] for cls in y_classes
                              if cls in class_weight])
    
        #...more error handling...
        return weights
    

    这意味着您只能使用其中一种,但不能同时使用。因此,您确实需要将您的sample_weights 乘以补偿不平衡所需的比率。


    更新:截至本次编辑时(2020 年 3 月 27 日),查看 training_utils.standardize_weights() 的 source code 我们可以看到它现在支持两者 class_weights 和 sample_weights:

    一切都归一化为单个样本(或时间步) 权重数组。 如果同时提供了sample_weights 和class_weights, 权重相乘。

    【讨论】:

    • 其实sample_weight会覆盖Keras中的class_weight,而后者完全没有效果(有点出乎IMO的意料)。因此,OP 可能需要将权重合并为一个,然后再将其传递给fit。
    • @Yu-Yang 很有趣,感谢分享(将在桌面上尝试并更新)。仍然是 OP 描述的方式,使用 class_weight 似乎足以平衡不平衡的数据集。如果需要进一步自定义,则手动合并和计算 sample_weighs 可能会有所帮助。
    • @user7867665 挖掘 Keras 源代码我找到了你的新问题的答案,很快就会更新。
    • @DarkCygnus 谢谢!这清除了它。在使用sample_weights 进行训练之前,我会进行重新加权。也许我们提出了功能请求
    • @user7867665 当然这是一个可能有用的功能。来吧:)
    【解决方案2】:

    为那些真正需要同时使用类权重和样本权重的人添加一些 DarkCygnus 答案:
    这是一个代码,我用它来生成样本权重,以对序列中的多类时间数据进行分类:
    (targets 是一个维度为 [#temporal, #categories] 的数组,其值在 set(#classes) 中,class_weights 是一个 [#categories, #classes] 的数组)。
    生成的序列与目标数组具有相同的长度,批处理中的常见用例是用零填充目标并且样本权重也达到相同的大小,从而使网络忽略填充的数据.

    def multiclass_temoral_class_weights(targets, class_weights):
        s_weights = np.ones((targets.shape[0],))
        # if we are counting the classes, the weights do not exist yet!
        if class_weights is not None:
            for i in range(len(s_weights)):
                weight = 0.0
                for itarget, target in enumerate(targets[i]):
                    weight += class_weights[itarget][int(round(target))]
                s_weights[i] = weight
        return s_weights
    

    【讨论】:

    • 很好的补充。似乎 Keras 现在支持同时使用两种权重(更新了我的答案)
    猜你喜欢
    • 2017-05-07
    • 2015-08-28
    • 2018-05-04
    • 2012-10-14
    • 2018-09-06
    • 2019-02-05
    • 2021-04-26
    • 1970-01-01
    • 2014-05-11
    相关资源
    最近更新 更多