I'm getting non-repeating results in TensorFlow (version 1.4.0), even though I'm resetting the seed to the same value each time:
import tensorflow as tf
sess = tf.InteractiveSession()
for i in range(5):
tf.set_random_seed(1234)
print(sess.run(tf.random_uniform([1])))
The output is:
[ 0.96046877]
[ 0.85591054]
[ 0.20277488]
[ 0.81463408]
[ 0.75180626]
I don't understand how this is consistent with the documentation :
If the graph-level seed is set, but the operation seed is not: The system deterministically picks an operation seed in conjunction with the graph-level seed so that it gets a unique random sequence.
Doesn't this mean that if I set the graph-level seed (as I did, using set_random_seed
), and I don't set the operation seed (as in my case, where I didn't specify the seed
argument in random_uniform
), I should expect to get repeating results?
A similar issue is addressed in this question, but the main emphasis here is to understand what the documentation means.
Additional details:
>> tf.__version__
'1.4.0-rc0'
>> tf.__git_version__
'v1.3.0-rc1-3732-g2dd1015'
EDIT 1:
I think I have a conjecture as to why this is the behavior.
The sentence "The system deterministically picks an operation seed in conjunction with the graph-level seed" does not mean that the op seed is a function of the graph seed only. Rather, it is also a function of some internal counter variable. The reason this makes sense is that otherwise, running
tf.set_random_seed(1234)
print(sess.run(tf.random_uniform([1])))
print(sess.run(tf.random_uniform([1])))
would yield two identical results (This is due to the fact(?) that the random number generator is stateless, and each op has its own seed).
To confirm this, I found that when terminating python and opening it again, the whole sequence of code at the beginning of the question does yield repeating results. Also, delving into the source of TensorFlow, I see that the file random_seed.py
has the lines
if graph_seed is not None:
if op_seed is None:
op_seed = ops.get_default_graph()._last_id
seeds = _truncate_seed(graph_seed), _truncate_seed(op_seed)
which shows that the seed of an op is a combination of two seeds: the graph seed and the _last_id
property of the graph, which is a counter that increases on each op that is added to the graph.