首页 文章

Keras自定义丢失功能,每个示例具有不同的权重

提问于
浏览
3

我正在尝试在Keras中实现一个自定义丢失函数,其中每个单独的示例(不是类)具有不同的权重 .

确切地说,给定通常 y_true (例如<1,1,0>)和 y_pred (例如<1,0.2,0.8>),我正在尝试创建 weights (例如<0.81,0.9,1.0>)和使用 binary_crossentropy 损失函数 . 我试过了:

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_shape替换了K.int_shape,现在得到: TypeError: range() integer end argument expected, got Tensor. 我用K.arange()进一步替换了range(),现在得到: TypeError: Tensor objects are not iterable when eager execution is not enabled. To iterate over this tensor use tf.map_fn .

有人可以帮我吗?我错过了什么?非常感谢!

2 回答

  • 2

    K.pow 可以将一系列指数作为参数 . 因此,您可以首先计算指数,作为张量( [num_examples - 1, num_examples - 2, ..., 0] ),然后将此张量输入 K.pow . 这里 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.90.56144917 = 0.693147182 * 0.9 ** 2 等) .

  • 1

    在tensorflow中,您首先使用张量预定义图形,然后再运行它 . 因此,使用numpy数组的函数不能与tensorflow一起使用是很常见的 . 在您的情况下,num_examples是问题所在 .

    想象一下,在张量流中,每次需要时都不会调用此损失函数,而是在模型训练时,此损失函数将构建用于计算图形内部损失函数的图形 .

    所以当keras想要尝试在tensorflow中构建你的损失函数时,你的y_true是一个抽象张量,你的第一个形状很可能会有None,因为batch_size还没有定义 .

    你必须以一种你不依赖于batch_size =>删除变量num_examples的方式重写你的损失函数

相关问题