有一个非常奇怪的例子:
w = tf.get_variable("w", shape=(), dtype=tf.int32,
initializer=tf.constant_initializer(2))
reset = tf.assign(w, 0)
update = tf.assign(w, w + 3)
update = tf.Print(update, [update])
reset = tf.Print(reset, [reset])
def body(i,x):
with tf.control_dependencies([update]):
t = tf.identity(w)
with tf.control_dependencies([reset]):
y = tf.identity(t)
return i+1, y
i, z = tf.while_loop(lambda i,z: i < 20, body, [0,0])
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(z))输出为5。但如何解释呢?正如我们所看到的,reset不被执行,而update只使用tf.Print执行一次。但是tf.while_loop将执行body 20次。所以这太神奇了。
更新
另一个奇怪的示例
import tensorflow as tf
x = tf.Variable(0, dtype=tf.int32)
old_val = tf.identity(x)
with tf.control_dependencies([old_val]):
new_val = tf.assign(x, x + 1)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run([old_val, new_val, x]))输出为[1,1,1]。在看完github的问题后,我也很困惑。sess.run()一个接一个地执行,这意味着它运行old_val,然后运行new_val,然后运行x。
当它运行old_val时,它得到0,当它运行new_val时,它发现old_val是new_val的依赖项,但是old_val已经运行。所以它立即运行new_val,得到1,然后运行x,得到1。
所以我认为它应该打印[0,1,1],那么有什么问题吗?
发布于 2017-11-12 19:22:14
以下是你为什么得到这个结果的解释:
让我们跟随您在会话中执行的节点上的图,看看会发生什么。
sess.run(z)
z是tf.while_loop的第二个返回变量,因此让我们看看执行tf.while_loop节点时会发生什么。
第一次迭代:
tf.while_loop执行body函数,直到谓词为真为止。因此,对于这第一次呼吁:
body(i,x)调用-> -- body函数的主体不引用x变量。因此
return i+1, y
while循环继续进行,现在在body调用中将y作为x传递。
第二次迭代:
body(i, x) = run(body(_,yvariable of the previous iteration))
现在,Tensorflow需要解析y变量。
y变量是tf.identity(t)tf.identity(t)必须在reset = tf.assign(w,0)之后执行。tf.identity(t)引用t。在执行reset之后,我们必须解析t,对其进行评估,然后退出y。因此:只有在执行t = tf.identity(w) ->之后才能执行update
因此,按以下顺序执行:update -> t -> reset -> y
评价结果:w = w + 3 -> w = 5; t = 5; w = 0; y = t = 5; return 5.
副作用
update和reset节点在body函数之外声明,这意味着它们只是两个独立的节点,现在它们被标记为执行的(概念上的)。
第三次迭代
计算顺序与上一次迭代相同,但是:update和reset节点已经执行(因为存在已执行的标志),因此tf.control_dependencies跳过它们的执行,Tensorflow只执行t和y。
因此:t = 5; y = 5; return 5.
正如您所看到的,从现在开始,您将得到5作为结果,始终如此。
https://stackoverflow.com/questions/47248406
复制相似问题