Cause comuni di nans durante l'allenamento


86

Ho notato che NANviene introdotto un evento frequente durante l'allenamento .

Spesso sembra essere introdotto da pesi nel prodotto interno / completamente connesso o strati di convoluzione che esplodono.

Questo accade perché il calcolo del gradiente sta esplodendo? O è a causa dell'inizializzazione del peso (in tal caso, perché l'inizializzazione del peso ha questo effetto)? O è probabilmente causato dalla natura dei dati di input?

La domanda generale qui è semplicemente: qual è il motivo più comune per cui le NAN si verificano durante la formazione? In secondo luogo, quali sono alcuni metodi per combatterlo (e perché funzionano)?


Stai chiamando funzioni MATLAB specifiche? È tutto il tuo codice?
Matthew Gunn

2
@ MatthewGunn Non credo che questa domanda sia specifica di Matlab, ma piuttosto caffecorrelata.
Shai

Risposte:


137

Buona domanda.
Mi sono imbattuto in questo fenomeno più volte. Ecco le mie osservazioni:


Gradiente esplodere

Motivo: grandi gradienti mettono fuori strada il processo di apprendimento.

Cosa dovresti aspettarti: guardando il registro di runtime, dovresti guardare i valori di perdita per iterazione. Noterai che la perdita inizia a crescere in modo significativo da iterazione a iterazione, alla fine la perdita sarà troppo grande per essere rappresentata da una variabile in virgola mobile e lo diventerà nan.

Cosa puoi fare: Diminuisci base_lr(nel solver.prototxt) di un ordine di grandezza (almeno). Se hai diversi livelli di perdita, dovresti ispezionare il registro per vedere quale livello è responsabile loss_weightdell'esplosione del gradiente e diminuire il (in train_val.prototxt) per quel livello specifico, invece del generale base_lr.


Cattiva politica e parametri del tasso di apprendimento

Motivo: caffe non riesce a calcolare un tasso di apprendimento valido e ottiene 'inf'o 'nan', invece, questo tasso non valido moltiplica tutti gli aggiornamenti e quindi invalida tutti i parametri.

Cosa dovresti aspettarti: guardando il registro di runtime, dovresti vedere che il tasso di apprendimento stesso diventa 'nan', ad esempio:

... sgd_solver.cpp:106] Iteration 0, lr = -nan

Cosa puoi fare: correggi tutti i parametri che influenzano la velocità di apprendimento nel tuo 'solver.prototxt'file.
Ad esempio, se usi lr_policy: "poly"e dimentichi di definire il max_iterparametro, ti ritroverai con lr = nan...
Per ulteriori informazioni sulla velocità di apprendimento in caffe, vedi questo thread .


Funzione di perdita difettosa

Motivo: a volte i calcoli della perdita negli strati di perdita fanno nanapparire s. Ad esempio, InfogainLosslivello di alimentazione con valori non normalizzati , utilizzo di livello di perdita personalizzato con bug, ecc.

Cosa dovresti aspettarti: guardando il registro di runtime probabilmente non noterai nulla di insolito: la perdita sta diminuendo gradualmente e all'improvviso nanappare un .

Cosa puoi fare: verifica se riesci a riprodurre l'errore, aggiungi la stampa al livello di perdita ed esegui il debug dell'errore.

Ad esempio: una volta ho utilizzato una perdita che normalizzava la penalità in base alla frequenza di occorrenza dell'etichetta in un batch. È successo che se una delle etichette di addestramento non appariva affatto nel batch, la perdita calcolata produceva nans. In quel caso, lavorare con lotti abbastanza grandi (rispetto al numero di etichette nel set) è stato sufficiente per evitare questo errore.


Ingresso difettoso

Motivo: hai un input con nandentro!

Cosa dovresti aspettarti: una volta che il processo di apprendimento "raggiunge" questo errore di input - output diventa nan. Guardando il registro di runtime probabilmente non noterai nulla di insolito: la perdita diminuisce gradualmente e all'improvviso nanappare un .

Cosa puoi fare: ricostruire i tuoi set di dati di input (lmdb / leveldn / hdf5 ...) assicurati di non avere file di immagini errati nel tuo set di addestramento / convalida. Per il debug puoi costruire una semplice rete che legge lo strato di input, ha una perdita fittizia sopra di essa e percorre tutti gli input: se uno di loro è difettoso, dovrebbe produrre anche questa falsa rete nan.


passo più grande della dimensione del kernel nel "Pooling"livello

Per qualche ragione, la scelta di stride> kernel_sizeper il raggruppamento potrebbe risultare con nans. Per esempio:

layer {
  name: "faulty_pooling"
  type: "Pooling"
  bottom: "x"
  top: "y"
  pooling_param {
    pool: AVE
    stride: 5
    kernel: 3
  }
}

risultati con nans in y.


Instabilità in "BatchNorm"

È stato riferito che in alcuni "BatchNorm"livelli di impostazioni potrebbero essere emessi dei messaggi a nancausa di instabilità numeriche.
Questo problema è stato sollevato in bvlc / caffe e PR # 5136 sta tentando di risolverlo.


Recentemente, sono venuto a conoscenza del debug_infoflag: l'impostazione debug_info: truein 'solver.prototxt'farà stampare caffe per registrare più informazioni di debug (comprese le grandezze del gradiente e i valori di attivazione) durante l'allenamento: queste informazioni possono aiutare a individuare ingrandimenti di gradiente e altri problemi nel processo di allenamento .


Grazie, come si interpretano quei numeri? Quali sono questi numeri? pastebin.com/DLYgXK5v perché c'è un solo numero per livello di output !? come dovrebbero apparire quei numeri in modo che qualcuno sappia che c'è un problema o che non ce n'è !?
Rika

@ Hossein, questo è esattamente ciò di cui tratta questo post .
Shai

Grazie per questa risposta. Ricevo una perdita NAN per un'applicazione di segmentazione delle immagini addestrata con perdita DICE (anche dopo aver aggiunto una piccola costante epsilon / levigatezza). Il mio set di dati contiene alcune immagini la cui verità fondamentale corrispondente che non contiene alcuna etichetta in primo piano e quando ho rimosso queste immagini dall'addestramento, la perdita è stata stabilizzata. Non sono sicuro del motivo?
samra irshad

@samrairs, hai provato ad aumentare l'epsilon nella perdita DICE?
Shai

Si l'ho fatto. Ho aperto il post allo stack-overflow e ho incollato l'evoluzione della perdita per alcune epoche. Ecco il riferimento: stackoverflow.com/questions/62259112/...
Samra Irshad

5

Nel mio caso, la causa era non impostare il bias negli strati di convoluzione / deconvoluzione.

Soluzione: aggiungere quanto segue ai parametri del livello di convoluzione.

bias_filler {tipo: valore "costante": 0}


come sarebbe in matconvnet? Ho qualcosa come "biases" .init_bias * ones (1,4, single)
h612

4

Questa risposta non riguarda una causa per nans, ma piuttosto propone un modo per aiutare a eseguire il debug. Puoi avere questo livello Python:

class checkFiniteLayer(caffe.Layer):
  def setup(self, bottom, top):
    self.prefix = self.param_str
  def reshape(self, bottom, top):
    pass
  def forward(self, bottom, top):
    for i in xrange(len(bottom)):
      isbad = np.sum(1-np.isfinite(bottom[i].data[...]))
      if isbad>0:
        raise Exception("checkFiniteLayer: %s forward pass bottom %d has %.2f%% non-finite elements" %
                        (self.prefix,i,100*float(isbad)/bottom[i].count))
  def backward(self, top, propagate_down, bottom):
    for i in xrange(len(top)):
      if not propagate_down[i]:
        continue
      isf = np.sum(1-np.isfinite(top[i].diff[...]))
        if isf>0:
          raise Exception("checkFiniteLayer: %s backward pass top %d has %.2f%% non-finite elements" %
                          (self.prefix,i,100*float(isf)/top[i].count))

L'aggiunta di questo livello al tuo train_val.prototxtin determinati punti che sospetti possa causare problemi:

layer {
  type: "Python"
  name: "check_loss"
  bottom: "fc2"
  top: "fc2"  # "in-place" layer
  python_param {
    module: "/path/to/python/file/check_finite_layer.py" # must be in $PYTHONPATH
    layer: "checkFiniteLayer"
    param_str: "prefix-check_loss" # string for printouts
  }
}

1

learning_rate è alto e dovrebbe essere diminuito La precisione nel codice RNN era nan, con selezionare il valore basso per il tasso di apprendimento che corregge


-1

Stavo cercando di costruire un autoencoder sparso e avevo diversi livelli per indurre la scarsità. Durante l'esecuzione della mia rete, ho incontrato i NaN. Rimuovendo alcuni strati (nel mio caso, ho effettivamente dovuto rimuovere 1), ho scoperto che i NaN sono scomparsi. Quindi, immagino che troppa scarsità possa portare anche a NaN (potrebbero essere stati invocati alcuni calcoli 0/0 !?)


potresti essere un po 'più specifico? potete fornire dettagli sulla configurazione che aveva se nanla configurazione fissa? che tipo di strati? quali parametri?
Shai

1
@shai avevo usato diversi livelli InnerProduct (lr_mult 1, decay_mult 1, lr_mult 2, decay_mult 0, xavier, std: 0.01) ciascuno seguito da ReLU (tranne l'ultimo). Lavoravo con MNIST e, se ricordo bene, l'architettura era 784 -> 1000 -> 500 -> 250 -> 100 -> 30 (e una fase di decodifica simmetrica); la rimozione dello strato 30 insieme al suo ReLU ha fatto sparire i NaN.
LKB
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.