Deep-Learning Nan Verlust Gründe


77

Vielleicht eine zu allgemeine Frage, aber kann jemand erklären, was dazu führen würde, dass ein Faltungs-Neuronales Netz auseinander geht?

Besonderheiten:

Ich verwende das iris_training-Modell von Tensorflow mit einigen meiner eigenen Daten und bekomme es immer wieder

FEHLER: Tensorfluss: Modell divergiert mit Verlust = NaN.

Zurück verfolgen...

tensorflow.contrib.learn.python.learn.monitors.NanLossDuringTrainingError: NaN-Verlust während des Trainings.

Traceback entstand mit Zeile:

 tf.contrib.learn.DNNClassifier(feature_columns=feature_columns,
                                        hidden_units=[300, 300, 300],
                                        #optimizer=tf.train.ProximalAdagradOptimizer(learning_rate=0.001, l1_regularization_strength=0.00001),                                                          
                                        n_classes=11,
                                        model_dir="/tmp/iris_model")

Ich habe versucht, den Optimierer anzupassen, eine Null für die Lernrate zu verwenden und keinen Optimierer zu verwenden. Alle Einblicke in Netzwerkschichten, Datengröße usw. sind willkommen.


5
Es ist eine natürliche Eigenschaft des stochastischen Gradientenabstiegs. Wenn die Lernrate zu groß ist, kann SGD ins Unendliche divergieren
Jaroslaw Bulatow

@YaroslavBulatov Ich habe es mit diesem AdagradOptiizer mit einer Lernrate von etwa 1E-15 versucht. Vielleicht sind meine Daten nicht für SGD geeignet. Können Sie einen anderen Algorithmus vorschlagen? Noch neu in Tensorflow und Deep Learning.
Kostenlose URL

In meinem Fall hat die Normalisierung geholfen
Dmitry

Die Lösung für mich war tf.losses.sparse_softmax_cross_entropy(y, logits)anstelle meiner eigenen Implementierung von Safe Softmax mittf.nn.Softmax
Eduardo Reis

Antworten:


121

Es gibt viele Dinge, die ich gesehen habe, wie ein Modell auseinander geht.

  1. Zu hohe Lernrate. Sie können oft feststellen, ob dies der Fall ist, wenn der Verlust zuzunehmen beginnt und dann ins Unendliche abweicht.

  2. Ich bin mit dem DNNClassifier nicht vertraut, aber ich vermute, dass er die kategoriale Cross-Entropy-Cost-Funktion verwendet. Dies beinhaltet das Protokoll der Vorhersage, das divergiert, wenn sich die Vorhersage Null nähert. Aus diesem Grund fügen die Leute der Vorhersage normalerweise einen kleinen Epsilon-Wert hinzu, um diese Divergenz zu verhindern. Ich vermute, dass der DNNClassifier dies wahrscheinlich tut oder den Tensorflow opp dafür verwendet. Wahrscheinlich nicht das Problem.

  3. Andere numerische Stabilitätsprobleme können auftreten, z. B. die Division durch Null, wobei das Hinzufügen des Epsilons hilfreich sein kann. Eine andere, weniger offensichtliche, wenn die Quadratwurzel, deren Ableitung, beim Umgang mit Zahlen mit endlicher Genauigkeit divergieren kann, wenn sie nicht richtig vereinfacht wird. Ich bezweifle erneut, dass dies beim DNNClassifier der Fall ist.

  4. Möglicherweise haben Sie ein Problem mit den Eingabedaten. Rufen Sie assert not np.any(np.isnan(x))die Eingabedaten auf, um sicherzustellen, dass Sie die Nan nicht einführen. Stellen Sie außerdem sicher, dass alle Zielwerte gültig sind. Stellen Sie schließlich sicher, dass die Daten ordnungsgemäß normalisiert sind. Sie möchten wahrscheinlich die Pixel im Bereich [-1, 1] und nicht [0, 255] haben.

  5. Die Beschriftungen müssen im Bereich der Verlustfunktion liegen. Wenn Sie also eine logarithmisch basierte Verlustfunktion verwenden, dürfen alle Beschriftungen nicht negativ sein (wie von evan pu und den Kommentaren unten angegeben).


1
Danke für den Zusammenbruch. Mein Problem war, dass meine Beschriftungen um Null symmetrisch waren (dh [-5, ..., 5]). Das Schalten löste das Problem.
Kostenlose URL

4
Die Beschriftungen sollten binär sein. Andernfalls wäre die kategoriale Kreuzentropiekostenfunktion nicht sinnvoll.
chasep255

tf.keras.utils.normalize(data)war nützlich, um die Daten zu normalisieren.
Transistor1

mit 'binär' bedeutet man, dass sie One-Hot-codiert sein sollten, dh ein Vektor (1,0,0, ...., 0) für Beispiele der ersten Klasse, (0,1,0, .... 0) für Beispiele der zweiten Klasse und (0, ...., 0,1) für Beispiele der letzten Klasse. Die Anzahl der Ausgabeknoten sollte der Anzahl der Klassen entsprechen, die Sie haben.
Andre Holzner

1
Sie sind mein Held! Wenn ich das lineare Regressionsbeispiel ( toptal.com/machine-learning/… ) mit einem anderen Datensatz, z. B. Celsius bis Fahrenheit, versuche, erhalte ich W, b und verliere alle 'nan'. Aber nachdem ich Ihrer Antwort gefolgt war, habe ich learning_rate = 0.01 in learning_rate = 0.001 geändert, dann hat alles perfekt funktioniert!
Holibut

12

Wenn Sie für Kreuzentropie trainieren, möchten Sie Ihrer Ausgabewahrscheinlichkeit eine kleine Zahl wie 1e-8 hinzufügen.

Da log (0) eine negative Unendlichkeit ist, ist die Ausgabeverteilung sehr verzerrt, wenn Ihr Modell ausreichend trainiert ist. Nehmen wir zum Beispiel an, ich mache eine Ausgabe mit 4 Klassen. Am Anfang sieht meine Wahrscheinlichkeit so aus

0.25 0.25 0.25 0.25

aber gegen Ende wird die Wahrscheinlichkeit wahrscheinlich so aussehen

1.0 0 0 0

Und Sie nehmen eine Kreuzentropie dieser Verteilung, alles wird explodieren. Die Lösung besteht darin, allen Begriffen künstlich eine kleine Zahl hinzuzufügen, um dies zu verhindern.


Ich benutze die categorical_crossentropyVerlustfunktion von Keras. Implementiert sie dies bereits?
StayFoolish

@StayFoolish Ich bin mir nicht sicher, ob die Antwort auf die Ausrede darin besteht, sich den Quellcode anzusehen, aber ich bin bereit zu wetten, dass sie sich bereits in ihrem Code darum gekümmert haben. Ich würde versuchen zu sehen, höchstwahrscheinlich geht es dir gut.
Evan Pu

4

Wenn Sie Ganzzahlen als Ziele verwenden, stellen Sie sicher, dass diese bei 0 nicht symmetrisch sind.

Verwenden Sie also nicht die Klassen -1, 0, 1. Verwenden Sie stattdessen 0, 1, 2.


1
Möchten Sie die Gründe dafür ein wenig kommentieren oder eine Referenz zur Fertigstellung zitieren?
Gsimard

@gsimard Ehrlich gesagt erinnere ich mich nicht, als ich vor einiger Zeit damit gearbeitet habe.
Rok Povsic

@gsimard, das liegt an Grund 5 in der akzeptierten Antwort. Logistikbasierte Regressionsfunktionen verwenden häufig Logarithmen, die nur für nicht negative Zahlen definiert sind
Free Url

1
@ Zroach Nein, in meinem Fall wurden negative Zahlen unterstützt, aber der Grund dafür, dass es nicht funktionierte, war spezifisch Symmetrie bei 0.
Rok Povsic

4

In meinem Fall habe ich NAN erhalten, als ich entfernte Ganzzahl-ETIKETTEN gesetzt habe. dh:

  • Labels [0..100] das Training war ok,
  • Labels [0..100] plus ein zusätzliches Label 8000, dann habe ich NANs bekommen.

Verwenden Sie daher kein sehr weit entferntes Etikett.

BEARBEITEN Sie können den Effekt im folgenden einfachen Code sehen:

from keras.models import Sequential
from keras.layers import Dense, Activation
import numpy as np

X=np.random.random(size=(20,5))
y=np.random.randint(0,high=5, size=(20,1))

model = Sequential([
            Dense(10, input_dim=X.shape[1]),
            Activation('relu'),
            Dense(5),
            Activation('softmax')
            ])
model.compile(optimizer = "Adam", loss = "sparse_categorical_crossentropy", metrics = ["accuracy"] )

print('fit model with labels in range 0..5')
history = model.fit(X, y, epochs= 5 )

X = np.vstack( (X, np.random.random(size=(1,5))))
y = np.vstack( ( y, [[8000]]))
print('fit model with labels in range 0..5 plus 8000')
history = model.fit(X, y, epochs= 5 )

Das Ergebnis zeigt die NANs nach dem Hinzufügen des Labels 8000:

fit model with labels in range 0..5
Epoch 1/5
20/20 [==============================] - 0s 25ms/step - loss: 1.8345 - acc: 0.1500
Epoch 2/5
20/20 [==============================] - 0s 150us/step - loss: 1.8312 - acc: 0.1500
Epoch 3/5
20/20 [==============================] - 0s 151us/step - loss: 1.8273 - acc: 0.1500
Epoch 4/5
20/20 [==============================] - 0s 198us/step - loss: 1.8233 - acc: 0.1500
Epoch 5/5
20/20 [==============================] - 0s 151us/step - loss: 1.8192 - acc: 0.1500
fit model with labels in range 0..5 plus 8000
Epoch 1/5
21/21 [==============================] - 0s 142us/step - loss: nan - acc: 0.1429
Epoch 2/5
21/21 [==============================] - 0s 238us/step - loss: nan - acc: 0.2381
Epoch 3/5
21/21 [==============================] - 0s 191us/step - loss: nan - acc: 0.2381
Epoch 4/5
21/21 [==============================] - 0s 191us/step - loss: nan - acc: 0.2381
Epoch 5/5
21/21 [==============================] - 0s 188us/step - loss: nan - acc: 0.2381

Interessant. Ich würde denken, dass dies von Ihrer Verlustfunktion abhängt. Können Sie bitte angeben, wie Sie den Verlust gemessen haben?
Kostenlose URL

1
Ich habe, wie es ist, die 'sparse_categorical_crossentropy'
Guido


0

Regularisierung kann helfen. Für einen Klassifizierer gibt es einen guten Fall für die Regularisierung von Aktivitäten, unabhängig davon, ob es sich um einen binären Klassifizierer oder einen Klassifizierer mit mehreren Klassen handelt. Für einen Regressor ist eine Kernel-Regularisierung möglicherweise besser geeignet.


0

Ich möchte einige (flache) Gründe einstecken, die ich wie folgt erlebt habe:

  1. Möglicherweise haben wir unser Wörterbuch (für NLP-Aufgaben) aktualisiert, aber das Modell und die vorbereiteten Daten haben ein anderes verwendet.
  2. Möglicherweise haben wir unsere Daten erneut verarbeitet (binär tf_record), aber wir haben das alte Modell geladen. Die wiederaufbereiteten Daten können mit den vorherigen in Konflikt stehen.
  3. Möglicherweise sollten wir das Modell von Grund auf neu trainieren, aber wir haben vergessen, die Prüfpunkte zu löschen, und das Modell hat die neuesten Parameter automatisch geladen.

Hoffentlich hilft das.


0

Der Grund nan, infoder -infkommt oft aus der Tatsache , dass division by 0.0in TensorFlow nicht durch Null Ausnahme in einer Abteilung führt. Es könnte in einem Ergebnis nan, infoder -inf„Wert“. In Ihren Trainingsdaten 0.0und möglicherweise in Ihrer Verlustfunktion kann es vorkommen, dass Sie eine division by 0.0.

a = tf.constant([2., 0., -2.])
b = tf.constant([0., 0., 0.])
c = tf.constant([1., 1., 1.])
print((a / b) + c)

Die Ausgabe ist der folgende Tensor:

tf.Tensor([ inf  nan -inf], shape=(3,), dtype=float32)

Das Hinzufügen eines kleinen eplison(z. B. 1e-5) reicht oft aus. Zusätzlich wird seit TensorFlow 2 die Operation tf.math.division_no_nandefiniert.


0

Obwohl die meisten Punkte bereits diskutiert werden. Aber ich möchte noch einmal einen Grund für NaN hervorheben, der fehlt.

tf.estimator.DNNClassifier(
    hidden_units, feature_columns, model_dir=None, n_classes=2, weight_column=None,
    label_vocabulary=None, optimizer='Adagrad', activation_fn=tf.nn.relu,
    dropout=None, config=None, warm_start_from=None,
    loss_reduction=losses_utils.ReductionV2.SUM_OVER_BATCH_SIZE, batch_norm=False
)

Standardmäßig ist die Aktivierungsfunktion "Relu". Es ist möglich, dass die Zwischenschicht einen negativen Wert erzeugt und "Relu" ihn in die 0 umwandelt, wodurch das Training allmählich unterbrochen wird.

Ich habe beobachtet, dass "LeakyRelu" solche Probleme lösen kann.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.