Как работает TensorFlow SparseCategoricalCrossentropy? - PullRequest
2 голосов
/ 17 января 2020

Я пытаюсь понять эту функцию потерь в TensorFlow, но я не понимаю ее. Это SparseCategoricalCrossentropy . Для всех других функций потерь требуются выходы и метки одинаковой формы, для этой функции c потери нет.

Исходный код:

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 ]

4 голосов
/ 17 января 2020

SparseCategoricalCrossentropy и КатегориальныйCrossentropy оба вычисляют категориальную кросс-энтропию. Единственное отличие состоит в том, как должны кодироваться цели / метки.

При использовании 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))

Это в отличие от КатегориальногоCrossentropy, где метки должны быть в горячем виде:

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 более эффективен, когда у вас много категорий.

3 голосов
/ 23 января 2020

Я хотел бы добавить еще несколько вещей, которые могут сбивать с толку. У 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>)
...