3
votes

Tensorflow: différents résultats avec la même graine aléatoire

Je lance un programme d'apprentissage par renforcement dans un environnement de gym (BipedalWalker-v2) implémenté dans tensorflow. J'ai défini manuellement la graine aléatoire de l'environnement, tensorflow et numpy comme suit

os.environ['PYTHONHASHSEED']=str(42)
random.seed(42)
np.random.seed(42)
tf.set_random_seed(42)

env = gym.make('BipedalWalker-v2')
env.seed(0)

config = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)
# run the graph with sess

Cependant, j'obtiens des résultats différents chaque fois que j'exécute mon programme (sans changer de code). Pourquoi les résultats ne sont-ils pas cohérents et que dois-je faire si je veux obtenir le même résultat?


Mise à jour:

Les seuls endroits auxquels je peux penser peuvent introduire un caractère aléatoire (autres que les réseaux de neurones) sont

  1. J'utilise tf.truncated_normal pour générer du bruit aléatoire epsilon afin d'implémenter la couche bruyante
  2. J'utilise np.random.uniform pour sélectionner au hasard des échantillons dans la mémoire tampon de relecture

Je remarque également que les scores que j'obtiens sont assez cohérents dans les 10 premiers épisodes, mais commencent ensuite à différer. D'autres choses telles que les pertes montrent également une tendance similaire mais ne sont pas les mêmes en numérique.

Mise à jour 2

J'ai également défini "PYTHONHASHSEED" et utilise un processeur à thread unique comme @ jaypops96 décrit, mais ne peut toujours pas reproduire le résultat. Le code a été mis à jour dans le bloc de code ci-dessus


7 commentaires

Utilisez-vous env.action_space.sample ou quelque chose de similaire n'importe où? Cela pourrait le faire. De plus, si votre agent utilise un caractère aléatoire dans son graphique (ce qui n'est pas rare, pour rendre l'agent plus robuste), vous obtiendrez des résultats variables.


@aedificatori Merci pour votre suggestion, j'ai vérifié mon code et mis à jour la question. Je commence à conjecturer s'il s'agit de la perte de précision ou de quelque chose de similaire?


Bien que l'apprentissage par renforcement puisse être quelque peu ridicule lorsqu'il s'agit de naviguer dans sa variété d'erreurs, la perte de précision est probablement encore trop petite pour être un problème (peut-être de quelques ordres de grandeur, à moins que vous n'ayez des erreurs d'arrondi ou de virgule flottante, que vous 'reconnaîtrais probablement d'emblée). Je pourrais vous recommander de tester Tensorflow et Numpy individuellement pour vous assurer que vos graines sont utilisées correctement. Donc, pour Numpy, à quelques endroits de votre programme, imprimez simplement un nombre aléatoire. Pour Tensorflow, même chose, mais vous devrez l'extraire de votre graphique si vous n'utilisez pas EagerExecution.


Vous devez ajouter une valeur de départ constante à toutes les opérations qui acceptent la valeur de départ comme argument, comme tf.nn.dropout , tf.contrib.layers.xavier_initializer , etc. Il semble que tf.set_random_seed ne fasse pas correctement son travail.


Je suggère de vérifier si votre graphique TensorFlow contient des opérations non déterministes. Notamment, reduction_sum est l'une de ces opérations. Ces opérations ne sont pas déterministes car l'addition et la multiplication en virgule flottante sont non associatives (l'ordre dans lequel les nombres à virgule flottante sont ajoutés ou multipliés affecte le résultat) et parce que ces opérations ne garantissent pas que leurs entrées sont ajoutées ou multipliées dans le même ordre à chaque fois . Je ne connais pas une liste complète des opérations TensorFlow non déterministes.


@PeterO, merci de partager ces informations précieuses!


Ce message est lié et plusieurs réponses valent la peine en train de lire.


3 Réponses :


2
votes

Il semble que les réseaux de neurones tensorflow introduisent un caractère aléatoire pendant l'entraînement qui n'est pas contrôlé par une graine aléatoire numpy. Le caractère aléatoire semble provenir au moins d'opérations de hachage python et d'opérations parallélisées s'exécutant dans un ordre non contrôlé.

J'ai réussi à obtenir une reproductibilité à 100% en utilisant un NN keras-tensorflow, en suivant les étapes de configuration de cette réponse: Comment obtenir des résultats reproductibles dans les keras

plus précisément, j'ai utilisé la formulation proposée par @Poete Maudit dans ce lien.

Leur clé était de définir des valeurs de départ aléatoires UP FRONT, pour numpy, python et tensorflow, puis aussi de faire fonctionner tensorflow sur un processeur à un seul thread dans une session spécialement configurée.

Voici le code que j'ai utilisé, mis à jour très légèrement à partir du lien que j'ai publié.

print('Running in 1-thread CPU mode for fully reproducible results training a CNN and generating numpy randomness.  This mode may be slow...')
# Seed value
# Apparently you may use different seed values at each stage
seed_value= 1

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

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

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

# 4. Set `tensorflow` pseudo-random generator at a fixed value
import tensorflow as tf
tf.set_random_seed(seed_value)

# 5. Configure a new global `tensorflow` session
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)
tf.keras.backend.set_session(sess)

#rest of code...


4 commentaires

Merci pour votre réponse :-). J'ai fait la configuration exacte comme vous l'avez décrit, sauf que je n'utilise pas de keras. Cependant, je ne peux toujours pas reproduire le même résultat.


Eh bien, cela peut être un peu différent puisque vous utilisez uniquement TF et non Keras, mais quelques notes: (1) essayez de définir les graines aléatoires avant de faire TOUT autre chose dans le code, et assurez-vous de les définir dans l'ordre exact que je spécifié. @Poete Maudit a souligné qu'il était important de les faire d'abord et dans cet ordre exact. (2) il semble que votre code n'ait pas d'analogue à ma ligne "tf.keras.backend.set_session (sess)" - vous configurez la session mais ne configurez jamais le backend tensorflow pour utiliser cette session. essayer de trouver quelque chose de comparable à ma ligne dans la documentation tensorflow?


Merci. J'ai réorganisé mon code pour qu'il soit cohérent avec le vôtre, mais je trouve toujours des résultats différents. Au fait, j'écris mon code dans tensorflow donc j'utilise la session pour exécuter le graphe tensorflow directement au lieu de l'utiliser comme sauvegarde


Hmm alors je suis peut-être à court d'idées. Vous exécutez le code que j'ai publié comme toute première chose dans votre script? comme, avant toute autre importation ou quoi que ce soit? D'autres personnes postant ont souligné que ces graines doivent être définies avant que TOUT autre ne se produise dans votre code. peut-être même devrait-il se produire lorsque vous démarrez la session d'interprétation si vous utilisez l'interpréteur ...? Juste une dernière pensée.



0
votes

Peut-être pouvez-vous essayer de régler le nombre de threads de parallélisme à 1. J'ai le même problème: la perte est devenue différente à la septième décimale à partir du deuxième épisode. Cela a été corrigé lorsque j'ai défini

tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)


0 commentaires

5
votes

Je suggère de vérifier si votre graphe TensorFlow contient des opérations non déterministes. Par exemple, reduction_sum avant TensorFlow 1.2 était l'une de ces opérations. Ces opérations ne sont pas déterministes car l'addition et la multiplication en virgule flottante sont non associatives (l'ordre dans lequel les nombres à virgule flottante sont ajoutés ou multipliés affecte le résultat) et parce que ces opérations ne garantissent pas que leurs entrées sont ajoutées ou multipliées dans le même ordre à chaque fois . Voir également cette question .

EDIT (20 septembre 2020): Le référentiel GitHub framework-determinism contient plus d'informations sur les sources de non-déterminisme dans les frameworks d'apprentissage automatique, en particulier TensorFlow.


0 commentaires