在张量流中,随机操作依赖于两个不同的种子:全局种子,由下式设置tf.set_random_seed
,以及一个操作种子,作为操作的参数提供。您将找到有关它们如何关联的更多详细信息在文档中.
每个随机操作都有不同的种子,因为每个随机操作都会维护自己的内部状态以生成伪随机数。让每个随机生成器保持自己的状态的原因是为了能够鲁棒地改变:如果它们共享相同的状态,那么在图中的某个位置添加一个新的随机生成器将改变所有其他生成器生成的值,从而违背了使用种子。
现在,为什么我们有这个全球的双轨制?and每次操作种子?嗯,实际上全局种子并不是必需的。它的存在是为了方便:它允许一次将所有随机操作种子设置为不同的确定性(如果未知)值,而不必详尽地遍历所有这些值。
现在,根据文档,当设置了全局种子而不是操作种子时,
系统确定性地选择操作种子和图级种子,以便获得唯一的随机序列。
更准确地说,提供的种子是当前图中创建的最后一个操作的 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
to gen1
with
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
但显然,这不应该通过代码审查。