我想有一个多标签分类任务,我想用Tensorflow
实现网络,我知道我必须用BCE
作为损耗,用Sigmoid
作为最后一层的激活,我想有稳定的计算,所以我决定使用选项from_logits
设置为True
来表示BCE
。问题是我尝试使用下面的代码来检查是否一切正常,但是结果不匹配。在下面的代码中,a
对应于两个样本,在第一个样本中,存在最后两个类别。b
对应于未通过Sigmoid
激活函数的网络的输出。
a = np.array([[0, 0, 1, 1],
[0, 1, 0, 1.]])
b = np.array([[18, -20, 20, 20],
[-18, 0., -10, 12]])
b_sigmoid = tf.sigmoid(b)
lf = tf.keras.losses.BinaryCrossentropy()
lt = tf.keras.losses.BinaryCrossentropy(from_logits=True)
调用lf(a, b_sigmoid)
会得到<tf.Tensor: shape=(), dtype=float64, numpy=2.0147683492886337>
,而调用lt(a, b)
会得到<tf.Tensor: shape=(), dtype=float64, numpy=2.336649845037007>
。正如你所看到的,它们不匹配。有人能告诉我为什么吗?它们必须得到相同或至少相似的数字,只有很小的差别。
1条答案
按热度按时间lymnna711#
该问题是由于Keras将epsilon constant用作模糊因子,以避免数值不稳定性和NaN值(如
log(-1.)
的结果)。当
from_logits
设置为False
时,此常数用于计算二元交叉熵。默认情况下,此epsilon值设置为1e-7
,但这会导致二元交叉熵计算中的一些不精确性。这就是recommended usage is to usefrom_logits=True
的原因,其中计算交叉熵的方法不依赖于此常数。如果希望两个结果彼此更接近,可以使用
tf.keras.backend.set_epsilon
将模糊因子设置为一个较低的值。使用1e-15
附近的值会使两种方法的结果更接近。(但可能会导致其他地方的数值不稳定)。测试: