先来看看官方解释
def identity(input, name=None): # pylint: disable=redefined-builtin r"""Return a tensor with the same shape and contents as input.
返回一个和输入 相同形状和内容 的 Tensor;
我们来分析一下:
1. 形状和内容都相同,那不就是等于吗?为什么还要这个函数呢?
2. 返回一个 Tensor,说明 tf.identity 是一个 op,因为 Tensor 是 op 的输入输出;
3. 也就是说,tf.identity 接受任意的 input,都强制输出 Tensor;
下面我们来验证一下
首先,以 constant 为例
##### constant 本身是个操作, 它的 = 也是操作 c = tf.constant(1.) print(c) # Tensor("Const:0", shape=(), dtype=float32) d = tf.identity(c, name='d') print(d) # Tensor("d:0", shape=(), dtype=float32) e = c print(e) # Tensor("Const:0", shape=(), dtype=float32)
tf.identity 和 = 没什么差别,只是加了个名字,然后我们可以不加的啊,不加名字,一模一样
接着,以 Variable 为例
##### Variable 本身不是操作,它的 = 不是操作 v = tf.Variable(2.) print(v) # <tf.Variable 'Variable:0' shape=() dtype=float32_ref>
no_name = tf.identity(v) print(no_name) # Tensor("Identity:0", shape=(), dtype=float32) x = tf.identity(v, name='x') print(x) # Tensor("x:0", shape=(), dtype=float32)
y = v print(y) # <tf.Variable 'Variable:0' shape=() dtype=float32_ref>
tf.identity 是个 op,而 = 不是 op;
此时,我们可以得出这样的结论:
tf.identity 是一个操作,把任意输入强制转换成 Tensor,如果 输入就是 Tensor,那他就等价于 =;
而 = 不是操作,只是内存拷贝;
然而这玩意有什么用呢?
这就要提到另一个方法 tf.control_dependencies,它只对其内部的操作起作用,
我们以一个累加的例子来说明
##### test1 x = tf.Variable(1.0) print(x) # <tf.Variable 'Variable:0' shape=() dtype=float32_ref> x_plus_1 = tf.assign_add(x, 1) ### 返回一个op # control_dependencies的意义是: # 在执行with包含的内容(y = x)前,先执行 control_dependencies 参数中的内容(x_plus_1),这里的解释不准确,先接着看。。。 with tf.control_dependencies([x_plus_1]): y = x print(y) # <tf.Variable 'Variable_6:0' shape=() dtype=float32_ref> ### y 只是个变量,不是 op init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) for i in range(5): print(sess.run(y)) # 1 1 1 1 1
先执行 with 包含的内容的前提是 ,该内容是个 操作,然而 y=x 不是操作,那么 control_dependencies 的参数 x_plus_1 没有执行,x 就还是 1, y=x 自然也是1,故输出 5 个 1
修改如下
##### test2 x = tf.Variable(1.0) x_plus_1 = tf.assign_add(x, 1) with tf.control_dependencies([x_plus_1]): y = x + 0.0 print(y) # Tensor("add:0", shape=(), dtype=float32) ### y 变成 add op init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) for i in range(5): print(sess.run(y)) # 2 3 4 5 6
with 内是个操作,x_plus_1 先执行,输出符合预期;
只是这样写有点别扭,y=x 和 y=x+0 产生了截然不同的结果;
继续修改
##### test3 x = tf.Variable(1.0) x_plus_1 = tf.assign_add(x, 1) with tf.control_dependencies([x_plus_1]): y = tf.identity(x, name='x') print(y) # Tensor("x:0", shape=(), dtype=float32) ### y 变成 add op init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) for i in range(5): print(sess.run(y)) # 2 3 4 5 6
tf.identity 登场了,他把 y=x 变成了一个 操作,结果符合预期;
当然也可以这样写
##### test4 x = tf.Variable(1.0) x = tf.assign_add(x, 1) with tf.control_dependencies([x]): y = x ### 等价于 y = tf.assign_add(x, 1) print(y) # Tensor("AssignAdd_3:0", shape=(), dtype=float32_ref) init = tf.initialize_all_variables() with tf.Session() as session: init.run() for i in range(5): print(y.eval()) # 2 3 4 5 6 ### 相当于sess.run(y)
总结:对于 control_dependencies 这个管理器,只有当里面的操作是一个 op 时,才会生效,也就是先执行传入的参数 op,再执行里面的 op;
而 y=x 仅仅是 一个简单赋值,不是 op,在 graph 中不会形成一个节点,这样该管理器就失效了;
tf.identity 是返回一个一模一样新的 tensor 的 op,这会增加一个新节点到 gragh 中,这时 control_dependencies 就会生效了
参考资料:
https://blog.csdn.net/hu_guan_jie/article/details/78495297
https://yq.aliyun.com/articles/487737
https://www.360kuai.com/pc/935e0f65c4a884856?cota=4&kuai_so=1&tj_url=so_rec&sign=360_57c3bbd1&refer_scene=so_1