【问题标题】:Costumizing loss function in keras with condition在具有条件的 keras 中自定义损失函数
【发布时间】:2021-03-16 12:43:54
【问题描述】:

我想为具有 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

这些是我发现的一些 sn-ps,但它们似乎不起作用:

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]

【问题讨论】:

  • 请讲道理;在 training 过程中包含未标记的数据,同时在训练期间尝试 ignore 它们没有任何意义。完全没有。
  • @desertnaut 我知道这看起来很奇怪,但我使用的数据是来自粒子物理学的碰撞数据。标记数据集来自模拟,未标记数据来自真实碰撞。问题是我要实现另一个输出到网络,它应该对域进行分类(所以如果是它的模拟数据或真实数据),并且在这个输出的前面有一个翻转梯度的层。目标是从数据集中获取域不变特征。据我了解,我在问题中描述的问题是设置工作。

标签: python tensorflow machine-learning keras loss-function


【解决方案1】:

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

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

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

基本上每个批次的信息量会更少。

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

【讨论】:

  • @desertnaut 在交叉熵计算中,标签用于求和。如果标签全部为 0,则损失为 0。我错了吗? i.ibb.co/4tCVTGw/losscalculatincrossentropy.png
  • 你是对的,我的错 - 没有正确表达自己。我应该说的是,通过使用全 0,实例不再是 unlabeled - 它们现在被隐式 labeled 作为一个额外的类,而且,它不是包含在初始的 one-hot 编码中。并且通过给出 0 的损失(正如您正确描述的那样),该过程发出信号“这是一个正确分类的样本”;作为一种实践,这是否有意义?
  • 好的,我知道这会导致什么问题。但是,如果我将批量大小设置为所有数据集,我不会遇到示例问题。据我了解,我的实例信息仍然较少,因此梯度步骤会有所不同?
  • @King5ters 如果您使用所有数据集,则梯度步骤将是相同的。因为损失为 0 时计算的梯度始终为 0,因此对最终结果没有贡献。当您使用批处理时,这会发生变化。根据批次中的内容,将朝着减少错误迈出一步。但是现在批次中也有非信息实例,因此每批次的步骤会有所不同
  • @Nikaido 好的,非常感谢,解释得很清楚!
猜你喜欢
  • 2018-12-08
  • 2020-12-19
  • 2017-12-18
  • 2020-03-27
  • 1970-01-01
  • 2021-12-15
  • 2018-10-28
  • 2017-12-29
  • 2018-11-12
相关资源
最近更新 更多