TensorFlow中"y=x"与y=tf.identity(x)的区别及代码疑问
y = x和y = tf.identity(x)在tf.control_dependencies下表现不同? 这个问题刚好踩中了TensorFlow静态计算图的一个容易混淆的细节——控制依赖只追踪新创建的操作节点,而不是张量的引用。咱们把两个代码的差异拆解明白:
首先先明确tf.control_dependencies的核心作用:它会让上下文块内所有新创建的操作(Op),都必须等待指定的操作执行完成后才能运行。但它对“单纯的张量赋值引用”完全无效。
代码1:y = x为什么输出全是0.0?
import tensorflow as tf x = tf.Variable(0.0, name="x") x_plus_1 = tf.assign_add(x, 1.0) with tf.control_dependencies([x_plus_1]): y = x # 这里只是引用已存在的x张量,没有创建新操作 init = tf.initialize_all_variables() with tf.Session() as sess: init.run() for i in range(5): print(y.eval())
当你写y = x时,并没有在计算图中新增任何操作节点——y只是x这个张量的一个“别名”,指向同一个已经存在的变量节点。tf.control_dependencies对这种单纯的引用关系毫无作用,它没办法强制要求“取x的值之前必须先执行x_plus_1”。
所以每次调用y.eval()时,程序直接读取了x当前的存储值(初始是0.0),完全没触发x_plus_1的执行,自然输出全是0.0。
代码2:y = tf.identity(x)为什么会递增输出?
import tensorflow as tf x = tf.Variable(0.0, name="x") x_plus_1 = tf.assign_add(x, 1.0) with tf.control_dependencies([x_plus_1]): y = tf.identity(x) # 创建了一个新的identity操作节点 init = tf.initialize_all_variables() with tf.Session() as sess: init.run() for i in range(5): print(y.eval())
这里tf.identity(x)的关键是:它在计算图里创建了一个全新的操作节点,这个节点的功能就是复制输入张量x的值。
因为这个新节点是在tf.control_dependencies([x_plus_1])的上下文里创建的,所以TensorFlow会自动给它加上依赖关系:必须先执行完x_plus_1(把x的值加1),才能执行这个identity节点去获取x的新值。
所以每次y.eval()都会先触发x加1,再返回更新后的值,输出就是1.0、2.0、3.0、4.0、5.0。
额外补充:还有哪些写法能达到和tf.identity一样的效果?
只要是在控制依赖上下文里创建新操作的写法都可以,比如:
y = x + 0.0(生成加法操作节点)y = tf.identity(x)(最标准的写法)y = tf.reshape(x, shape=[])(如果x是标量的话,生成reshape节点)
这些写法都会生成新的操作节点,从而被tf.control_dependencies约束,强制先执行前置的x_plus_1操作。
内容的提问来源于stack exchange,提问作者t94126

