keras 如何在y_true和y_pred可用的自定义损失函数中使用输入

b4wnujal  于 2023-02-04  发布在  其他
关注(0)|答案(1)|浏览(170)

我在tensorflow中构建了一个自动编码器,它接受一个带有缺失值(-999.)的输入,然后将其屏蔽。目标/标签是没有缺失值的输入的干净版本。模型如下:

inputs = Input(shape=(input_size, 1))
model = Masking(mask_value=-999.)(inputs)
...
model = CustomLossLayer(2.)([model, inputs])
model = Model(inputs, model)
model.compile(loss=None, optimizer='adam')

我想在损失函数中加入一个权重,这样缺失值的误差会被放大,这样做的目的是为了鼓励模型更好地预测缺失值。
我找到的最接近的解决方案使用这两个类:

class CustomLossClass(Loss):
    def __init__(self, weights):
        super().__init__()
        self.weights = weights

    def call(self, y_true, y_pred):        
        return reduce_mean(square(multiply(subtract(y_true, y_pred), self.weights)))

class CustomLossLayer(Layer):
    def __init__(self, weight, name="custom_loss"):
        super().__init__(name=name)
        self.weight = float(weight)

    def call(self, inputs):
        where_missing = equal(inputs[1], -999.)
        weights = where(where_missing, self.weight, 1.)
        self.add_loss(CustomLossClass(weights))
        return inputs[0]`

函数reduce_mean、square、multiply、subtract、where和equal都是从基础tensorflow 模块导入的。
当我运行代码时,给出的错误是:

TypeError: __call__() missing 2 required positional arguments: 'y_true' and 'y_pred'

我不知道如何将y_true和y_pred变量传递给loss类,我的理解是,如果您将loss定义为一个层(CustomLossLayer)并使用add_loss,那么它会在训练期间自动将这些变量传递给CustomLossClass。
我也尝试过将loss()函数封装在另一个函数中,并将其包含在model.compile(loss=...)中,但似乎无法将当前批处理的输入传递给loss函数以确定缺失数据的位置,也许我需要为此执行自定义训练循环,但我希望避免这种情况。
有人能给我一些建议或工作代码,以实现我在这里试图做什么?

yyhrrdl8

yyhrrdl81#

我已经写了一个工作代码的例子,试图实现重量更新的损失函数。使用一个自定义损失函数,而不是损失类可能是你正在寻找:

import tensorflow as tf

class CustomLayer(Layer):
    def __init__(self):
        super().__init__()

    def call(self, inputs):
        return inputs[1]

# Define the custom loss function
def masked_mse(mask_value):
    def loss(y_true, y_pred):
        weight = 2.0
        tf.print("y_true", y_true, summarize=10)
        tf.print("y_pred:", y_pred, summarize=10)
        where_missing = tf.equal(y_pred, mask_value)
        weights = tf.where(where_missing, weight, 1.)
        tf.print("weights:", weights, summarize=10)
        return tf.reduce_mean(tf.square(tf.multiply(tf.subtract(y_true, y_pred), weights)))
    return loss

mask_value = -999.
input_size = 10
inputs = Input(shape=(input_size, 1))
masked = Masking(mask_value=-999.)(inputs)
model = CustomLayer()([masked, inputs])
model = Model(inputs, model)

# Compile the model with the masked loss function and specified weight
model.compile(optimizer='adam', loss=masked_mse(mask_value), metrics=['accuracy'], run_eagerly=True)

x_train = tf.constant([[-999., 1., 2., 3., -999., 5., 6., 7., 8., 9.]], dtype=tf.float32)
y_train = tf.constant([[0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]], dtype=tf.float32)

# Train the model on the input data
model.fit(x_train, y_train, epochs=1, batch_size=1)

我还添加了print语句来查看权重是否按预期工作。

y_true [[0 0 0 0 0 0 0 0 0 0]]
y_pred: [[-999 1 2 3 -999 5 6 7 8 9]]
weights: [[2 1 1 1 2 1 1 1 1 1]]
1/1 [==============================] - 0s 40ms/step - loss: 798427.6875 - accuracy: 0.2000

相关问题