Reputation: 3886
How can I make a Tensor Flow graph push an incrementing number to a queue?
I am just doing this for learning purposes, so I'd prefer if you kept it similar to what I'm doing (and correct what I'm doing wrong). This is my code:
import tensorflow as tf
# create queue
queue = tf.RandomShuffleQueue(capacity=10, min_after_dequeue=1, dtypes=tf.float32)
# create variables, and "add" operation
push_var = tf.Variable(initial_value=1.0, trainable=False)
add = push_var.assign_add(1)
# enqueue operation
push = queue.enqueue(add)
# dequeue operation
pop = queue.dequeue()
sess = tf.InteractiveSession()
tf.initialize_all_variables().run()
# add var to stack
sess.run(push) # push_var = 2 after ran
sess.run(push) # push_var = 3 after ran
sess.run(push) # push_var = 4 after ran
sess.run(push) # push_var = 5 after ran
sess.run(push) # push_var = 6 after ran
sess.run(push) # push_var = 7 after ran
sess.run(push) # push_var = 8 after ran
# pop variable (random shuffle)
print sess.run(pop)
print sess.run(pop)
sess.close()
Output:
8
8
I'm expecting it to be 2 random numbers between 2 and 8. Instead, it always is popping the current value of the variable.
Is this because instead of pushing the actual value of the variable I am instead pushing a pointer to the variable? Tensor Flow's documentation says assign_add
returns
A Tensor that will hold the new value of this variable after the addition has completed.
Again, I'm trying to learn about Tensor Flow. I'd appreciate any learning resources (besides the TensorFlow website) if you have any! Thanks.
EDIT:
Changing push = queue.enqueue(add)
to push = queue.enqueue(add + 0)
results in expected behavior. Could someone explain this?
Upvotes: 4
Views: 703
Reputation: 3358
@David Wong is correct that the variable is just a reference to its underlying tensor. Even though you've pushed it 7 times, the 7 elements in the queue all point to the same underlying tensor. When pop
is executed, the underlying tensor is referenced and returned.
Let me explain a little bit more. The assign_add(1)
simply updates the referenced value, so it returns a reference. When you do push = queue.enqueue(add)
, it internally calls tf.convert_to_tensor(add)
which would return a reference if its input is also a reference.
You can inspect the output of tf.convert_to_tensor(add)
in the python shell:
In [2]: tf.convert_to_tensor(add)
Out[2]: <tf.Tensor 'AssignAdd:0' shape=() dtype=float32_ref>
The dtype=float32_ref
indicates it is a reference.
As for add + 0
, you can also inspect it in the ipython shell, which is equivalent to tf.add(add, 0)
:
In [3]: add+0
Out[3]: <tf.Tensor 'add:0' shape=() dtype=float32>
It is not a reference and has a parent node add = push_var.assign_add(1)
.
So the problem here is
1) a tensor would be evaluated when it is pushed to a queue, all its parent nodes would be evaluated as well.
In your case, the add + 0
is evaluated, so is its parent node add = push_assign_add(1)
which incremented the referenced value by 1.
2) a reference is not evaluated when pushed to a queue. There are simply references in the queue. When they are popped and referenced, their actually tensor values are fetched.
In your case, all these references all point to the same tensor. So the pops all return 8
.
Upvotes: 2
Reputation: 748
This is because your "add" variable is actually a reference to the push_var variable. Thus, when you push to queue, you are pushing a reference to the variable. Pushing "add+0" mean you are pushing a new tensor that contains the value of "add+0" with the value "add" at the time of the push, this is why it works.
Upvotes: 1