Häufige Ursachen für Nans während des Trainings

85

Ich habe festgestellt, dass ein häufiges Auftreten während des Trainings NANeingeführt wird.

Oft scheint es durch Gewichte in inneren Produkt- / vollständig verbundenen oder Faltungsschichten, die explodieren, eingeführt zu werden.

Tritt dies auf, weil die Gradientenberechnung explodiert? Oder liegt es an der Gewichtsinitialisierung (wenn ja, warum hat die Gewichtsinitialisierung diesen Effekt)? Oder liegt es wahrscheinlich an der Art der Eingabedaten?

Die übergeordnete Frage lautet hier einfach: Was ist der häufigste Grund für das Auftreten von NANs während des Trainings? Und zweitens, was sind einige Methoden, um dies zu bekämpfen (und warum funktionieren sie)?

Aidan Gomez
quelle
Rufen Sie bestimmte MATLAB-Funktionen auf? Ist das alles dein eigener Code?
Matthew Gunn
2
@MatthewGunn Ich denke nicht, dass diese Frage matlab-spezifisch ist, sondern eher im Zusammenhang steht caffe.
Shai

Antworten:

133

Gute Frage.
Ich bin mehrmals auf dieses Phänomen gestoßen. Hier sind meine Beobachtungen:


Gradient explodieren

Grund: Große Farbverläufe bringen den Lernprozess aus der Bahn.

Was Sie erwarten sollten: Wenn Sie sich das Laufzeitprotokoll ansehen, sollten Sie sich die Verlustwerte pro Iteration ansehen. Sie werden feststellen, dass der Verlust von Iteration zu Iteration erheblich zunimmt. Schließlich ist der Verlust zu groß, um durch eine Gleitkommavariable dargestellt zu werden, und er wird nan.

Was können Sie tun: Verringern Sie die base_lr(in der solver.prototxt) um eine Größenordnung (mindestens). Wenn Sie mehrere Verlustschichten haben, sollten Sie das Protokoll überprüfen, um loss_weightfestzustellen, welche Schicht für das Aufblasen des Gradienten verantwortlich ist, und die (in train_val.prototxt) für diese bestimmte Schicht anstelle der allgemeinen Schicht verringern base_lr.


Schlechte Lernratenpolitik und Parameter

Grund: caffe kann keine gültige Lernrate berechnen und erhält 'inf'oder 'nan'stattdessen multipliziert diese ungültige Rate alle Aktualisierungen und macht somit alle Parameter ungültig.

Was Sie erwarten sollten: Wenn Sie sich das Laufzeitprotokoll ansehen, sollten Sie feststellen, dass die Lernrate selbst zum 'nan'Beispiel wird:

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

Was können Sie tun: Korrigieren Sie alle Parameter, die sich auf die Lernrate in Ihrer 'solver.prototxt'Datei auswirken.
Wenn Sie beispielsweise Parameter verwenden lr_policy: "poly"und vergessen, diese zu definieren max_iter, erhalten Sie lr = nan...
Weitere Informationen zur Lernrate in caffe finden Sie in diesem Thread .


Fehlerhafte Verlustfunktion

Grund: Manchmal führen die Berechnungen des Verlusts in den Verlustschichten dazu, dass nans angezeigt wird. Beispiel: Fütterungsschicht InfogainLossmit nicht normalisierten Werten , Verwendung einer benutzerdefinierten Verlustschicht mit Fehlern usw.

Was Sie erwarten sollten: Wenn Sie sich das Laufzeitprotokoll ansehen, werden Sie wahrscheinlich nichts Ungewöhnliches bemerken: Der Verlust nimmt allmählich ab und plötzlich nanerscheint ein.

Was können Sie tun: Überprüfen Sie, ob Sie den Fehler reproduzieren können, fügen Sie der Verlustschicht einen Ausdruck hinzu und debuggen Sie den Fehler.

Zum Beispiel: Einmal habe ich einen Verlust verwendet, der die Strafe durch die Häufigkeit des Auftretens von Etiketten in einer Charge normalisiert hat. Es ist einfach so passiert, dass, wenn eines der Trainingsetiketten überhaupt nicht im Stapel erschien - der berechnete Verlust nans erzeugt. In diesem Fall war es ausreichend, mit ausreichend großen Chargen (in Bezug auf die Anzahl der Etiketten im Satz) zu arbeiten, um diesen Fehler zu vermeiden.


Fehlerhafte Eingabe

Grund: Sie haben eine Eingabe mit nandarin!

Was Sie erwarten sollten: Sobald der Lernprozess "trifft", wird diese fehlerhafte Eingabe - Ausgabe nan. Wenn Sie sich das Laufzeitprotokoll ansehen, werden Sie wahrscheinlich nichts Ungewöhnliches bemerken: Der Verlust nimmt allmählich ab und plötzlich nanerscheint ein.

Was können Sie tun ? Erstellen Sie Ihre Eingabedatensätze (lmdb / leveldn / hdf5 ...) neu, und stellen Sie sicher, dass Ihr Trainings- / Validierungssatz keine fehlerhaften Bilddateien enthält. Für das Debuggen können Sie ein einfaches Netz erstellen, das die Eingabeebene liest, einen Dummy-Verlust aufweist und alle Eingaben durchläuft: Wenn eine davon fehlerhaft ist, sollte dieses Dummy-Netz auch erzeugen nan.


Schritt größer als die Kernelgröße in der "Pooling"Schicht

Aus irgendeinem Grund kann die Auswahl von stride> kernel_sizefür das Pooling zu nans führen. Zum Beispiel:

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

Ergebnisse mit nans in y.


Instabilitäten in "BatchNorm"

Es wurde berichtet, dass unter einigen Einstellungen die "BatchNorm"Schicht nanaufgrund numerischer Instabilitäten s ausgeben kann .
Dieses Problem wurde in bvlc / caffe angesprochen und PR # 5136 versucht, es zu beheben.


Vor kurzem wurde mir bewusst, debug_infoFlagge: Einstellung debug_info: truein 'solver.prototxt'caffe Druck machen mehr Debug - Informationen (einschließlich Gradientengrößen und Aktivierungswerte) während des Trainings zu protokollieren: Diese Informationen können in Spek Gradienten blowups und andere Probleme in den Trainingsprozess helfen .

Shai
quelle
Danke, wie interpretiert man diese Zahlen? Was sind diese Zahlen? pastebin.com/DLYgXK5v Warum gibt es nur eine Nummer pro Layer-Ausgabe? Wie sollen diese Zahlen aussehen, damit jemand weiß, dass es ein Problem gibt oder es kein Problem gibt?
Rika
@Hossein genau darum geht es in diesem Beitrag .
Shai
Danke für diese Antwort. Ich erhalte einen NAN-Verlust für eine Bildsegmentierungsanwendung, die mit DICE-Verlust trainiert wurde (auch nach Hinzufügen einer kleinen Epsilon / Glättungskonstante). Mein Datensatz enthält einige Bilder, deren entsprechende Grundwahrheit keine Vordergrundbezeichnung enthält, und als ich diese Bilder aus dem Training entfernte, wurde der Verlust stabilisiert. Ich bin mir nicht sicher, warum das so ist?
Samra Irshad
@samrairshad hast du versucht, das Epsilon im Würfelverlust zu erhöhen?
Shai
Ja, habe ich. Ich habe den Post bei Stack-Overflow geöffnet und die Verlustentwicklung für einige Epochen eingefügt. Hier ist die Referenz: stackoverflow.com/questions/62259112/…
samra irshad
5

In meinem Fall war es die Ursache, die Vorspannung in den Faltungs- / Entfaltungsschichten nicht einzustellen.

Lösung: Fügen Sie den Parametern der Faltungsschicht Folgendes hinzu.

Bias_Filler {Typ: "Konstante" Wert: 0}

Izady
quelle
Wie würde das in matconvnet aussehen? Ich habe so etwas wie 'voreingenommenheiten' .init_bias * one (1,4, single)
h612
4

Diese Antwort handelt nicht von einer Ursache für nans, sondern schlägt einen Weg vor, um das Debuggen zu unterstützen. Sie können diese Python-Ebene haben:

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

Das Hinzufügen dieser Ebene zu Ihrer train_val.prototxtan bestimmten Stellen, von denen Sie vermuten, dass sie Probleme verursachen können:

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
  }
}
Shai
quelle
1

learning_rate ist hoch und sollte verringert werden. Die Genauigkeit im RNN-Code war nan, wobei der niedrige Wert für die festgelegte Lernrate ausgewählt wird

Mohammad Rasoul Tanhatalab
quelle
-1

Ich habe versucht, einen spärlichen Autoencoder zu bauen, und hatte mehrere Schichten darin, um Sparsamkeit zu induzieren. Während ich mein Netz betrieb, stieß ich auf die NaNs. Beim Entfernen einiger Schichten (in meinem Fall musste ich tatsächlich 1 entfernen) stellte ich fest, dass die NaNs verschwunden waren. Ich denke also, dass zu viel Sparsamkeit auch zu NaNs führen kann (einige 0/0-Berechnungen wurden möglicherweise aufgerufen!?)

LKB
quelle
Kannst du etwas genauer sein? Können Sie Details zu der Konfiguration mit nans und der festen Konfiguration angeben? Welche Art von Schichten? Welche Parameter?
Shai
1
@shai Ich hatte mehrere InnerProduct-Schichten (lr_mult 1, zerfall_mult 1, lr_mult 2, zerfall_mult 0, xavier, std: 0,01) verwendet, gefolgt von ReLU (mit Ausnahme der letzten). Ich habe mit MNIST gearbeitet, und wenn ich mich richtig erinnere, war die Architektur 784 -> 1000 -> 500 -> 250 -> 100 -> 30 (und eine symmetrische Decoderphase); Durch Entfernen der 30-Schicht zusammen mit ihrer ReLU verschwanden die NaNs.
LKB