为什么我的自定义损失(分类交叉熵)不起作用?

时间:2020-04-06 19:04:44

标签: tensorflow keras

我正在为自己构建一些基于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-模态,设置loss=model.loss,则该模型根本不会收敛。损耗随机波动,但不会收敛。

是我在head头的地方。由于简单的XOR示例可以同时使用,而且设置categorical_crossentropy也可以使用,因此我不太明白为什么使用上述模态无效。

我做错了什么吗?

很抱歉,我无法在此处提供一个小示例,但是由于框架已经包含一些代码行,因此无法实现。从经验上讲,所有 都应该起作用。

有什么想法可以找出问题的根源或是什么原因造成的?

1 个答案:

答案 0 :(得分:1)

您正在创建张量元组以形成形状。那可能行不通。

为什么不仅如此?

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期望没有激活的输出。