Tensorflow 被“tf.cond”的行为弄糊涂了`

Tensorflow 被“tf.cond”的行为弄糊涂了`,tensorflow,Tensorflow,我需要在我的图中有一个条件控制流。如果pred为True,则图形应调用更新变量然后返回的op,否则返回变量不变。简化版本为: pred=tf.常数(真) x=tf.变量([1]) assign_x_2=tf.assign(x,[2]) def更新_x_2(): 使用tf.control_依赖项([assign_x_2]): 返回tf.identity(x) y=tf.cond(pred,update_x_2,lambda:tf.identity(x)) 使用tf.Session()作为会话: s

我需要在我的图中有一个条件控制流。如果
pred
True
,则图形应调用更新变量然后返回的op,否则返回变量不变。简化版本为:

pred=tf.常数(真)
x=tf.变量([1])
assign_x_2=tf.assign(x,[2])
def更新_x_2():
使用tf.control_依赖项([assign_x_2]):
返回tf.identity(x)
y=tf.cond(pred,update_x_2,lambda:tf.identity(x))
使用tf.Session()作为会话:
session.run(tf.initialize\u all\u variables())
打印(y.eval())

但是,我发现
pred=True
pred=False
都会导致相同的结果
y=[2]
,这意味着当
tf.cond
未选择
update\ux\u2
时,也会调用赋值运算。如何解释?如何解决这个问题;DR:如果您想在其中一个分支中执行副作用(如赋值),则必须在传递给
tf.cond()的函数中创建执行副作用的op

tf.cond()
的行为有点不直观。由于TensorFlow图中的执行在图中向前流动,因此在计算条件之前必须执行分支中引用的所有操作。这意味着true和false分支都接收对
tf.assign()
op的控制依赖,因此
y
始终设置为
2
,即使
pred是
false`

解决方案是在定义真正分支的函数内创建
tf.assign()
op。例如,您可以按如下方式构造代码:

pred=tf.placeholder(tf.bool,shape=[])
x=tf.变量([1])
def更新_x_2():
使用tf.control_依赖项([tf.assign(x[2])):
返回tf.identity(x)
y=tf.cond(pred,update_x_2,lambda:tf.identity(x))
使用tf.Session()作为会话:
session.run(tf.initialize\u all\u variables())
打印(y.eval(feed_dict={pred:False}))#==>[1]
打印(y.eval(feed_dict={pred:True}))#==>[2]
这将得到
[1]
的结果


这个答案与上面的答案完全相同。但我想和大家分享的是,你可以把你想用的每一个操作都放在它的分支功能中。因为,给你的示例代码,tensor
x
is可以被
update\ux\u2
函数直接使用。

是的,这也让我感到困惑。我的理解是,在执行
tf.cond
之前,运行时会确保所有依赖项都已执行。
True
False
分支中的op的依赖关系也是
cond
的依赖关系,因此即使分支中的op可能永远不会执行,但它的所有依赖关系都会执行,这听起来对吗?是的-图形修剪会考虑所有潜在的依赖关系(任一分支的)来执行,并且仅当它们在一个分支中定义时才禁止执行,因为
CondContext
和该依赖关系将是一个死张量(阻止op执行),如果它不在分支中。这样做的原因是什么?为什么不修剪非活动分支后面的子图?@LenarHoyt:修剪发生在计算
pred
的值之前。这使得TensorFlow能够基于一个简单的键(本质上是
Session.run()
的参数)缓存一个修剪过的图,并使条件执行的实现变得简单而轻量级。同样的机制用于实现
tf.while_loop()
,在这一级别执行控制流的优势更加明显。
pred = tf.constant(False)
x = tf.Variable([1])

def update_x_2():
    assign_x_2 = tf.assign(x, [2])
    with tf.control_dependencies([assign_x_2]):
        return tf.identity(x)
y = tf.cond(pred, update_x_2, lambda: tf.identity(x))
with tf.Session() as session:
  session.run(tf.initialize_all_variables())
  print(y.eval())