So erzielen Sie mit TensorFlow stabile Ergebnisse, indem Sie einen zufälligen Startwert festlegen

75

Ich versuche, ein neuronales Netzwerk mehrmals mit unterschiedlichen Parametern auszuführen, um die Netzwerkparameter (Ausfallwahrscheinlichkeiten, Lernrate ed) zu kalibrieren. Ich habe jedoch das Problem, dass das Ausführen des Netzwerks unter Beibehaltung der Parameter immer noch eine andere Lösung bietet, wenn ich das Netzwerk in einer Schleife wie folgt ausführe:

filename = create_results_file()
for i in range(3):
  g = tf.Graph()
  with g.as_default():
    accuracy_result, average_error = network.train_network(
        parameters, inputHeight, inputWidth, inputChannels, outputClasses)
    f, w = get_csv_writer(filename)
    w.writerow([accuracy_result, "did run %d" % i, average_error])
    f.close()

Ich verwende den folgenden Code zu Beginn meiner Funktion train_network, bevor ich die Layer- und Fehlerfunktion meines Netzwerks einrichte:

np.random.seed(1)
tf.set_random_seed(1)

Ich habe auch versucht, diesen Code vor der Erstellung des TensorFlow-Diagramms hinzuzufügen, erhalte jedoch immer wieder andere Lösungen für meine Ergebnisausgabe.

Ich verwende einen AdamOptimizer und initialisiere Netzwerkgewichte mit tf.truncated_normal. Zusätzlich verwende ich, np.random.permutationum die eingehenden Bilder für jede Epoche zu mischen.

Waanders
quelle

Antworten:

47

Das Festlegen des aktuellen zufälligen TensorFlow-Startwerts wirkt sich nur auf das aktuelle Standarddiagramm aus. Da Sie ein neues Diagramm für Ihr Training erstellen und es als Standard ( with g.as_default():) festlegen, müssen Sie den zufälligen Startwert innerhalb des Bereichs dieses withBlocks festlegen .

Zum Beispiel sollte Ihre Schleife wie folgt aussehen:

for i in range(3):
  g = tf.Graph()
  with g.as_default():
    tf.set_random_seed(1)
    accuracy_result, average_error = network.train_network(
        parameters, inputHeight, inputWidth, inputChannels, outputClasses)

Beachten Sie, dass hierfür für jede Iteration der äußeren forSchleife derselbe zufällige Startwert verwendet wird. Wenn Sie in jeder Iteration einen anderen, aber dennoch deterministischen Startwert verwenden möchten, können Sie diesen verwenden tf.set_random_seed(i + 1).

mrry
quelle
4
Ich glaube, mein set_random_seed (1) befand sich bereits im Block g.as_default (), da es eine der ersten Zeilen im Code train_network ist. Trotzdem habe ich versucht, den Code wie in Ihrem Beispiel einzufügen, aber ich erhalte immer noch instabile Ergebnisse:> Fehler bei den Genauigkeitsbeschriftungen> 0.9805 lief0 2.96916> 0.9807 lief1 2.96494> 0.9804 lief2 2.95215
Waanders
Ich habe das gleiche Problem. tensorflow 0.12.1Wenn ich den zufälligen Startwert wie angegeben einstelle, sehe ich leichte Unterschiede in den Wahrscheinlichkeitsausgaben von Lauf zu Lauf.
Luke
5
Der Grund hängt von Ihrer Funktion ab, aber es ist wahrscheinlich, dass kleine Unterschiede in der Genauigkeitsberechnung durch eine nicht deterministische parallele Reduzierung von Operationen wie verursacht werden tf.reduce_sum(). (Diese Operationen behandeln die Gleitkommaaddition als kommutativ,
obwohl dies
@ Mrry, ich habe einen ähnlichen Fehler mit DropoutWrapper. Wenn ich halte keep_prob=1, erhalte ich konsistente Ergebnisse. Unterschiedliche Läufe geben mir jedoch unterschiedliche Werte mit keep_prob=0.8. Was könnte der Grund sein? Ich habe es auf stackoverflow.com/questions/42156296
Martianwars
15

Deterministisches Verhalten kann entweder durch Bereitstellen eines Startwerts auf Diagrammebene oder auf Betriebsebene erhalten werden. Beide haben für mich gearbeitet. Ein Startwert auf Diagrammebene kann mit tf.set_random_seed platziert werden . Ein Startwert auf Betriebsebene kann z. B. in einem variablen Intializer wie folgt platziert werden:

myvar = tf.Variable(tf.truncated_normal(((10,10)), stddev=0.1, seed=0))
ssegvic
quelle
13

Tensorflow 2.0-kompatible Antwort : Wenn für eine Tensorflow-Version größer als 2.0 der globale Zufalls-Seed festgelegt werden soll, wird der Befehl verwendet tf.random.set_seed.

Wenn wir von migrieren Tensorflow Version 1.x to 2.x, können wir den Befehl verwenden tf.compat.v2.random.set_seed.

Beachten Sie, dass tf.functiondies in diesem Fall wie eine erneute Ausführung eines Programms wirkt.

Um den Operation Level Seed (wie oben beantwortet) festzulegen, können Sie den Befehl verwenden tf.random.uniform([1], seed=1).

Weitere Informationen finden Sie auf dieser Tensorflow-Seite .

Tensorflow-Unterstützung
quelle
7

Es scheint, als würde keine dieser Antworten aufgrund der zugrunde liegenden Implementierungsprobleme in CuDNN funktionieren.

Sie können etwas mehr Determinismus erzielen, indem Sie ein zusätzliches Flag hinzufügen

os.environ['PYTHONHASHSEED']=str(SEED)
os.environ['TF_CUDNN_DETERMINISTIC'] = '1'  # new flag present in tf 2.0+
random.seed(SEED)
np.random.seed(SEED)
tf.set_random_seed(SEED)

Dies wird jedoch immer noch nicht ganz deterministisch sein. Um eine noch genauere Lösung zu erhalten, müssen Sie das in diesem NVIDIA- Repo beschriebene Verfahren anwenden .

Luke
quelle
7

Bitte fügen Sie alle zufälligen Startfunktionen vor Ihrem Code hinzu:

tf.reset_default_graph()
tf.random.set_seed(0)
random.seed(0)
np.random.seed(0)

Ich denke, einige Modelle in TensorFlow verwenden Numpy oder die Python-Zufallsfunktion.

Zhihui Shao
quelle
0

Ich verwende TensorFlow 2 (2.2.0) und führe Code in JupyterLab aus. Ich habe dies in macOS Catalina und in Google Colab mit den gleichen Ergebnissen getestet. Ich werde der Antwort des Tensorflow-Supports einige Dinge hinzufügen .

Wenn ich mit der model.fit () -Methode trainiere, mache ich das in einer Zelle. Ich mache ein paar andere Sachen in anderen Zellen. Dies ist der Code, den ich in der genannten Zelle ausführe:

# To have same results always place this on top of the cell
tf.random.set_seed(1)

(x_train, y_train), (x_test, y_test) = load_data_onehot_grayscale()
model = get_mlp_model_compiled() # Creates the model, compiles it and returns it

history = model.fit(x=x_train, y=y_train,
                    epochs=30,
                    callbacks=get_mlp_model_callbacks(),
                    validation_split=.1,
                   )

Das verstehe ich:

  1. TensorFlow hat einige zufällige Prozesse, die in verschiedenen Phasen ablaufen (Initialisieren, Mischen, ...). Jedes Mal, wenn diese Prozesse stattfinden, verwendet TensorFlow eine Zufallsfunktion. Wenn Sie den Samen mit setzentf.random.set_seed(1) Sie diese Prozesse ihn verwenden. Wenn der Startwert festgelegt ist und sich die Prozesse nicht ändern, sind die Ergebnisse dieselben.
  2. Nun, in dem obigen Code, wenn ich ändern tf.random.set_seed(1)gehen unter der Linie model = get_mlp_model_compiled()meine Ergebnisse zu ändern, ich glaube , es liegt daran ,get_mlp_model_compiled() Anwendungen Zufall und ist nicht mit dem Samen ich will.
  3. Vorsichtsmaßnahme zu Punkt 2: Wenn ich die Zelle dreimal hintereinander laufen lasse, erhalte ich die gleichen Ergebnisse. Ich glaube, das passiert, weil in Lauf get_mlp_model_compiled()Nr. 1 der interne Zähler von TensorFlow nicht mit meinem Samen verwendet wird. In Lauf Nr. 2 wird ein Startwert verwendet, und in allen nachfolgenden Läufen wird auch der Startwert verwendet, sodass die Ergebnisse nach Lauf Nr. 2 gleich sind.

Ich habe möglicherweise falsche Informationen, kann mich also gerne korrigieren.

Um zu verstehen, was los ist, sollten Sie die Dokumente lesen . Sie sind nicht so lang und leicht zu verstehen.

loco.loop
quelle
-1

Diese Antwort ist eine Ergänzung zu Lukes Antwort und für TF v2.2.0

import numpy as np
import os
import random
import tensorflow as tf # 2.2.0

SEED = 42
os.environ['PYTHONHASHSEED']=str(SEED)
os.environ['TF_CUDNN_DETERMINISTIC'] = '1'  # TF 2.1
random.seed(SEED)
np.random.seed(SEED)
tf.random.set_seed(SEED)
Hart
quelle
Mit TF_CUDNN_DETERMINISTICPausen das Notebook mit tf 2.3.0 nicht sicher warum. Dies hat mich dazu gebracht, 2 Tage lang direkt in meinem Code zu debuggen! Benutze das nicht.
Kaushal28