Che cosa sono logits, softmax e softmax_cross_entropy_with_logits?


351

Stavo esaminando i documenti API di Tensorflow qui . Nella documentazione di tensorflow, hanno usato una parola chiave chiamata logits. Che cos'è? In molti metodi nei documenti API è scritto come

tf.nn.softmax(logits, name=None)

Se ciò che è scritto logitssono solo quelli Tensors, perché mantenere un nome diverso come logits?

Un'altra cosa è che ci sono due metodi che non sono riuscito a differenziare. Li avevamo

tf.nn.softmax(logits, name=None)
tf.nn.softmax_cross_entropy_with_logits(logits, labels, name=None)

Quali sono le differenze tra loro? I documenti non mi sono chiari. So cosa tf.nn.softmaxfa. Ma non l'altro. Un esempio sarà davvero utile.

Risposte:


427

Logits significa semplicemente che la funzione opera sull'output non scalato dei livelli precedenti e che la scala relativa per comprendere le unità è lineare. Significa, in particolare, che la somma degli input potrebbe non essere uguale a 1, che i valori non sono probabilità (potresti avere un input di 5).

tf.nn.softmaxproduce solo il risultato dell'applicazione della funzione softmax a un tensore di input. Il softmax "schiaccia" gli input in modo che sum(input) = 1: sia un modo di normalizzare. La forma dell'output di un softmax è la stessa dell'input: normalizza solo i valori. Le uscite di softmax possono essere interpretate come probabilità.

a = tf.constant(np.array([[.1, .3, .5, .9]]))
print s.run(tf.nn.softmax(a))
[[ 0.16838508  0.205666    0.25120102  0.37474789]]

Al contrario, tf.nn.softmax_cross_entropy_with_logitscalcola l'entropia crociata del risultato dopo aver applicato la funzione softmax (ma lo fa insieme in un modo matematicamente più attento). È simile al risultato di:

sm = tf.nn.softmax(x)
ce = cross_entropy(sm)

L'entropia crociata è una metrica di riepilogo: somma attraverso gli elementi. L'output di tf.nn.softmax_cross_entropy_with_logitsun [2,5]tensore di forma è di forma [2,1](la prima dimensione viene considerata come il batch).

Se vuoi fare l'ottimizzazione per ridurre al minimo l'entropia crociata E stai realizzando il softmax dopo l'ultimo strato, dovresti usarlo tf.nn.softmax_cross_entropy_with_logitsinvece di farlo da solo, perché copre casi angolari numericamente instabili nel modo matematicamente giusto. Altrimenti, finirai per hackerarlo aggiungendo piccoli epsilon qua e là.

Modificato il 02-02-2016: se si dispone di etichette a classe singola, in cui un oggetto può appartenere solo a una classe, è ora possibile prendere in considerazione l'utilizzo in tf.nn.sparse_softmax_cross_entropy_with_logitsmodo da non dover convertire le etichette in un denso array one-hot. Questa funzione è stata aggiunta dopo la versione 0.6.0.


1
A proposito di softmax_cross_entropy_with_logits, non so se lo uso correttamente. Il risultato non è così stabile nel mio codice. Lo stesso codice viene eseguito due volte, la precisione totale cambia da 0,6 a 0,8. 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.
Rida,

15
Sei double-softmaxing nella tua prima riga. softmax_cross_entropy_with_logits prevede log non scalati, non l'output di tf.nn.softmax. Vuoi solo tf.nn.softmax_cross_entropy_with_logits(tf.add(tf.matmul(x, W, b))nel tuo caso.
Data

7
@dga Penso che tu abbia un refuso nel tuo codice, i bbisogni devono essere al di fuori della parentesi,tf.nn.softmax_cross_entropy_with_logits(tf.add(tf.matmul(x, W), b)
jrieke

1
cosa significa "che la scala relativa per comprendere le unità è lineare". parte della tua prima frase significa?
Charlie Parker,

5
Eseguito l'upgrade, ma la tua risposta è leggermente errata quando dici che "[t] la forma dell'output di un softmax è la stessa dell'input - normalizza semplicemente i valori". Softmax non solo "schiaccia" i valori in modo che la loro somma sia uguale a 1. Inoltre li ridistribuisce, e questo è probabilmente il motivo principale per cui viene utilizzato. Vedi stackoverflow.com/questions/17187507/… , in particolare la risposta di Piotr Czapla.
Paolo Perrotta,

282

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.

Formula per perdita di entropia crociata

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().


Confermo tutto quanto sopra. Il semplice codice: M = tf.random.uniform([100, 10], minval=-1.0, maxval=1.0); labels = tf.one_hot(tf.random.uniform([100], minval=0, maxval=10 , dtype='int32'), 10); tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=M) - tf.reduce_sum(-tf.nn.log_softmax(M)*tf.one_hot(labels, 10), -1)restituisce quasi zero ovunque
Sami A. Haija il

51

tf.nn.softmaxcalcola la propagazione diretta attraverso uno strato di softmax. Lo usi durante la valutazione del modello quando calcoli le probabilità che il modello genera.

tf.nn.softmax_cross_entropy_with_logitscalcola il costo per uno strato di softmax. Viene utilizzato solo durante l' allenamento .

I log sono le probabilità di log non normalizzate che generano il modello (i valori emessi prima che la normalizzazione del softmax sia applicata a loro).


2
Capisco. Perché non chiamare la funzione, tf.nn.softmax_cross_entropy_sans_normalization?
auro,

8
@auro perché normalizza i valori (internamente) durante il calcolo dell'entropia incrociata. Il punto tf.nn.softmax_cross_entropy_with_logitsè valutare quanto il modello si discosta dalle etichette in oro, non fornire un output normalizzato.
Erickrf,

1
Nel caso di utilizzo di tf.nn.sparse_softmax_cross_entropy_with_logits () calcola il costo di uno strato di softmax sparse, e quindi dovrebbe essere usato solo durante l'allenamento quale sarebbe l'alternativa quando si esegue il modello con nuovi dati, è possibile ottenere probabilità da questo uno.
SerialDev

2
@SerialDev, non è possibile ottenere le probabilità da tf.nn.sparse_softmax_cross_entropy_with_logits. Per ottenere le probabilità utilizzare tf.nn.softmax.
Nandeesh,

4

Le risposte sopra hanno una descrizione sufficiente per la domanda posta.

In aggiunta a ciò, Tensorflow ha ottimizzato l'operazione di applicazione della funzione di attivazione e quindi il calcolo dei costi utilizzando la propria attivazione seguita da funzioni di costo. Quindi è una buona pratica usare:tf.nn.softmax_cross_entropy() oltretf.nn.softmax(); tf.nn.cross_entropy()

Puoi trovare una differenza evidente tra loro in un modello ad alta intensità di risorse.


1
la risposta sopra chiaramente non ha letto la domanda .. Dicono tutti le stesse cose, che sono note, ma non rispondono alla domanda stessa
Euler_Salter

@abhish Intendevi, tf.nn.softmaxseguito da tf.losses.softmax_cross_entropy?
ankurrc,

4

Ciò che mai accade softmaxè il logit, questo è ciò che J. Hinton ripete continuamente nei video di Coursera.


1

Risposta compatibile Tensorflow 2.0 : le spiegazioni dgae stackoverflowuser2010sono molto dettagliate su Logits e le relative funzioni.

Tutte queste funzioni, se utilizzate , funzioneranno correttamente Tensorflow 1.x, ma se si esegue la migrazione del codice da 1.x (1.14, 1.15, etc)a 2.x (2.0, 2.1, etc..), l'utilizzo di tali funzioni provoca errori.

Quindi, specificando le chiamate compatibili 2.0 per tutte le funzioni, abbiamo discusso in precedenza, se migriamo da 1.x to 2.x, a beneficio della comunità.

Funzioni in 1.x :

  1. tf.nn.softmax
  2. tf.nn.softmax_cross_entropy_with_logits
  3. tf.nn.sparse_softmax_cross_entropy_with_logits

Funzioni rispettive durante la migrazione da 1.xa 2.x :

  1. tf.compat.v2.nn.softmax
  2. tf.compat.v2.nn.softmax_cross_entropy_with_logits
  3. tf.compat.v2.nn.sparse_softmax_cross_entropy_with_logits

Per ulteriori informazioni sulla migrazione da 1.xa 2.x, consultare questa Guida alla migrazione .


0

Un'altra cosa che vorrei sicuramente evidenziare come logit è solo un output non elaborato, in genere l'output dell'ultimo livello. Anche questo può essere un valore negativo. Se lo utilizziamo per la valutazione "cross entropia" come indicato di seguito:

-tf.reduce_sum(y_true * tf.log(logits))

allora non funzionerà. Poiché il registro di -ve non è definito. Quindi, utilizzando o l'attivazione di softmax, si supererà questo problema.

Questa è la mia comprensione, per favore correggimi se sbaglio.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.