我想补充一些可能会令人困惑的内容。 SparseCategoricalCrossentropy
有两个非常重要的参数需要指定。第一个是 from_logits;回想一下,logits 是网络输出的值,这些值没有通过 Softmax(或 Sigmoid)进行归一化处理。第二个参数是 reduction
。通常情况下,它被设置为 'auto'
,这将按照正常方式计算分类交叉熵,即计算 label*log(pred)
的平均值。但是将该值设置为 'none'
实际上将给出分类交叉熵中每个元素的值 label*log(pred)
,其形状为 (batch_size)
。在此列表上执行 reduce_mean
将给出与 reduction='auto'
相同的结果。
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>)
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>)
from_logits=True
,则不需要指定最后一层的激活函数(https://www.tensorflow.org/tutorials/images/classification#compile_the_model)。虽然这并不重要,但它可以使模型更加数值稳定(https://dev59.com/4FMI5IYBdhLWcg3wCWwo#57304538)。 - Bersan