首页 > 解决方案 > 为什么在使用 tf.keras(Tensorflow 2.0)的分类器训练中,作为损失和指标的 BinaryCrossentropy 并不相同?

问题描述

我使用 BinaryCrossentropy 作为损失和指标之一:

model.compile(
    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-5), 
    loss=tf.keras.losses.BinaryCrossentropy(), 
    metrics=[tf.keras.metrics.BinaryCrossentropy(), tf.keras.metrics.AUC()])

由于它们是相同的东西,我认为它们应该产生相同的结果。然而,它们分别在训练集和验证集上显示略有不同的值。为什么是这样?BinaryCrossentropy 不应该在相同数据上具有相同的值吗? 在此处输入图像描述

是否有可能,损失值是最后一批的损失,而度量值是在 epoch 的所有批次上计算的(平均值?)?

我试图在tf.keras.Model.compile上找到相关信息,但我还无法确认。

标签: tensorflowdeep-learningneural-networktensorflow2.0

解决方案


如果您使用与损失和度量相同的函数,您通常会在深度网络中看到不同的结果。这通常是因为floating point precision errors:即使数学方程是等价的,但运算的顺序并不相同,这可能会导致细微的差异。

如果您考虑两者的简单示例,它将返回相同的结果。

作为度量的二元交叉熵:

m.update_state([[0, 1], [0, 0]], [[0.6, 0.4], [0.4, 0.6]])
m.result().numpy()

0.81492424

作为损失的二元交叉熵:

y_true = [[0., 1.], [0., 0.]]
y_pred = [[0.6, 0.4], [0.4, 0.6]]
bce = tf.keras.losses.BinaryCrossentropy()
bce(y_true, y_pred).numpy()

0.81492424

对于每个批次和 Epoch 的计算,计算没有差异,但是在训练数据集和验证数据集上的计算之间存在差异。对于 val 集,它是在纪元结束时为您的整个 val 数据集计算的。对于训练集:它是在批次结束时计算的,并且平均值会不断更新,直到 epochs 结束。

仅当使用样本权重时,度量和损失的计算方法才会改变,不仅仅是精度误差,在您的情况下,您没有定义任何样本权重,如下所示,否则它会超过浮点精度误差:

sample_weight = np.random.rand(len(y_train))
history = model.fit(X_train_scaled, y_train, epochs=2, sample_weight=sample_weight)
  • 自 epoch 开始以来的损失是迄今为止看到的所有批次损失的平均值。每个批次损失是加权实例损失的总和除以批次大小(不是权重总和,因此批次损失不是损失的加权平均值)。
  • 自 epoch 开始以来的度量等于加权实例损失的总和除以迄今为止看到的所有权重的总和。换句话说,它是所有实例损失的加权平均值。不是一回事。如果你做数学,你会发现

    loss =metric * mean of sample weights (plus some floating point precision error)

希望这能解释你的问题,快乐学习!


推荐阅读