tensorflow 将from_logits设置为True时,二元交叉熵和多标注分类无法按预期工作

xghobddn  于 2023-03-19  发布在  Git
关注(0)|答案(1)|浏览(314)

我想有一个多标签分类任务,我想用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>。正如你所看到的,它们不匹配。有人能告诉我为什么吗?它们必须得到相同或至少相似的数字,只有很小的差别。

lymnna71

lymnna711#

该问题是由于Keras将epsilon constant用作模糊因子,以避免数值不稳定性和NaN值(如log(-1.)的结果)。
from_logits设置为False时,此常数用于计算二元交叉熵。默认情况下,此epsilon值设置为1e-7,但这会导致二元交叉熵计算中的一些不精确性。这就是recommended usage is to use from_logits=True的原因,其中计算交叉熵的方法不依赖于此常数。
如果希望两个结果彼此更接近,可以使用tf.keras.backend.set_epsilon将模糊因子设置为一个较低的值。使用1e-15附近的值会使两种方法的结果更接近。(但可能会导致其他地方的数值不稳定)。

tf.keras.backend.set_epsilon(1e-15)
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)

测试:

>>> lt(a,b)
<tf.Tensor: shape=(), dtype=float64, numpy=2.336649845037007>
>>> lf(a, b_sigmoid)
<tf.Tensor: shape=(), dtype=float64, numpy=2.3366498369361732>

相关问题