TensorFlow SparseCategoricalCrossentropy 是如何工作的?

Posted

技术标签:

【中文标题】TensorFlow SparseCategoricalCrossentropy 是如何工作的?【英文标题】:How does TensorFlow SparseCategoricalCrossentropy work? 【发布时间】:2020-05-04 08:58:03 【问题描述】:

我试图理解 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 提供合适的参数?

【问题讨论】:

【参考方案1】:

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

当使用 SparseCategoricalCrossentropy 时,目标由类别的索引表示(从 0 开始)。您的输出具有 4x2 形状,这意味着您有两个类别。因此,目标应该是一个 4 维向量,其条目为 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))

这与标签应该是 one-hot 编码的分类交叉熵相反:

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激活函数,和categoricalCrossentropy一样? @AralRoca 根据tensorflow页面上的例子,如果设置了from_logits=True那么就不需要指定最后一层的激活(tensorflow.org/tutorials/images/…)。没关系,但它使它在数值上更稳定 (***.com/a/57304538/2076973)【参考方案2】:

我想添加一些可能会令人困惑的内容。 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

以上是关于TensorFlow SparseCategoricalCrossentropy 是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

如何让 Tensorflow Profiler 在 Tensorflow 2.5 中使用“tensorflow-macos”和“tensorflow-metal”工作

python [test tensorflow] test tensorflow installation #tensorflow

关于tensorflow的显存占用问题

java调用tensorflow训练好的模型

tensorflow新手必看,tensorflow入门教程,tensorflow示例代码

tensorflow 如何在线训练模型