首页 > 解决方案 > 为什么我的自定义损失(分类交叉熵)不起作用?

问题描述

我正在为自己构建基于 Tensorflow 和 Keras 的某种框架。作为开始,我只编写了框架的核心并实现了第一个玩具示例。这个玩具示例只是一个经典的前馈网络求解 XOR。

可能没有必要解释它周围的一切,但我实现了这样的损失函数:

class MeanSquaredError(Modality):

    def loss(self, y_true, y_pred, sample_weight=None):
        y_true = tf.cast(y_true, dtype=y_pred.dtype)
        loss = tf.keras.losses.MeanSquaredError(reduction=tf.keras.losses.Reduction.NONE)(y_true, y_pred)
        return tf.reduce_sum(loss) / self.model_hparams.model.batch_size

这将在实际模型类中使用,如下所示:

class Model(keras.Model):

    def loss(self, y_true, y_pred, weights=None):
        target_modality = self.modalities['targets'](self.problem.hparams, self.hparams)
        return target_modality.loss(y_true, y_pred)

现在,在训练方面,我可以像这样训练模型:

model.compile(
    optimizer=keras.optimizers.Adam(0.001),
    loss=model.loss,  # Simply setting 'mse' works as well here
    metrics=['accuracy']
)

或者我可以设置loss=mse. 两种情况都按预期工作,没有任何问题。

但是,我有另一个Modality类用于序列到序列(例如翻译)任务。它看起来像这样:

class CategoricalCrossentropy(Modality):
    """Simple SymbolModality with one hot as embeddings."""

    def loss(self, y_true, y_pred, sample_weight=None):
        labels = tf.reshape(y_true, shape=(tf.shape(y_true)[0], tf.reduce_prod(tf.shape(y_true)[1:])))
        y_pred = tf.reshape(y_pred, shape=(tf.shape(y_pred)[0], tf.reduce_prod(tf.shape(y_pred)[1:])))
        loss = tf.keras.losses.CategoricalCrossentropy(reduction=tf.keras.losses.Reduction.NONE, from_logits=True)(labels, y_pred)
        return tf.reduce_mean(loss) / self.model_hparams.model.batch_size

这样做只是将y_truey_pred张量重塑[batch_size, seq_len, embedding_size][seq_len * batch_size, embedding_size]- 有效地堆叠所有示例。由此,计算并归一化分类交叉熵。

现在,我使用的模型是一个非常简单的 LSTM——不过这并不重要。当我像这样训练模型时:

model.compile(
    optimizer=keras.optimizers.Adam(0.001),
    loss='categorical_crossentropy',  # <-- Setting the loss via string argument (works)
    metrics=['accuracy']
)

该模型确实按预期学习了任务。但是,如果我使用CategoricalCrossentropy上面的 -modality 设置loss=model.loss,模型根本不会收敛。损失随机振荡但不收敛。

就是我挠头的地方。由于简单的 XOR 示例在两种方式中都有效,并且由于设置categorical_crossentropy也有效,我不太明白为什么使用所述模态不起作用。

我在做一些明显错误的事情吗?

很抱歉我不能在这里提供一个小例子,但这不可能,因为框架已经包含一些代码行。从经验上讲,一切都应该起作用。

任何想法我可以如何追踪问题或可能导致此问题的原因?

标签: tensorflowkeras

解决方案


您正在为形状创建一个张量元组。那可能行不通。

为什么不只是这个?

labels = tf.keras.backend.batch_flatten(y_true)
y_pred = tf.keras.backend.batch_flatten(y_pred)

标准'categorical_crossentropy'损失不执行任何类型的展平,并将最后一个轴视为类。

您确定要展平数据吗?如果扁平化,就会将类数乘以步数,这似乎没有多大意义。

此外,标准'categorical_crossentropy'损失使用from_logits=False

标准损失期望来自"softmax"激活的输出,而from_logits=True期望没有激活的输出。


推荐阅读