【问题标题】:Enqueue and increment variable in Tensor FlowTensorflow 中的入队和增量变量
【发布时间】:2016-11-18 03:06:14
【问题描述】:

如何让张量流图将递​​增的数字推送到队列中?

我只是为了学习目的而这样做,所以我希望你保持它与我正在做的事情相似(并纠正我做错的事情)。这是我的代码:

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

输出:

8
8

我希望它是 2 到 8 之间的 2 个随机数。相反,它总是弹出变量的当前值。

这是因为我不是推送变量的实际值而是推送一个指向变量的指针吗? Tensor Flow 的 documentation 表示 assign_add 返回

一个张量,它将在 添加已完成。

我再次尝试了解 Tensor Flow。如果您有任何学习资源(TensorFlow 网站除外),我将不胜感激!谢谢。

编辑:

push = queue.enqueue(add) 更改为 push = queue.enqueue(add + 0) 会导致预期的行为。有人可以解释一下吗?

【问题讨论】:

  • 您使用的是哪个版本?我在 tf.11 和 tf 12rc1 中尝试过,但我无法重现这种行为,当我尝试你的代码时,我看到 dequeue 会产生不同的数字

标签: python tensorflow


【解决方案1】:

@David Wong 是正确的,该变量只是对其基础张量的引用。即使你已经推送了 7 次,队列中的 7 个元素都指向同一个底层张量。执行pop时,引用并返回底层张量。

让我再解释一下。 assign_add(1) 只是更新引用的值,因此它返回一个引用。当您执行push = queue.enqueue(add) 时,它会在内部调用tf.convert_to_tensor(add),如果它的输入也是一个引用,它将返回一个引用。

您可以在 python shell 中检查tf.convert_to_tensor(add) 的输出:

In [2]: tf.convert_to_tensor(add)
Out[2]: <tf.Tensor 'AssignAdd:0' shape=() dtype=float32_ref>

dtype=float32_ref 表示它是一个引用。

至于add + 0,也可以在ipython shell中进行检查,相当于tf.add(add, 0)

In [3]: add+0
Out[3]: <tf.Tensor 'add:0' shape=() dtype=float32>

它不是一个引用并且有一个父节点add = push_var.assign_add(1)

所以这里的问题是

1) 一个张量在被推入队列时会被评估,它的所有父节点也会被评估。

在您的情况下,add + 0 被评估,它的父节点 add = push_assign_add(1) 也被评估,它将引用的值增加 1。

2) 推送到队列时不评估引用。队列中有简单的引用。当它们被弹出和引用时,它们的实际张量值被获取。

在您的情况下,所有这些引用都指向同一个张量。所以pops都返回8

【讨论】:

  • 嗯,我认为 queue.enqueue 只能推送张量的具体值,所以它会在运行期间强制评估参考
  • @YaroslavBulatov 你介意指出评估发生在哪里吗?
  • Enqueue 操作被执行时。它需要一个张量并将其放入队列中,因此 tensorflow 运行时在运行 enqueue 操作之前评估 assign_add。评估 assign_add 给出变量值
  • 嗯,我收回来,有一些类似引用的事情,我假设 enqueue op 按值而不是按引用获取张量,但看起来它的语义不同,具体取决于张量是否在 GPU 上 -- stackoverflow.com/questions/41308515/…
【解决方案2】:

这是因为您的“add”变量实际上是对 push_var 变量的引用。因此,当您推送到队列时,您正在推送对变量的引用。推送“add+0”意味着您正在推送一个新张量,其中包含“add+0”的值和推送时的“add”值,这就是它起作用的原因。

【讨论】:

  • 谢谢。您知道如何正确实现这一目标吗?
  • 是的,我不确定正确的方法是什么,但是实现这一点而又不会非常尴尬的一种方法是使用 tmp = tf.add(push_var, 1) (它返回一个新的张量),将 tmp 推入队列,然后 push_var = tf.assign(tmp)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-07
  • 2012-03-19
相关资源
最近更新 更多