使用 tf.set_random_seed 在 Tensorflow 中可重现结果

新手上路,请多包涵

我正在尝试生成 N 组独立的随机数。我有一个简单的代码,它显示了 3 组 10 个随机数的问题。我注意到即使我使用 tf.set_random_seed 来设置种子,不同运行的结果看起来也不一样。非常感谢任何帮助或意见。

 (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)

这是代码的输出:

 # 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]

我想要类似的东西

[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 ]

更新 1: 事实上,我将种子初始值设定项放在 for 循环中的原因是因为我想对它们进行不同的设置(例如,将其视为不同的 MCMC 运行)。这是我完成这项工作的代码,但我不确定它是否有效。基本上我在 0 和 2^32-1 之间生成几个随机种子,并在每次运行中更改种子。非常感谢任何有助于提高内存/RAM 效率的帮助或评论。

 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 .....
 .
 .
 .

原文由 Mehdi Rezaie 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 896
1 个回答

在 tensorflow 中,随机操作依赖于两个不同的种子:全局种子,由 tf.set_random_seed 设置,以及操作种子,作为操作的参数提供。您将 在文档中 找到有关它们如何关联的更多详细信息。

每个随机操作都有不同的种子,因为每个随机操作都维护自己的内部状态以生成伪随机数。让每个随机生成器保持其自己的状态的原因是为了能够稳健地改变:如果它们共享相同的状态,那么在你的图中的某个地方添加一个新的随机生成器会改变所有其他生成器产生的值,从而违背了使用种子。

现在,为什么我们有这种全局 per-op 种子的双重系统?好吧,实际上全局种子不是必需的。它的存在是为了方便:它允许一次将所有随机操作种子设置为不同的和确定的(如果未知)值,而不必详尽地遍历所有这些。

现在,根据文档,当设置了全局种子而不是操作种子时,

系统确定性地选择一个操作种子和图级种子,以便它获得唯一的随机序列。

更准确地说,提供的种子是在当前图中创建的最后一个操作的 ID。因此,全局播种的随机操作对图中的变化非常敏感,特别是那些在它之前创建的。

例如,

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

现在如果我们之前创建一个节点,结果会改变:

 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

但是,如果一个节点是在之后创建的,它不会影响操作种子:

 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

显然,就像您的情况一样,如果您生成多个操作,它们将具有不同的种子:

 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

出于好奇,为了验证种子只是图中最后使用的 id 这一事实,您可以将 — 的种子与 gen2 gen1

 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

显然,这不应该通过代码审查。

原文由 P-Gn 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题