代码之家  ›  专栏  ›  技术社区  ›  KM.

Keras自定义损失函数,每个示例具有不同的权重

  •  4
  • KM.  · 技术社区  · 7 年前

    我试图在Keras中实现一个自定义损失函数,其中每个示例(而不是类)都有不同的权重。

    准确地说 y\u真 (例如,<1,1,0>)和 y\u预测 (例如,<1,0.2,0.8>),我正在努力创造 重量 (例如<0.81、0.9、1.0>)并将其与 二进制交叉熵 损失函数。我尝试过:

    import numpy as np
    from keras import backend as K
    
    def my_binary_crossentropy(y_true, y_pred):
        base_factor = 0.9
        num_examples = K.int_shape(y_true)[0]
    
        out = [ K.pow(base_factor, num_examples - i - 1) for i in range(num_examples) ]
        forgetting_factors = K.stack(out)
    
        return K.mean(
            forgetting_factors * K.binary_crossentropy(y_true, y_pred),
            axis=-1
        )
    

    并且可以很好地处理这个简单的示例:

    y_true = K.variable( np.array([1,1,0]) )
    y_pred = K.variable( np.array([1,0.2,0.8]) )
    print K.eval(my_binary_crossentropy(y_true, y_pred))
    

    但是,当我将其用于 model.compile(loss=my_binary_crossentropy, ...) 我得到以下错误: TypeError: range() integer end argument expected, got NoneType

    我试过几件事。我替换了 K、 int\u形状 具有 K\u形状 现在得到: TypeError: range() integer end argument expected, got Tensor. 我进一步替换了 范围() 具有 K、 arange() 现在得到: TypeError: Tensor objects are not iterable when eager execution is not enabled. To iterate over this tensor use tf.map_fn

    谁能帮帮我吗?我错过了什么?非常感谢!

    2 回复  |  直到 7 年前
        1
  •  3
  •   Yu-Yang    7 年前

    K.pow 可以将一系列指数作为参数。所以你可以先计算指数,作为张量( [num_examples - 1, num_examples - 2, ..., 0] ),然后将此张量输入 K、 战俘 。在这里 num_examples 基本上只是 K.shape(y_pred)[0] ,这也是张量。

    def my_binary_crossentropy(y_true, y_pred):
        base_factor = 0.9
        num_examples = K.cast(K.shape(y_pred)[0], K.floatx())
        exponents = num_examples - K.arange(num_examples) - 1
        forgetting_factors = K.pow(base_factor, exponents)
        forgetting_factors = K.expand_dims(forgetting_factors, axis=-1)
        forgetting_factors = K.print_tensor(forgetting_factors)  # only for debugging
    
        loss = K.mean(
            forgetting_factors * K.binary_crossentropy(y_true, y_pred),
            axis=-1
        )
        loss = K.print_tensor(loss)  # only for debugging
        return loss
    

    例如,由两个 K.print_tensor 声明如下:

    model = Sequential()
    model.add(Dense(1, activation='sigmoid', input_shape=(100,)))
    model.compile(loss=my_binary_crossentropy, optimizer='adam')
    
    model.evaluate(np.zeros((3, 100)), np.ones(3), verbose=0)
    [[0.809999943][0.9][1]]
    [0.56144917 0.623832464 0.693147182]
    
    model.evaluate(np.zeros((6, 100)), np.ones(6), verbose=0)
    [[0.590489924][0.656099916][0.728999913]...]
    [0.409296423 0.454773813 0.505304217...]
    

    由于舍入错误,数字不准确。这个 forgetting_factors (第一行打印在 model.evaluate )实际上是0.9的幂。您还可以验证返回的损耗值衰减系数是否为0.9( 0.623832464 = 0.693147182 * 0.9 0.56144917 = 0.693147182 * 0.9 ** 2 等)。

        2
  •  1
  •   dennis-w    7 年前

    在tensorflow中,首先使用张量预定义图形,然后再运行它。因此,使用numpy数组的函数通常不会使用tensorflow。在您的案例中,num\u示例就是问题所在。

    假设在tensorflow中,该损失函数不会在每次需要时都被调用,相反,该损失函数将构建图形,用于在训练模型时计算图形中的损失函数。

    因此,当keras想要在tensorflow中构建损失函数时,您的y\u true是一个抽象张量,它很可能对您的第一个形状没有任何张量,因为batch\u大小尚未定义。

    您必须以一种不依赖于批次大小的方式重写损失函数=>删除变量num\u示例