Resultados reproducibles en Tensorflow con tf.set_random_seed

Estoy tratando de generar N conjuntos de números aleatorios independientes. Tengo un código simple que muestra el problema para 3 series de 10 números aleatorios. Me doy cuenta de que aunque uso tf.set_random_seed para establecer la semilla, los resultados de diferentes ejecuciones no se parecen. Cualquier ayuda o comentario son muy apreciados.

 (py3p6) bash-3.2$ cat test.py import tensorflow as tf for i in range(3): tf.set_random_seed(1234) generate = tf.random_uniform((10,), 0, 10) with tf.Session() as sess: b = sess.run(generate) print(b) 

Esta es la salida del código:

 # output : [9.604688 5.811516 6.4159 9.621765 0.5434954 4.1893444 5.8865128 7.9785547 8.296125 8.388672 ] [8.559105 3.2390785 6.447526 8.316823 1.6297233 1.4103293 2.647568 2.954973 6.5975866 7.494894 ] [2.0277488 6.6134906 0.7579422 4.6359386 6.97507 3.3192968 2.866236 2.2205782 6.7940736 7.2391043] 

Quiero algo como

 [9.604688 5.811516 6.4159 9.621765 0.5434954 4.1893444 5.8865128 7.9785547 8.296125 8.388672 ] [9.604688 5.811516 6.4159 9.621765 0.5434954 4.1893444 5.8865128 7.9785547 8.296125 8.388672 ] [9.604688 5.811516 6.4159 9.621765 0.5434954 4.1893444 5.8865128 7.9785547 8.296125 8.388672 ] 

Actualización 1: De hecho, la razón por la que había puesto el inicializador de inicialización en el bucle for fue que quería configurarlos de manera diferente (piénselo como para diferentes ejecuciones de MCMC, por ejemplo). Este es mi código que hace el trabajo, pero no estoy seguro de si es eficiente. Básicamente, genero un par de semillas aleatorias entre 0 y 2 ^ 32-1, y cambio la semilla en cada ejecución. Cualquier ayuda o comentario para que sea más eficiente en memoria / RAM son muy apreciados.

 import numpy as np import tensorflow as tf global_seed = 42 N_chains = 5 np.random.seed(global_seed) seeds = np.random.randint(0, 4294967295, size=N_chains) for i in range(N_chains): tf.set_random_seed(seeds[i]) .... some stuff .... kernel_initializer = tf.random_normal_initializer(seed=seeds[i]) .... some stuff with tf.Session() as sess: .... some stuff ..... . . . 

En tensorflow, una operación aleatoria se basa en dos semillas diferentes: una semilla global, establecida por tf.set_random_seed , y una semilla de operación, proporcionada como un argumento a la operación. Encontrará más detalles sobre cómo se relacionan en los documentos .

Tiene una semilla diferente para cada operación aleatoria porque cada operación aleatoria mantiene su propio estado interno para la generación de números pseudoaleatorios. La razón por la cual cada generador aleatorio mantiene su propio estado es ser robusto para cambiar: si compartieran el mismo estado, entonces agregar un nuevo generador aleatorio en algún lugar de su gráfico cambiaría los valores producidos por todos los demás generadores, anulando el propósito de utilizando una semilla.

Ahora, ¿por qué tenemos este sistema dual de semillas globales y per-op? Bueno, en realidad la semilla global no es necesaria. Está ahí por conveniencia: permite configurar todas las semillas de operaciones aleatorias a un valor diferente y determinístico (si no se conoce) a la vez, sin tener que analizarlas exhaustivamente.

Ahora, cuando se establece una semilla global pero no la semilla op, de acuerdo con los documentos,

El sistema elige de forma determinista una semilla de operación junto con la semilla de nivel de gráfico para que obtenga una secuencia aleatoria única.

Para ser más precisos, la semilla que se proporciona es el identificador de la última operación que se ha creado en el gráfico actual. En consecuencia, la operación aleatoria globalmente generada es extremadamente sensible al cambio en el gráfico, en particular a los creados antes que ellos mismos.

Por ejemplo,

 import tensorflow as tf tf.set_random_seed(1234) generate = tf.random_uniform(()) with tf.Session() as sess: print(generate.eval()) # 0.96046877 

Ahora si creamos un nodo antes, el resultado cambia:

 import tensorflow as tf tf.set_random_seed(1234) tf.zeros(()) # new op added before generate = tf.random_uniform(()) with tf.Session() as sess: print(generate.eval()) # 0.29252338 

Sin embargo, si se crea un nodo después, no afecta a la semilla op:

 import tensorflow as tf tf.set_random_seed(1234) generate = tf.random_uniform(()) tf.zeros(()) # new op added after with tf.Session() as sess: print(generate.eval()) # 0.96046877 

Obviamente, como en su caso, si genera varias operaciones, tendrán diferentes semillas:

 import tensorflow as tf tf.set_random_seed(1234) gen1 = tf.random_uniform(()) gen2 = tf.random_uniform(()) with tf.Session() as sess: print(gen1.eval()) print(gen2.eval()) # 0.96046877 # 0.85591054 

Como curiosidad, y para validar el hecho de que las semillas son simplemente la última ID utilizada en el gráfico, puede alinear la semilla de gen2 con gen1 con

 import tensorflow as tf tf.set_random_seed(1234) gen1 = tf.random_uniform(()) # 4 operations seems to be created after seed has been picked seed = tf.get_default_graph()._last_id - 4 gen2 = tf.random_uniform((), seed=seed) with tf.Session() as sess: print(gen1.eval()) print(gen2.eval()) # 0.96046877 # 0.96046877 

Obviamente, sin embargo, esto no debería pasar la revisión del código.

Hay un problema relacionado con GitHub . Pero en su caso, consulte la documentación de tf.set_random_seed :

Establece la semilla aleatoria a nivel de gráfico.

Probablemente desee utilizar el mismo gráfico y la misma operación para obtener los mismos números aleatorios en diferentes sesiones.

 import tensorflow as tf tf.set_random_seed(1234) generate = tf.random_uniform((10,), 0, 10) tf.get_default_graph().finalize() # something everybody tends to forget for i in range(3): with tf.Session() as sess: b = sess.run(generate) print(b) 

da

 [9.604688 5.811516 6.4159 9.621765 0.5434954 4.1893444 5.8865128 7.9785547 8.296125 8.388672 ] [9.604688 5.811516 6.4159 9.621765 0.5434954 4.1893444 5.8865128 7.9785547 8.296125 8.388672 ] [9.604688 5.811516 6.4159 9.621765 0.5434954 4.1893444 5.8865128 7.9785547 8.296125 8.388672 ] 

En tu caso, creaste diferentes operaciones dentro del mismo gráfico.

Está obteniendo diferentes resultados en diferentes ejecuciones porque hay tres variables de generate (operación) definidas en el gráfico y no una. Esto se debe a que tiene la operación de generar dentro del bucle for que conduce a tres operaciones. (Tensor("random_uniform:0"), Tensor("random_uniform_1:0"), Tensor("random_uniform_2:0")) . Solo print(generate) dentro del bucle for. Verá tres operaciones diferentes como se indicó anteriormente.

tf.set_random_seed establece la semilla en el nivel del gráfico. Por lo tanto, elige de forma determinista la semilla para cada operación en el gráfico. Por lo tanto, a las tres operaciones de generate les asignan las mismas tres semillas en cada ejecución. Y esta es la razón por la cual, para cada ejecución, vería los mismos resultados para las tres variables de manera correspondiente. Por favor, eche un vistazo a esto para obtener más información sobre cómo establecer semillas aleatorias.

Por lo tanto, si desea obtener los mismos resultados cada vez que ejecute una sesión, puede hacer esto:

 tf.set_random_seed(1234) generate = tf.random_uniform((10,), 0, 10) for i in range(3): with tf.Session() as sess: b = sess.run(generate) print(b) 

Pero por qué quieres crear n sesiones. Lo ideal sería crear una sesión y luego ejecutar la sesión n veces. No es necesario crear una nueva sesión para cada ejecución y cada vez que intenta colocar las variables y las operaciones en el gráfico en el dispositivo (GPU o CPU).