Keras 中的自定义损失函数,以掩码数组作为输入

Edd*_*ddy 5 python machine-learning deep-learning keras tensorflow

我正在尝试使用如下所示的自定义损失函数来训练自动编码器。输入 Missing_matrix 是一个由 1 和 0 组成的 nxm 数组,对应于 nxm 特征数组。我需要将 Missing_array 与 y_pred 进行逐个元素相乘,这应该是输入特征的重建,以便我可以屏蔽那些乘以 0 的特征,以忽略它们在成本函数中的贡献。我以前从未编写过自定义损失函数,下面的函数根本不起作用。我曾尝试搜索类似的自定义成本函数,但无法找到一个引入像这样的输入数组的函数。我将不胜感激您的帮助或正确方向的指出。

def custom_loss(missing_array):
    
    def missing_mse(y_true, y_pred):
        mse = MeanSquaredError()
        y_pred_masked = tf.math.multiply(y_pred, missing_array)
        return mse(y_true = y_true, y_pred = y_pred_masked)

    return missing_mse
Run Code Online (Sandbox Code Playgroud)

编辑:更进一步

from keras.losses import MeanSquaredError
import tensorflow as tf

def custom_loss(missing_matrix):
    
    def missing_mse(y_true, y_pred):
        mse = MeanSquaredError()
        y_pred_masked = tf.math.multiply(y_pred, tf.convert_to_tensor(missing_matrix, dtype=tf.float32))
        return mse(y_true = y_true, y_pred = y_pred_masked)

    return missing_mse
Run Code Online (Sandbox Code Playgroud)

有错误

InvalidArgumentError:  Incompatible shapes: [64,1455] vs. [13580,1455]
     [[node gradient_tape/missing_mse/BroadcastGradientArgs (defined at <ipython-input-454-b60d74568bf2>:64) ]] [Op:__inference_train_function_25950]

Function call stack:
train_function
Run Code Online (Sandbox Code Playgroud)

64让我觉得这就是批次。我可能需要批量获取 64 个缺失的矩阵?

编辑2:这很有趣!所以我验证了如果我做类似的事情,自定义损失函数将会训练

def train(self, model, X_train):
        """
        Model training
        """
        #model.fit(X_train, X_train, epochs = 10, batch_size = 64, validation_split = 0.10)
        for batch_idx in range(0, len(X_train), 70):
            self.batch_start = batch_idx
            self.batch_end = batch_idx + 70
            model.train_on_batch(X_train[self.batch_start:self.batch_end,:], X_train[self.batch_start:self.batch_end,:])
        return model
Run Code Online (Sandbox Code Playgroud)

并修改我的自定义损失

def custom_loss2(self, missing_matrix):
    
        def missing_mse(y_true, y_pred):
            mse = MeanSquaredError()
            y_pred_masked = tf.math.multiply(y_pred, tf.convert_to_tensor(missing_matrix[self.batch_start:self.batch_end,:], dtype=tf.float32))
            return mse(y_true = y_true[self.batch_start:self.batch_end,:], y_pred = y_pred_masked[self.batch_start:self.batch_end,:])

        return missing_mse
Run Code Online (Sandbox Code Playgroud)

那么现在我怎样才能获得纪元并打印出验证损失等......?或者更确切地说,更好的方法是什么?今晚我就是这样。晚安!

Mar*_*ani 5

问题是,y_truey_pred是批量的,而掩模是一次性通过的。自动将数据分成相等批次的一种简单解决方案是使用model.add_loss().

下面我重现了一个带有自动编码器和自定义掩蔽损失的虚拟示例。掩码作为模型输入传递,这是使其工作所需的简单技巧。

使用也mean_squared_error代替MeanSquaredError.

def missing_mse(y_true, y_pred, missing_array):
    
    y_pred_masked = tf.math.multiply(y_pred, missing_array)
    
    mse = tf.keras.losses.mean_squared_error(y_true = y_true, y_pred = y_pred_masked)
    
    return mse

inp = Input((100,))
x = Dense(20)(inp)
out = Dense(100)(x)

inp_mask = Input((100,))

model = Model([inp, inp_mask], out)
model.add_loss(missing_mse(inp, out, inp_mask))
model.compile('adam', loss=None)

X = np.random.uniform(0,1, (300,100))
mask = np.random.randint(0,2, (300,100))

model.fit(x=[X,mask], y=None, epochs=10, batch_size=64)

# at inference time you can remove the mask input in this way
new_model = Model(model.input[0], model.output)
new_model.predict(X).shape
Run Code Online (Sandbox Code Playgroud)