Version courte:
Supposons que vous ayez deux tenseurs, où y_hat
contient les scores calculés pour chaque classe (par exemple, à partir de y = W * x + b) et y_true
contient les véritables étiquettes codées à chaud.
y_hat = ... # Predicted label, e.g. y = tf.matmul(X, W) + b
y_true = ... # True label, one-hot encoded
Si vous interprétez les scores y_hat
comme des probabilités logarithmiques non normalisées, ce sont des logits .
De plus, la perte totale d'entropie croisée calculée de cette manière:
y_hat_softmax = tf.nn.softmax(y_hat)
total_loss = tf.reduce_mean(-tf.reduce_sum(y_true * tf.log(y_hat_softmax), [1]))
est essentiellement équivalent à la perte d'entropie croisée totale calculée avec la fonction softmax_cross_entropy_with_logits()
:
total_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true))
Version longue:
Dans la couche de sortie de votre réseau de neurones, vous calculerez probablement un tableau qui contient les scores de classe pour chacune de vos instances d'entraînement, par exemple à partir d'un calcul y_hat = W*x + b
. Pour servir d'exemple, ci-dessous, j'ai créé un y_hat
tableau 2 x 3, où les lignes correspondent aux instances de formation et les colonnes correspondent aux classes. Il y a donc ici 2 instances de formation et 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]])
Notez que les valeurs ne sont pas normalisées (c'est-à-dire que les lignes ne totalisent pas 1). Afin de les normaliser, nous pouvons appliquer la fonction softmax, qui interprète l'entrée comme des probabilités de log non normalisées (alias logits ) et génère des probabilités linéaires normalisées.
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]])
Il est important de bien comprendre ce que la sortie softmax dit. Ci-dessous, j'ai montré un tableau qui représente plus clairement la sortie ci-dessus. On peut voir que, par exemple, la probabilité que l'instance de formation 1 soit de "classe 2" est de 0,619. Les probabilités de classe pour chaque instance de formation sont normalisées, la somme de chaque ligne est donc de 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
Nous avons donc maintenant des probabilités de classe pour chaque instance de formation, où nous pouvons prendre l'argmax () de chaque ligne pour générer une classification finale. De ci-dessus, nous pouvons générer que l'instance de formation 1 appartient à la "classe 2" et l'instance de formation 2 appartient à la "classe 1".
Ces classifications sont-elles correctes? Nous devons mesurer par rapport aux véritables étiquettes de l'ensemble de formation. Vous aurez besoin d'un y_true
tableau codé à chaud , où encore les lignes sont des instances d'apprentissage et les colonnes sont des classes. Ci-dessous, j'ai créé un exemple d' y_true
un tableau à chaud où la véritable étiquette pour l'instance de formation 1 est "Classe 2" et la véritable étiquette pour l'instance de formation 2 est "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.]])
La distribution de probabilité est-elle y_hat_softmax
proche de la distribution de probabilité de y_true
? Nous pouvons utiliser la perte d'entropie croisée pour mesurer l'erreur.
Nous pouvons calculer la perte d'entropie croisée par ligne et voir les résultats. Ci-dessous, nous pouvons voir que l'instance de formation 1 a une perte de 0,479, tandis que l'instance de formation 2 a une perte plus élevée de 1,200. Ce résultat est logique parce que dans notre exemple ci-dessus, a y_hat_softmax
montré que la probabilité la plus élevée de l'instance de formation 1 était pour "Classe 2", qui correspond à l'instance de formation 1 dans y_true
; cependant, la prévision pour l'instance de formation 2 a montré une probabilité la plus élevée pour "Classe 1", qui ne correspond pas à la vraie 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])
Ce que nous voulons vraiment, c'est la perte totale sur toutes les instances de formation. Nous pouvons donc calculer:
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
Utilisation de softmax_cross_entropy_with_logits ()
Nous pouvons plutôt calculer la perte d'entropie croisée totale en utilisant la tf.nn.softmax_cross_entropy_with_logits()
fonction, comme indiqué ci-dessous.
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
Notez cela total_loss_1
et total_loss_2
produisez des résultats essentiellement équivalents avec quelques petites différences dans les tout derniers chiffres. Cependant, vous pourriez aussi bien utiliser la deuxième approche: elle prend une ligne de code en moins et accumule moins d'erreur numérique car le softmax est fait pour vous à l'intérieur 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)
. Mais quand j'utilise une autre façon,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))
le résultat est stable et meilleur.