使用条件自定义keras中的损失函数

Costumizing loss function in keras with condition

我想为具有 4 个不同 类 的多分类问题设置一个 keras 模型(tensorflow 后端)。我有标记和未标记的数据。

我已经解决了只使用标记数据进行训练的情况,我的模型看起来像这样:

# create model
inputs = keras.Input(shape=(len(config.variables), ))  
X = layers.Dense(units=200, activation="relu")(inputs)
output = layers.Dense(units=4, activation="softmax", name="output")(X)

model = keras.Model(inputs=inputs, outputs=output)
model.compile(optimizer=optimizers.Adam(1e-4), loss=loss_function, metrics=["accuracy"])

# train model
model.fit(
    x=train_data, 
    y=train_class_labels,
    batch_size=200, 
    epochs=200, 
    verbose=2, 
    validation_split=0.2,
    sample_weight       = class_weights
    )

我有不同损失的功能模型,即 categorical_crossentropysparse_categorical_crossentropy,并且根据损失函数,我的 train_class_labels 在单热表示中(例如 [ [0, 1,0,0], [0,0,0,1], ...]) 或整数表示(例如 [0,0,2,1,0,3, ...]),一切正常美好的。 class_weights 是一些权重向量 ([0.78, 1,34, ...])

现在为了我的进一步计划,我需要在训练过程中包含未标记的数据,但我需要它被损失函数忽略。

我尝试过的:

  1. 当使用 categorical_crossentropy 作为损失时,将未标记数据的标签设置为 [0,0,0,0],因为我认为我的未标记数据会被损失函数忽略。这不知何故改变了训练后的预测。
  2. 我也尝试将未标记数据的权重设置为 0,但这确实有影响

我得出结论,我需要以某种方式标记我未标记的数据并自定义我的损失函数,以便它可以被告知忽略这些样本。像

def custom_loss(y_true, y_pred):
    if y_true == labeled data:
        return normal loss function
    if y_true == unlabeled data:
        return 0

这些是我找到的一些片段,但它们似乎不起作用:

def custom_loss(y_true, y_pred):
    loss = losses.sparse_categorical_crossentropy(y_true, y_pred)
    return K.switch(K.flatten(K.equal(y_true, -1)), K.zeros_like(loss), loss)

def custom_loss2(y_true, y_pred):
    idx  = tf.not_equal(y_true, -1)
    y_true = tf.boolean_mask(y_true, idx)
    y_pred = tf.boolean_mask(y_pred, idx)
    return losses.sparse_categorical_crossentropy(y_true, y_pred)

在这些示例中,我将未标记数据的标签设置为 -1,因此 train_class_labels 看起来像这样:[0,-1,2,0,3, ...]

但是当使用第一个损失函数时我得到了 Nans 而当使用第二个损失函数时我得到了以下错误: Invalid argument: logits and labels must have the same first dimension, got logits shape [1,5000] and labels shape [5000]

我认为将标签设置为 [0,0,0,0] 就可以了。因为损失是根据每个 class 实例的对数损失总和计算的(在您的情况下,对于没有标签的实例,损失将为 0)。

我不明白你为什么要在监督设置中的训练中插入非标记数据。

我认为您获得的差异是由于批量大小和梯度步长造成的。如果有对梯度下降没有贡献的实例,计算出的损失会和之前不同,然后你得到预测的差异。

基本上每个批次的实例信息较少。

如果您使用所有数据集的大小作为批量大小,则与之前没有未标记实例的训练没有区别(但始终使用批量大小 = 数据集大小的训练)