Wie man reproduzierbare Ergebnisse in Keras erhält

78

Jedes Mal, wenn ich das imdb_lstm.pyBeispiel über das Keras-Framework ( https://github.com/fchollet/keras/blob/master/examples/imdb_lstm.py ) ausführe, erhalte ich unterschiedliche Ergebnisse ( Testgenauigkeit ). Der Code enthält np.random.seed(1337)oben vor allen Keras Importe. Es sollte verhindern, dass bei jedem Lauf unterschiedliche Zahlen generiert werden. Was vermisse ich?

UPDATE: Wie man repro:

  1. Installieren Sie Keras ( http://keras.io/ )
  2. Führen Sie https://github.com/fchollet/keras/blob/master/examples/imdb_lstm.py einige Male aus. Es wird das Modell trainieren und die Testgenauigkeit ausgeben.
    Erwartetes Ergebnis: Die Testgenauigkeit ist bei jedem Lauf gleich.
    Tatsächliches Ergebnis: Die Testgenauigkeit ist bei jedem Lauf unterschiedlich.

UPDATE2: Ich verwende es unter Windows 8.1 mit MinGW / msys, Modulversionen:
theano 0.7.0
numpy 1.8.1
scipy 0.14.0c1

UPDATE3: Ich habe das Problem etwas eingegrenzt. Wenn ich das Beispiel mit einer GPU ausführe (setze das Flag Flag = gpu0), erhalte ich jedes Mal eine andere Testgenauigkeit, aber wenn ich es auf der CPU ausführe, funktioniert alles wie erwartet. Meine Grafikkarte: NVIDIA GeForce GT 635)

Pavel Surmenok
quelle
Ich kann das Ausführen des Codes unter Ubuntu 14.04
Padraic Cunningham
theano -> 0.6.0, numpy -> '1.9.2',scipy -> '0.15.1'
Padraic Cunningham
Vielleicht ist das Problem, dass ich Windows benutze. numpy.random.uniform funktioniert einwandfrei und liefert immer die gleichen Ergebnisse.
Pavel Surmenok
4
Der Code für die GPU muss häufig SIMDähnliche Anweisungen verwenden. Dies kann dazu führen, dass der Zufallsgenerator in zufälliger Reihenfolge aufgerufen wird. Auch die GPU ist eher eine autonome Einheit und kann einen eigenen Zufallsgenerator verwenden. Schließlich ist es nicht trivial, beliebigen Code auf der GPU auszuführen.
U354356007
2
Welche CUDA-Version haben Sie verwendet? Haben Sie cuDNN installiert? Letzteres bringt meiner Meinung nach einige Opfer für die Geschwindigkeit, die zu einem nicht deterministischen Verhalten auf der GPU führen. (Sollte geringfügig sein, ich denke, es hat damit zu tun, dass atomare Operationen auf dem Backrprop berechnet werden, aber Sie würden nicht jedes Mal den gleichen Wert erhalten.)
user2805751

Antworten:

48

Die Antwort finden Sie in den Keras-Dokumenten: https://keras.io/getting-started/faq/#how-can-i-obtain-reproducible-results-using-keras-during-development .

Kurz gesagt, um absolut sicher zu sein, dass Sie mit Ihrem Python-Skript reproduzierbare Ergebnisse auf der CPU eines Computers / Laptops erhalten, müssen Sie Folgendes tun:

  1. Stellen Sie die PYTHONHASHSEEDUmgebungsvariable auf einen festen Wert ein
  2. Stellen Sie den pythoneingebauten Pseudozufallsgenerator auf einen festen Wert ein
  3. Stellen Sie den numpyPseudozufallsgenerator auf einen festen Wert ein
  4. Stellen Sie den tensorflowPseudozufallsgenerator auf einen festen Wert ein
  5. Konfigurieren Sie eine neue globale tensorflowSitzung

Wenn Kerasich dem Link oben folge, verwende ich folgenden Quellcode:

# Seed value
# Apparently you may use different seed values at each stage
seed_value= 0

# 1. Set the `PYTHONHASHSEED` environment variable at a fixed value
import os
os.environ['PYTHONHASHSEED']=str(seed_value)

# 2. Set the `python` built-in pseudo-random generator at a fixed value
import random
random.seed(seed_value)

# 3. Set the `numpy` pseudo-random generator at a fixed value
import numpy as np
np.random.seed(seed_value)

# 4. Set the `tensorflow` pseudo-random generator at a fixed value
import tensorflow as tf
tf.random.set_seed(seed_value)
# for later versions: 
# tf.compat.v1.set_random_seed(seed_value)

# 5. Configure a new global `tensorflow` session
from keras import backend as K
session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)
K.set_session(sess)
# for later versions:
# session_conf = tf.compat.v1.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
# sess = tf.compat.v1.Session(graph=tf.compat.v1.get_default_graph(), config=session_conf)
# tf.compat.v1.keras.backend.set_session(sess)

Es ist unnötig zu sagen , dass Sie müssen nicht angeben , seedoder random_statean die numpy, scikit-learnoder tensorflow/ kerasFunktionen , die Sie in Ihrem Python - Skript verwenden , genau weil mit dem Quellcode oben wir global ihre pseudo-Zufallsgeneratoren auf einen festen Wert eingestellt.

Ausgestoßene
quelle
2
Verwenden Sie für spätere Versionen von Tensorflow, wenn ein Fehler auftritt
Kalpit
13

In der Dokumentation von Theano wird über die Schwierigkeiten beim Setzen von Zufallsvariablen und darüber gesprochen, warum jede Diagramminstanz mit einem eigenen Zufallszahlengenerator versehen wird.

Das Teilen eines Zufallszahlengenerators zwischen verschiedenen {{{RandomOp}}} Instanzen macht es schwierig, denselben Stream unabhängig von anderen Operationen im Diagramm zu erzeugen und {{{RandomOps}}} isoliert zu halten. Daher verfügt jede {{{RandomOp}}} Instanz in einem Diagramm über einen eigenen Zufallszahlengenerator. Dieser Zufallszahlengenerator ist eine Eingabe für die Funktion. In der typischen Verwendung verwenden wir die neuen Funktionen von Funktionseingaben ({{{value}}}, {{{update}}}), um das rng für jedes {{{RandomOp}}} zu übergeben und zu aktualisieren. Durch Übergeben von RNGs als Eingaben ist es möglich, die normalen Methoden für den Zugriff auf Funktionseingaben zu verwenden, um auf die Rng jedes {{{RandomOp}}} zuzugreifen. Bei diesem Ansatz gibt es keinen bereits vorhandenen Mechanismus, um mit dem kombinierten Zufallszahlenstatus eines gesamten Graphen zu arbeiten.

Sie bieten auch Beispiele zum Setzen aller Zufallszahlengeneratoren.

Sie können auch alle Zufallsvariablen, die von einem RandomStreams-Objekt zugewiesen wurden, mit der Startmethode dieses Objekts festlegen. Dieser Startwert wird verwendet, um einen temporären Zufallszahlengenerator zu erstellen, der wiederum Startwerte für jede der Zufallsvariablen generiert.

>>> srng.seed(902340)  # seeds rv_u and rv_n with different seeds each
PabTorre
quelle
11
Aber um sie zu säen, müssen wir Zugriff auf die zufälligen Objekte von theano haben, die Keras verwenden werden. Ist es möglich, über Keras API zu tun?
Max
12

Mit meinem Code habe ich endlich reproduzierbare Ergebnisse erzielt. Es ist eine Kombination von Antworten, die ich im Internet gesehen habe. Das erste, was @alex sagt, ist:

  1. Set numpy.random.seed;
  2. Verwenden PYTHONHASHSEED=0 für Python 3.

Dann müssen Sie das von @ user2805751 in Bezug auf cuDNN festgestellte Problem lösen, indem Sie Ihren Keras-Code mit den folgenden zusätzlichen Elementen aufrufen THEANO_FLAGS:

  1. dnn.conv.algo_bwd_filter=deterministic,dnn.conv.algo_bwd_data=deterministic

Und schließlich müssen Sie Ihre Theano-Installation gemäß diesem Kommentar patchen , der im Wesentlichen aus Folgendem besteht:

  1. Ersetzen aller Aufrufe des *_dev20Betreibers durch seine reguläre Version intheano/sandbox/cuda/opt.py .

Dies sollte zu denselben Ergebnissen für denselben Samen führen.

Beachten Sie, dass es zu einer Verlangsamung kommen kann. Ich sah eine Laufzeitsteigerung von ca. 10%.

Kepler
quelle
4

Das Problem ist jetzt in Tensorflow 2.0 gelöst! Ich hatte das gleiche Problem mit TF 1.x (siehe Wenn Keras-Ergebnisse nicht reproduzierbar sind, was ist die beste Vorgehensweise für den Vergleich von Modellen und die Auswahl von Hyperparametern? ), Aber

import os
####*IMPORANT*: Have to do this line *before* importing tensorflow
os.environ['PYTHONHASHSEED']=str(1)

import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers 
import random
import pandas as pd
import numpy as np

def reset_random_seeds():
   os.environ['PYTHONHASHSEED']=str(1)
   tf.random.set_seed(1)
   np.random.seed(1)
   random.seed(1)

#make some random data
reset_random_seeds()
NUM_ROWS = 1000
NUM_FEATURES = 10
random_data = np.random.normal(size=(NUM_ROWS, NUM_FEATURES))
df = pd.DataFrame(data=random_data, columns=['x_' + str(ii) for ii in range(NUM_FEATURES)])
y = df.sum(axis=1) + np.random.normal(size=(NUM_ROWS))

def run(x, y):
    reset_random_seeds()

    model = keras.Sequential([
            keras.layers.Dense(40, input_dim=df.shape[1], activation='relu'),
            keras.layers.Dense(20, activation='relu'),
            keras.layers.Dense(10, activation='relu'),
            keras.layers.Dense(1, activation='linear')
        ])
    NUM_EPOCHS = 500
    model.compile(optimizer='adam', loss='mean_squared_error')
    model.fit(x, y, epochs=NUM_EPOCHS, verbose=0)
    predictions = model.predict(x).flatten()
    loss = model.evaluate(x,  y) #This prints out the loss by side-effect

#With Tensorflow 2.0 this is now reproducible! 
run(df, y)
run(df, y)
run(df, y)
user2543623
quelle
2

Ich möchte den vorherigen Antworten etwas hinzufügen. Wenn Sie Python 3 verwenden und für jeden Lauf reproduzierbare Ergebnisse erzielen möchten, müssen Sie dies tun

  1. Setzen Sie numpy.random.seed am Anfang Ihres Codes
  2. Geben Sie dem Python-Interpreter PYTHONHASHSEED = 0 als Parameter
Alex
quelle
2

Ich habe Sequential()neuronale Netze mit Keras trainiert und getestet . Ich habe eine nichtlineare Regression für verrauschte Sprachdaten durchgeführt. Ich habe den folgenden Code verwendet, um zufälligen Startwert zu generieren:

import numpy as np
seed = 7
np.random.seed(seed)

Ich erhalte val_lossjedes Mal genau die gleichen Ergebnisse, wenn ich mit denselben Daten trainiere und teste.

tauseef_CuriousGuy
quelle
1
Haben Sie GPU verwendet? Welches Backend: Theano oder TensorFlow?
Pavel Surmenok
Ich habe CPU mit Theano-Backend verwendet.
tauseef_CuriousGuy
1
Ich habs. Die CPU funktioniert auch bei mir einwandfrei. Ich habe nur Probleme, wenn ich auf einer GPU laufe.
Pavel Surmenok
2

Das funktioniert bei mir:

SEED = 123456
import os
import random as rn
import numpy as np
from tensorflow import set_random_seed

os.environ['PYTHONHASHSEED']=str(SEED)
np.random.seed(SEED)
set_random_seed(SEED)
rn.seed(SEED)
Victor Villacorta
quelle
0

Ich stimme dem vorherigen Kommentar zu, aber reproduzierbare Ergebnisse erfordern manchmal dieselbe Umgebung (z. B. installierte Pakete, Maschineneigenschaften usw.). Daher empfehle ich, Ihre Umgebung an einen anderen Ort zu kopieren, um reproduzierbare Ergebnisse zu erzielen. Versuchen Sie, eine der nächsten Technologien zu verwenden:

  1. Docker . Wenn Sie ein Linux haben, ist es sehr einfach, Ihre Umgebung an einen anderen Ort zu verschieben. Sie können auch versuchen, DockerHub zu verwenden .
  2. Bindemittel . Dies ist eine Cloud-Plattform zur Reproduktion wissenschaftlicher Experimente.
  3. Everware . Dies ist eine weitere Cloud-Plattform für "wiederverwendbare Wissenschaft". Siehe das Projekt-Repository auf Github.
Yelaman
quelle
Mein Problem ist, dass ich selbst in derselben Umgebung keine reproduzierbaren Ergebnisse erzielen kann, wenn ich das Training zweimal durchführe.
Pavel Surmenok
0

Das Konferenzpapier: Nicht zufällige Gewichtsinitialisierung in Deep-Learning-Netzwerken für wiederholbaren Determinismus, Veröffentlichungsdatum 5. Juni 2019, vorgestellt auf der 10. Internationalen IEEE-Konferenz für zuverlässige Systeme, Dienste und Technologien (DESSERT-19) an der Leeds Beckett University (LBU), Großbritannien , Großbritannien, Irland und die ukrainische Sektion des IEEE vom 5. bis 7. Juni 2019

https://ieeexplore.ieee.org/document/8770007

zeigt, wie wiederholbare Ergebnisse erzielt werden, indem kritische Codebereiche erzwungen werden.

Es wurde zu einem Journal Paper erweitert: Wiederholbarer Determinismus unter Verwendung nicht zufälliger Gewichtsinitialisierungen in Smart City-Anwendungen von Deep Learning. Veröffentlichung im Journal of Reliable Intelligent Environments in einer Smart Cities-Sonderausgabe. Es verwendet Glorot Xavier-Limits und erzielt die gleiche Genauigkeit mit Perzeptronschichten, aber wachsen das Gewicht in eine lineare Reihenfolge, was einen Vorteil für die Regelextraktion in Perzeptronschichten haben kann.

Richard Rudd-Orthner
quelle
0

In Tensorflow 2.0 können Sie zufällige Startwerte wie folgt festlegen:

import tensorflow as tf
tf.random.set_seed(221)


from tensorflow import keras
from tensorflow.keras import layers


model = keras.Sequential( [ 
layers.Dense(2,name = 'one'),
layers.Dense(3,activation = 'sigmoid', name = 'two'),
layers.Dense(2,name = 'three')])

x = tf.random.uniform((12,12))
model(x)
Aaditya Ura
quelle