Разница в этих значениях: [.5, .89, .6]
, так как его сумма не равна 1. Я думаю, вы ошиблись и вместо этого имели в виду это: [.05, .89, .06]
.
Если вы предоставите значения с суммой, равной 1, то результаты обеих формул будут одинаковыми:
import tensorflow as tf
import numpy as np
y_true = np.array( [[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]])
y_pred = np.array([[.9, .05, .05], [.05, .89, .06], [.05, .01, .94]])
print(tf.keras.losses.categorical_crossentropy(y_true, y_pred).numpy())
print(np.sum(-y_true * np.log(y_pred), axis=1))
#output
#[0.10536052 0.11653382 0.0618754 ]
#[0.10536052 0.11653382 0.0618754 ]
Однако давайте рассмотрим, как рассчитывается тензор y_pred
, если он не масштабируется (сумма значений не равна 1)? Если вы посмотрите на исходный код категориальной кросс-энтропии здесь вы увидите, что он масштабируется на y_pred
, так что класс probas каждого образца суммируется до 1:
if not from_logits:
# scale preds so that the class probas of each sample sum to 1
output /= tf.reduce_sum(output,
reduction_indices=len(output.get_shape()) - 1,
keep_dims=True)
так как мы передали pred, сумма probas которого не равна 1, давайте посмотрим, как эта операция изменит наш тензор [.5, .89, .6]
:
output = tf.constant([.5, .89, .6])
output /= tf.reduce_sum(output,
axis=len(output.get_shape()) - 1,
keepdims=True)
print(output.numpy())
# array([0.2512563 , 0.44723618, 0.30150756], dtype=float32)
Таким образом, он должен быть равен, если мы заменим приведенный выше вывод операции (масштабированный y_pred
) и передадим его вашей собственной реализованной категориальной кросс-энтропии с немасштабированным y_pred
, переходящим в реализацию тензорного потока:
y_true =np.array( [[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]])
#unscaled y_pred
y_pred = np.array([[.9, .05, .05], [.5, .89, .6], [.05, .01, .94]])
print(tf.keras.losses.categorical_crossentropy(y_true, y_pred).numpy())
#scaled y_pred (categorical_crossentropy scales above tensor to this internally)
y_pred = np.array([[.9, .05, .05], [0.2512563 , 0.44723618, 0.30150756], [.05, .01, .94]])
print(np.sum(-y_true * np.log(y_pred), axis=1))
Выход:
[0.10536052 0.80466845 0.0618754 ]
[0.10536052 0.80466846 0.0618754 ]
Теперь давайте изучим результаты вашего второго примера. Почему ваш второй пример показывает другой вывод? Если вы снова проверите исходный код, вы увидите эту строку:
output = tf.clip_by_value(output, epsilon, 1. - epsilon)
который обрезает значения ниже порогового значения. Ваш ввод [0.99999999999, 0.00000000001]
будет преобразован в [0.9999999, 0.0000001]
в этой строке, поэтому он даст вам другой результат:
y_true = np.array([[0, 1]])
y_pred = np.array([[0.99999999999, 0.00000000001]])
print(tf.keras.losses.categorical_crossentropy(y_true, y_pred).numpy())
print(np.sum(-y_true * np.log(y_pred), axis=1))
#now let's first clip the values less than epsilon, then compare loss
epsilon=1e-7
y_pred = tf.clip_by_value(y_pred, epsilon, 1. - epsilon)
print(tf.keras.losses.categorical_crossentropy(y_true, y_pred).numpy())
print(np.sum(-y_true * np.log(y_pred), axis=1))
Выход:
#results without clipping values
[16.11809565]
[25.32843602]
#results after clipping values if there is a value less than epsilon (1e-7)
[16.11809565]
[16.11809565]
18.07.2021