Versão curta:
Suponha que você tenha dois tensores, onde y_hat
contém pontuações computadas para cada classe (por exemplo, de y = W * x + b) e y_true
contém rótulos verdadeiros codificados com um hot hot.
y_hat = ... # Predicted label, e.g. y = tf.matmul(X, W) + b
y_true = ... # True label, one-hot encoded
Se você interpretar as pontuações y_hat
como probabilidades de log não normalizadas, elas serão logits .
Além disso, a perda total de entropia cruzada calculada desta maneira:
y_hat_softmax = tf.nn.softmax(y_hat)
total_loss = tf.reduce_mean(-tf.reduce_sum(y_true * tf.log(y_hat_softmax), [1]))
é essencialmente equivalente à perda total de entropia cruzada calculada com a função softmax_cross_entropy_with_logits()
:
total_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true))
Versão longa:
Na camada de saída da sua rede neural, você provavelmente calculará uma matriz que contém as pontuações da classe para cada uma das suas instâncias de treinamento, como em uma computação y_hat = W*x + b
. Para servir como exemplo, abaixo, criei uma y_hat
matriz como 2 x 3, em que as linhas correspondem às instâncias de treinamento e as colunas correspondem às classes. Então, aqui existem 2 instâncias de treinamento e 3 classes.
import tensorflow as tf
import numpy as np
sess = tf.Session()
# Create example y_hat.
y_hat = tf.convert_to_tensor(np.array([[0.5, 1.5, 0.1],[2.2, 1.3, 1.7]]))
sess.run(y_hat)
# array([[ 0.5, 1.5, 0.1],
# [ 2.2, 1.3, 1.7]])
Observe que os valores não são normalizados (ou seja, as linhas não somam 1). Para normalizá-los, podemos aplicar a função softmax, que interpreta a entrada como probabilidades de log não normalizadas (aka logits ) e gera probabilidades lineares normalizadas.
y_hat_softmax = tf.nn.softmax(y_hat)
sess.run(y_hat_softmax)
# array([[ 0.227863 , 0.61939586, 0.15274114],
# [ 0.49674623, 0.20196195, 0.30129182]])
É importante entender completamente o que a saída softmax está dizendo. Abaixo, mostrei uma tabela que representa mais claramente a saída acima. Pode-se observar que, por exemplo, a probabilidade de a instância de treinamento 1 ser "Classe 2" é 0,619. As probabilidades da classe para cada instância de treinamento são normalizadas, portanto, a soma de cada linha é 1,0.
Pr(Class 1) Pr(Class 2) Pr(Class 3)
,--------------------------------------
Training instance 1 | 0.227863 | 0.61939586 | 0.15274114
Training instance 2 | 0.49674623 | 0.20196195 | 0.30129182
Portanto, agora temos probabilidades de classe para cada instância de treinamento, onde podemos usar o argmax () de cada linha para gerar uma classificação final. Acima, podemos gerar que a instância de treinamento 1 pertença à "Classe 2" e a instância de treinamento 2 pertença à "Classe 1".
Essas classificações estão corretas? Precisamos avaliar os rótulos verdadeiros do conjunto de treinamento. Você precisará de uma y_true
matriz codificada de um ponto quente , onde novamente as linhas estão instâncias de treinamento e as colunas são classes. Abaixo, criei um exemplo y_true
de matriz quente, onde o rótulo verdadeiro para a instância de treinamento 1 é "Classe 2" e o rótulo verdadeiro para a instância de treinamento 2 é "Classe 3".
y_true = tf.convert_to_tensor(np.array([[0.0, 1.0, 0.0],[0.0, 0.0, 1.0]]))
sess.run(y_true)
# array([[ 0., 1., 0.],
# [ 0., 0., 1.]])
A distribuição de probabilidade está y_hat_softmax
próxima da distribuição de probabilidade em y_true
? Podemos usar a perda de entropia cruzada para medir o erro.
Podemos calcular a perda de entropia cruzada em uma linha e ver os resultados. Abaixo, podemos ver que a instância de treinamento 1 tem uma perda de 0,479, enquanto a instância de treinamento 2 tem uma perda maior de 1.200. Esse resultado faz sentido porque, no exemplo acima, y_hat_softmax
mostrou que a maior probabilidade da instância de treinamento 1 era para "Classe 2", que corresponde à instância de treinamento 1 em y_true
; no entanto, a previsão para a instância de treinamento 2 mostrou uma probabilidade mais alta para "Classe 1", que não corresponde à verdadeira classe "Classe 3".
loss_per_instance_1 = -tf.reduce_sum(y_true * tf.log(y_hat_softmax), reduction_indices=[1])
sess.run(loss_per_instance_1)
# array([ 0.4790107 , 1.19967598])
O que realmente queremos é a perda total em todas as instâncias de treinamento. Para que possamos calcular:
total_loss_1 = tf.reduce_mean(-tf.reduce_sum(y_true * tf.log(y_hat_softmax), reduction_indices=[1]))
sess.run(total_loss_1)
# 0.83934333897877944
Usando softmax_cross_entropy_with_logits ()
Em vez disso, podemos calcular a perda total de entropia cruzada usando a tf.nn.softmax_cross_entropy_with_logits()
função, como mostrado abaixo.
loss_per_instance_2 = tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true)
sess.run(loss_per_instance_2)
# array([ 0.4790107 , 1.19967598])
total_loss_2 = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true))
sess.run(total_loss_2)
# 0.83934333897877922
Observe que total_loss_1
e total_loss_2
produz resultados essencialmente equivalentes com algumas pequenas diferenças nos dígitos finais. No entanto, você também pode usar a segunda abordagem: leva menos uma linha de código e acumula menos erro numérico porque o softmax é feito para você dentro de softmax_cross_entropy_with_logits()
.
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(tf.nn.softmax(tf.add(tf.matmul(x,W),b)),y) cost=tf.reduce_mean(cross_entropy)
. Mas quando uso outra maneira,pred=tf.nn.softmax(tf.add(tf.matmul(x,W),b)) cost =tf.reduce_mean(-tf.reduce_sum(y*tf.log(pred),reduction_indices=1))
o resultado é estável e melhor.