Versione breve:
Supponiamo di avere due tensori, dove y_hatcontiene punteggi calcolati per ciascuna classe (ad esempio, da y = W * x + b) e y_truecontiene etichette vere con codifica a caldo.
y_hat = ... # Predicted label, e.g. y = tf.matmul(X, W) + b
y_true = ... # True label, one-hot encoded
Se interpretate i punteggi y_hatcome probabilità di log non normalizzate, allora sono logit .
Inoltre, la perdita totale di entropia calcolata in questo modo:
y_hat_softmax = tf.nn.softmax(y_hat)
total_loss = tf.reduce_mean(-tf.reduce_sum(y_true * tf.log(y_hat_softmax), [1]))
è sostanzialmente equivalente alla perdita totale di entropia calcolata con la funzione softmax_cross_entropy_with_logits():
total_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true))
Versione lunga:
Nel livello di output della tua rete neurale, probabilmente calcolerai un array che contiene i punteggi delle classi per ciascuna delle tue istanze di allenamento, ad esempio da un calcolo y_hat = W*x + b. Per fare da esempio, di seguito ho creato un y_hatarray come 2 x 3, in cui le righe corrispondono alle istanze di training e le colonne corrispondono alle classi. Quindi qui ci sono 2 istanze di allenamento e 3 lezioni.
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]])
Si noti che i valori non sono normalizzati (ovvero le righe non aggiungono fino a 1). Per normalizzarli, possiamo applicare la funzione softmax, che interpreta l'input come probabilità di log non normalizzate (ovvero logit ) e genera probabilità lineari normalizzate.
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 comprendere appieno cosa sta dicendo l'output di softmax. Di seguito ho mostrato una tabella che rappresenta più chiaramente l'output sopra. Si può vedere che, ad esempio, la probabilità che l'istanza di addestramento 1 sia "Classe 2" è 0,619. Le probabilità di classe per ciascuna istanza di allenamento sono normalizzate, quindi la somma di ogni riga è 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
Quindi ora abbiamo le probabilità di classe per ogni istanza di addestramento, dove possiamo prendere l'argmax () di ogni riga per generare una classificazione finale. Da sopra, possiamo generare che l'istanza di addestramento 1 appartiene a "Classe 2" e l'istanza di addestramento 2 appartiene a "Classe 1".
Queste classificazioni sono corrette? Dobbiamo misurarci con le vere etichette del set di addestramento. Sarà necessario un y_truearray con codifica a caldo , in cui le righe sono istanze di training e le colonne sono classi. Di seguito ho creato un esempio y_trueone-hot array in cui l'etichetta vera per l'istanza di addestramento 1 è "Classe 2" e l'etichetta vera per l'istanza di addestramento 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.]])
La distribuzione di probabilità è y_hat_softmaxvicina alla distribuzione di probabilità in y_true? Possiamo usare la perdita di entropia incrociata per misurare l'errore.

Siamo in grado di calcolare la perdita di entropia su base riga e vedere i risultati. Di seguito possiamo vedere che l'istanza di addestramento 1 ha una perdita di 0.479, mentre l'istanza di addestramento 2 ha una perdita maggiore di 1.200. Questo risultato ha senso perché nel nostro esempio sopra, ha y_hat_softmaxmostrato che la probabilità più alta dell'istanza di allenamento 1 era per "Classe 2", che corrisponde all'istanza di addestramento 1 in y_true; tuttavia, la previsione per l'addestramento dell'istanza 2 ha mostrato la massima probabilità per "Classe 1", che non corrisponde alla vera 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])
Ciò che vogliamo veramente è la perdita totale in tutte le istanze di allenamento. Quindi possiamo calcolare:
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
Utilizzo di softmax_cross_entropy_with_logits ()
Possiamo invece calcolare la perdita totale di entropia incrociata usando la tf.nn.softmax_cross_entropy_with_logits()funzione, come mostrato di seguito.
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
Notare che total_loss_1e total_loss_2produrre risultati sostanzialmente equivalenti con alcune piccole differenze nelle cifre finali. Tuttavia, potresti anche usare il secondo approccio: prende una riga di codice in meno e accumula meno errori numerici perché il softmax è fatto per te all'interno di 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). Ma quando uso un altro modo,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))il risultato è stabile e migliore.