TensorFlow稀疏分类交叉熵是如何工作的?

29

我正在尝试理解TensorFlow中的损失函数,但我不懂它是什么意思。它叫做SparseCategoricalCrossentropy。所有其他的损失函数都需要相同形状的输出和标签,但这个特定的损失函数不需要。

源代码:

import tensorflow as tf;

scce = tf.keras.losses.SparseCategoricalCrossentropy();
Loss = scce(
  tf.constant([ 1,    1,    1,    2   ], tf.float32),
  tf.constant([[1,2],[3,4],[5,6],[7,8]], tf.float32)
);
print("Loss:", Loss.numpy());

错误是:

InvalidArgumentError: Received a label value of 2 which is outside the valid range of [0, 2).  
Label values: 1 1 1 2 [Op:SparseSoftmaxCrossEntropyWithLogits]

如何向损失函数 SparseCategoricalCrossentropy 提供适当的参数?

2个回答

32

SparseCategoricalCrossentropy和CategoricalCrossentropy都计算分类交叉熵。唯一的区别在于目标/标签的编码方式不同。

当使用SparseCategoricalCrossentropy时,目标由类别的索引(从0开始)表示。您的输出具有4x2的形状,这意味着您有两个类别。因此,目标应该是一个四维向量,其条目只能为0或1。例如:

scce = tf.keras.losses.SparseCategoricalCrossentropy();
Loss = scce(
  tf.constant([ 0,    0,    0,    1   ], tf.float32),
  tf.constant([[1,2],[3,4],[5,6],[7,8]], tf.float32))

这与CategoricalCrossentropy相反,后者需要对标签进行独热编码:

cce = tf.keras.losses.CategoricalCrossentropy();
Loss = cce(
  tf.constant([ [1,0]    [1,0],    [1, 0],   [0, 1]   ], tf.float32),
  tf.constant([[1,2],[3,4],[5,6],[7,8]], tf.float32))

SparseCategoricalCrossentropy在有很多类别的情况下更有效率。


我应该在最后一层中使用softmax激活函数,就像分类交叉熵一样吗? - Aral Roca
2
基于TensorFlow页面上的示例,如果您设置了 from_logits=True,则不需要指定最后一层的激活函数(https://www.tensorflow.org/tutorials/images/classification#compile_the_model)。虽然这并不重要,但它可以使模型更加数值稳定(https://dev59.com/4FMI5IYBdhLWcg3wCWwo#57304538)。 - Bersan

16

我想补充一些可能会令人困惑的内容。 SparseCategoricalCrossentropy 有两个非常重要的参数需要指定。第一个是 from_logits;回想一下,logits 是网络输出的值,这些值没有通过 Softmax(或 Sigmoid)进行归一化处理。第二个参数是 reduction。通常情况下,它被设置为 'auto',这将按照正常方式计算分类交叉熵,即计算 label*log(pred) 的平均值。但是将该值设置为 'none' 实际上将给出分类交叉熵中每个元素的值 label*log(pred),其形状为 (batch_size)。在此列表上执行 reduce_mean 将给出与 reduction='auto' 相同的结果。

# Assuming TF2.x
import tensorflow as tf

model_predictions = tf.constant([[1,2], [3,4], [5,6], [7,8]], tf.float32)
labels_sparse = tf.constant([1, 0, 0, 1 ], tf.float32)
labels_dense = tf.constant([[1,0], [1,0], [1,0], [0,1]], tf.float32)

loss_obj_scc = tf.keras.losses.SparseCategoricalCrossentropy(
    from_logits=True,
    reduction='auto'
)
loss_from_scc = loss_obj_scc(
    labels_sparse,
    model_predictions,
  )


loss_obj_cc = tf.keras.losses.CategoricalCrossentropy(
    from_logits=True,
    reduction='auto'
)
loss_from_cc = loss_obj_cc(
    labels_dense,
    model_predictions,
  )


print(loss_from_scc, loss_from_cc)
>> (<tf.Tensor: shape=(), dtype=float32, numpy=0.8132617>,
 <tf.Tensor: shape=(), dtype=float32, numpy=1.0632616>)
# With `reduction='none'`
loss_obj_scc_red = tf.keras.losses.SparseCategoricalCrossentropy(
    from_logits=True,
    reduction='none')

loss_from_scc_red = loss_obj_scc_red(
    labels_sparse,
    model_predictions,
  )

print(loss_from_scc_red, tf.math.reduce_mean(loss_from_scc_red))

>> (<tf.Tensor: shape=(4,), dtype=float32, numpy=array([0.31326166, 1.3132616 , 
1.3132616 , 0.31326166], dtype=float32)>,
 <tf.Tensor: shape=(), dtype=float32, numpy=0.8132617>)

第三句话就是我的神经网络没能正常工作的原因!我已经到处找过了,这是唯一一个清晰解释的地方!+1 - mauriii

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接