每个示例具有不同权重的 Keras 自定义损失函数
Keras custom loss function with different weights per example
我正在尝试在 Keras 中实现一个自定义损失函数,其中每个单独的示例(不是 class)都有不同的权重。
准确地说,给定通常的 y_true(例如 <1,1,0>)和 y_pred(例如 <1,0.2,0.8>),我正在尝试创建 权重 (例如 <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.
我进一步替换了 range() 与 K.arange() 现在得到:TypeError: Tensor objects are not iterable when eager execution is not enabled. To iterate over this tensor use tf.map_fn
.
有人能帮帮我吗?我错过了什么?非常感谢!
在 tensorflow 中,您首先要用张量预定义图表,然后再 运行 它。因此,适用于 numpy 数组的函数不适用于 tensorflow 是很常见的。在你的情况下 num_examples 是问题所在。
想象一下,在 tensorflow 中,这个损失函数不会在您每次需要时都被调用,而是这个损失函数会在训练模型时构建图表,用于在您的图表中计算损失函数。
因此,当 keras 想要尝试在 tensorflow 中构建损失函数时,您的 y_true 是一个抽象张量,您的第一个形状很可能具有 None,因为 batch_size尚未定义。
您必须以不依赖于 batch_size => 删除变量的方式重写损失函数 num_examples
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.9
和 0.56144917 = 0.693147182 * 0.9 ** 2
,等等)。
我正在尝试在 Keras 中实现一个自定义损失函数,其中每个单独的示例(不是 class)都有不同的权重。
准确地说,给定通常的 y_true(例如 <1,1,0>)和 y_pred(例如 <1,0.2,0.8>),我正在尝试创建 权重 (例如 <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.
我进一步替换了 range() 与 K.arange() 现在得到:TypeError: Tensor objects are not iterable when eager execution is not enabled. To iterate over this tensor use tf.map_fn
.
有人能帮帮我吗?我错过了什么?非常感谢!
在 tensorflow 中,您首先要用张量预定义图表,然后再 运行 它。因此,适用于 numpy 数组的函数不适用于 tensorflow 是很常见的。在你的情况下 num_examples 是问题所在。
想象一下,在 tensorflow 中,这个损失函数不会在您每次需要时都被调用,而是这个损失函数会在训练模型时构建图表,用于在您的图表中计算损失函数。
因此,当 keras 想要尝试在 tensorflow 中构建损失函数时,您的 y_true 是一个抽象张量,您的第一个形状很可能具有 None,因为 batch_size尚未定义。
您必须以不依赖于 batch_size => 删除变量的方式重写损失函数 num_examples
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.9
和 0.56144917 = 0.693147182 * 0.9 ** 2
,等等)。