2015-11-10 7 views
15

Stavo guardando il Tensorflow MNIST example for beginners e ha scoperto che in questa parte:Perché l'esempio TensorFlow ha esito negativo quando si aumentano le dimensioni del batch?

for i in range(1000): 
    batch_xs, batch_ys = mnist.train.next_batch(100) 
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys}) 

cambiare la dimensione del lotto da 100 a essere al di sopra 204 fa sì che il modello di non riuscire a convergere. Funziona fino a 204, ma a 205 e qualsiasi numero più alto ho provato, la precisione sarebbe finita a < 10%. È un bug, qualcosa sull'algoritmo, qualcos'altro?

Questo sta eseguendo l'installazione binaria per OS X, sembra essere la versione 0.5.0.

+0

Nel caso in cui siete affetti dallo stesso problema, come ho fatto, si consiglia di controllare qui: http://stackoverflow.com/questions/33712178/tensorflow-nan-bug – user1111929

risposta

28

Stai utilizzando il modello lineare di base nell'esempio per principianti?

Ecco un trucco per eseguire il debug - guardare il cross-entropia come si aumenta la dimensione del lotto (la prima linea è l'esempio, la seconda ho solo aggiunto):

cross_entropy = -tf.reduce_sum(y_*tf.log(y)) 
cross_entropy = tf.Print(cross_entropy, [cross_entropy], "CrossE") 

Ad una dimensione del lotto di 204, si vedrà:

I tensorflow/core/kernels/logging_ops.cc:64] CrossE[92.37558] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[90.107414] 

Ma a 205, vedrete una sequenza come questo, fin dall'inizio:

I tensorflow/core/kernels/logging_ops.cc:64] CrossE[472.02966] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[475.11697] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1418.6655] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1546.3833] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1684.2932] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1420.02] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[1796.0872] 
I tensorflow/core/kernels/logging_ops.cc:64] CrossE[nan] 

Ack - NaN sta mostrando. Fondamentalmente, la grande dimensione del batch sta creando un gradiente così grande che il tuo modello sta andando fuori controllo in modo vertiginoso - gli aggiornamenti che sta applicando sono troppo grandi e superano la direzione in cui dovrebbe andare con un enorme margine.

In pratica, ci sono alcuni modi per risolvere questo problema. È possibile ridurre il tasso di apprendimento da 0,01 a, ad esempio, 0,005, il che si traduce in una precisione finale di 0,92.

train_step = tf.train.GradientDescentOptimizer(0.005).minimize(cross_entropy) 

Oppure si potrebbe usare un più sofisticato algoritmo di ottimizzazione (Adam, Momentum, etc.) che cerca di fare di più per capire la direzione del gradiente. Oppure potresti usare un modello più complesso che ha più parametri liberi su cui disperdere quel grande gradiente.

15

@dga ha dato un'ottima risposta, ma volevo espandermi un po '.

Quando ho scritto il tutorial principianti, ho implementato la funzione di costo in questo modo:

cross_entropy = -tf.reduce_sum (y_ * tf.log (y))

ho scritto in questo modo perché sembra più simile alla definizione matematica di cross-entropy. Ma potrebbe in realtà essere meglio fare qualcosa di simile:

cross_entropy = -tf.reduce_mean (y_ * tf.log (y))

Perché potrebbe essere più bello di utilizzare un mezzo invece di una somma? Bene, se sommiamo, raddoppiando la dimensione del lotto raddoppiamo il costo e raddoppiamo anche la magnitudo del gradiente. A meno che non aggiustiamo il nostro tasso di apprendimento (o usiamo un algoritmo che lo regola per noi, come suggerito da @dga) il nostro addestramento esploderà! Ma se usiamo una media, allora il nostro tasso di apprendimento diventa indipendente dalla nostra dimensione del lotto, che è bello.

Ti incoraggio a controllare Adam (tf.train.AdamOptimizer()). Spesso è più tollerante a manipolare cose che SGD.

+0

Ma questo non cambia tutto ciò che stiamo cercando di ottimizzare. Con i valori '[1, 72, 5]' la differenza è piuttosto significativa. –

+1

'sum' indica il numero di bit/nits/cifre necessari per codificare tutti i dati. Prendendo la media su tutti gli esempi, fornisce il numero medio di bit richiesti per esempio. Ma la versione precedente prende la media su entrambe le dimensioni. Un modello MNIST non addestrato (senza pianificazione) dovrebbe, in modo non prevedibile, richiedere 1 cifra per cifra o 'log (10) ~ = 2.3' nits per cifra. Passa a log10 se lo desideri in cifre. Se si desidera mantenere il significato fisico utilizzare 'costo = -tf.reduce_mean (tf.reduce_sum (self.y_ * tf.log (self.y), 1))'. ovvero: 'somma' tra le classi,' media' sugli articoli. – mdaoust

2

@dga ha ben spiegato la ragione di tale comportamento (la cross_entropy diventa troppo grande) e quindi l'algoritmo non sarà in grado di convergere. Ci sono un paio di modi per risolvere questo problema. Ha già suggerito di diminuire il tasso di apprendimento.

La discesa dei gradienti è l'algoritmo più semplice. Quasi tutti gli altri optimizers lavorerà correttamente:

train_step = tf.train.AdagradOptimizer(0.01).minimize(cross_entropy) 
train_step = tf.train.AdamOptimizer().minimize(cross_entropy) 
train_step = tf.train.FtrlOptimizer(0.01).minimize(cross_entropy) 
train_step = tf.train.RMSPropOptimizer(0.01, 0.1).minimize(cross_entropy) 

Un altro approccio è quello di utilizzare tf.nn.softmax_cross_entropy_with_logits che gestisce instabilità numerici.

15

Nan si verifica quando (0) si verifica 0 * log:

sostituire:

cross_entropy = -tf.reduce_sum(y_*tf.log(y)) 

con:

cross_entropy = -tf.reduce_sum(y_*tf.log(y + 1e-10)) 
+0

Qualsiasi dettaglio su quello che è successo qui sarà utile. – turtle

+0

@turtle il '1e-10' è solo un termine breve per evitare l'instabilità numerica del log quando y = 0 – Conchylicultor

Problemi correlati