简体   繁体   English

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

[英]Keras custom loss function with different weights per example

I'm trying to implement in Keras a custom loss function where each individual example (not class) has a different weight. 我正在尝试在Keras中实现一个自定义丢失函数,其中每个单独的示例(不是类)具有不同的权重。

To be precise, given the usual y_true (eg. <1,1,0>) and y_pred (eg <1,0.2,0.8>), I'm trying to create weights (eg <0.81, 0.9, 1.0>) and use these with the binary_crossentropy loss function. 确切地说,给定通常的y_true (例如<1,1,0>)和y_pred (例如<1,0.2,0.8>),我正在尝试创建权重 (例如<0.81,0.9,1.0>)和将这些与binary_crossentropy损失函数一起使用。 I have tried: 我试过了:

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
    )

And works fine with this simple example: 并通过这个简单的例子正常工作:

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))

However, when I use it with model.compile(loss=my_binary_crossentropy, ...) I get the following error: TypeError: range() integer end argument expected, got NoneType . 但是,当我将它与model.compile(loss=my_binary_crossentropy, ...)一起使用时,我收到以下错误: TypeError: range() integer end argument expected, got NoneType

I have tried a few things. 我尝试了一些事情。 I replaced K.int_shape with K_shape and now getting: TypeError: range() integer end argument expected, got Tensor. 我用K_shape替换了K.int_shape并且现在得到: TypeError: range() integer end argument expected, got Tensor. I further replaced range() with K.arange() and now getting: TypeError: Tensor objects are not iterable when eager execution is not enabled. To iterate over this tensor use tf.map_fn 我再次被替换范围()K.arange()现在越来越: TypeError: Tensor objects are not iterable when eager execution is not enabled. To iterate over this tensor use tf.map_fn TypeError: Tensor objects are not iterable when eager execution is not enabled. To iterate over this tensor use tf.map_fn . TypeError: Tensor objects are not iterable when eager execution is not enabled. To iterate over this tensor use tf.map_fn

Can anyone help me please? 有人可以帮我吗? What am I missing? 我错过了什么? Many Thanks! 非常感谢!

K.pow can take a sequence of exponents as argument. K.pow可以将一系列指数作为参数。 So you can compute the exponents first, as a tensor ( [num_examples - 1, num_examples - 2, ..., 0] ), and then feed this tensor into K.pow . 因此,您可以首先计算指数,作为张量( [num_examples - 1, num_examples - 2, ..., 0] ),然后将此张量提供给K.pow Here num_examples is basically just K.shape(y_pred)[0] , which is also a tensor. 这里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

As an example, the output printed by the two K.print_tensor statements would be like: 例如,两个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...]

The numbers are not exact due to rounding errors. 由于舍入误差,数字不准确。 The forgetting_factors (first lines printed after model.evaluate ) are indeed the powers of 0.9. forgetting_factors (后打印的第一行model.evaluate )确实的0.9的权力。 You can also verify that the returned loss values decay by a factor of 0.9 ( 0.623832464 = 0.693147182 * 0.9 and 0.56144917 = 0.693147182 * 0.9 ** 2 , etc). 您还可以验证返回的损失值是否衰减0.9( 0.623832464 = 0.693147182 * 0.90.56144917 = 0.693147182 * 0.9 ** 2等)。

In tensorflow you first predefine you graph with tensors before you run it. 在张量流中,您首先在运行之前使用张量预定义图形。 So it's quite common that a function which works with numpy array won't work with tensorflow. 因此,使用numpy数组的函数不能与tensorflow一起使用是很常见的。 In your case num_examples is the problem. 在您的情况下,num_examples是问题所在。

Imagine that in tensorflow this loss function will not be called every time you need it, instead this loss function will build the graph for calculating the loss function inside your graph when the model is trained. 想象一下,在张量流中,每次需要时都不会调用此损失函数,而是在模型训练时,此损失函数将构建用于计算图形内部损失函数的图形。

So when keras wants to try to build your loss function inside tensorflow, your y_true is an abstract tensor which most likely will have None for your first shape because the batch_size isn't defined yet. 所以当keras想要尝试在tensorflow中构建你的损失函数时,你的y_true是一个抽象张量,你的第一个形状很可能会有None,因为batch_size还没有定义。

You have to rewrite your loss function in a way that you're not dependent on your batch_size => remove the variable num_examples 你必须以一种你不依赖于batch_size =>删除变量num_examples的方式重写你的损失函数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM