Tensorfow中使用tf.identity()的作用

Tensorfow中使用tf.identity()的作用先来看 TensorFlow 中对 identity 的定义 defidentity input name None nbsp pylint disable redefined builtin nbsp

先来看TensorFlow中对identity的定义:

def identity(input, name=None):  # pylint: disable=redefined-builtin
  r“””Return a tensor with the same shape and contents as input.
  Args:
    input: A `Tensor`.
    name: A name for the operation (optional).
  Returns:
    A `Tensor`. Has the same type as `input`.
  “””






  if context.in_graph_mode():
    return gen_array_ops.identity(input, name=name)
  else:
    if context.context().device_name != input.device:
      return input._copy()  # pylint: disable=protected-access
    return input






它返回一个和输入的 tensor 大小和数值都一样的 tensor ,类似于 y=x 操作,我们通常可以查到以下使用示例:

import tensorflow as tf g = tf.Graph() with g.as_default(): x = tf.Variable(1.0, name='x') x_plus_1 = tf.assign_add(x, 1, name='x_plus') with tf.control_dependencies([x_plus_1]): y = x z=tf.identity(x,name='z_added') init = tf.global_variables_initializer() with tf.Session() as sess: sess.run(init) for i in range(5): print(sess.run(z)) # 输出 2,3,4,5,6 # 如果改为输出 print(sess.run(y)) ,则结果为 1,1,1,1,1 

但是所有的博客资料都没有详细说明为什么会这样,以及在 Graph 的构建中,这个方法应该怎么使用。

起初一看,这个方法好像并没有什么用,只是把输入原样复制了一遍,但是实际上,tf.identity在计算图内部创建了两个节点,send / recv节点,用来发送和接受两个变量,如果两个变量在不同的设备上,比如 CPU 和 GPU,那么将会复制变量,如果在一个设备上,将会只是一个引用。

之所以会出现上面代码的情况,就是因为 y = x 并没有在计算图中占有一席之地,所以每次sess.run(y) 的时候都没有进行它的上一步 tf.control_dependencies 的操作,而 z 的计算则不同,它是计算图内部的节点,所以每次sess.run(z) 的时候都会进行 tf.control_dependencies 的操作,所以它输出的值每次都会更新; 并且,我们可以想见,如果我们同时输出 y 和 z,那么 y 的值也会同步更新为2,3,4,5,6。

我们打印该计算图内部所有的 OP,可以看到也是没有 y 这样一个计算节点存在的:

[<tf.Operation 'x/initial_value' type=Const>, <tf.Operation 'x' type=VariableV2>, <tf.Operation 'x/Assign' type=Assign>, <tf.Operation 'x/read' type=Identity>, <tf.Operation 'x_plus/value' type=Const>, <tf.Operation 'x_plus' type=AssignAdd>, <tf.Operation 'z_added' type=Identity>, <tf.Operation 'init' type=NoOp>] 

那么在什么时候使用这个方法呢?

它是通过在计算图内部创建 send / recv节点来引用或复制变量的,最主要的用途就是更好的控制在不同设备间传递变量的值

另外,它还有一种常见的用途,就是用来作为一个虚拟节点来控制流程操作,比如我们希望强制先执行loss_averages_op或updata_op,然后更新相关变量。这可以实现为:

with tf.control_dependencies([loss_averages_op]): total_loss = tf.identity(total_loss) 

或者:

with tf.control_dependencies([updata_op]): train_tensor = tf.identity(total_loss,name='train_op') 

在这里,tf.identity除了在执行 loss_averages_op之后标记total_loss张量被执行之外没有做任何有用的事情。

 

 

(1)与control_dependencies配套使用主要解释见博文:https://blog.csdn.net/hu_guan_jie/article/details/

(2)tf.identity is useful when you want to explicitly transport tensor between devices (like, from GPU to a CPU). The op adds send/recv nodes to the graph, which make a copy when the devices of the input and the output are different.

A default behavior is that the send/recv nodes are added implicitly when the operation happens on a different device but you can imagine some situations (especially in a multi-threaded/distributed settings) when it might be useful to fetch the value of the variable multiple times within a single execution of the session.runtf.identity allows for more control with regard to when the value should be read from the source device. Possibly a more appropriate name for this op would be read.

Also, please note that in the implementation of tf.Variable link, the identity op is added in the constructor, which makes sure that all the accesses to the variable copy the data from the source only once. Multiple copies can be expensive in cases when the variable lives on a GPU but it is read by multiple CPU ops (or the other way around). Users can change the behavior with multiple calls to tf.identity when desired.

EDIT: Updated answer after the question was edited.

In addition, tf.identity can be used used as a dummy node to update a reference to the tensor. This is useful with various control flow ops. In the CIFAR case we want to enforce that the ExponentialMovingAverageOp will update relevant variables before retrieving the value of the loss. This can be implemented as:

with tf.control_dependencies([loss_averages_op]): total_loss = tf.identity(total_loss) 

Here, the tf.identity doesn’t do anything useful aside of marking the total_loss tensor to be ran after evaluating loss_averages_op.

(3)为没有名称参数的op分配name

In addition to the above, I simply use it when I need to assign a name to ops that do not have a name argument, just like when initializing a state in RNN’s:

rnn_cell = tf.contrib.rnn.MultiRNNCell([cells]) # no name arg initial_state = rnn_cell.zero_state(batch_size,tf.float32) # give it a name with tf.identity() initial_state = tf.identity(input=initial_state,name="initial_state")

 (4)当我们的输入数据以字节为单位进行序列化时,我们想要从该数据集中提取特征。 我们可以关键字格式执行此操作,然后为其获取占位符。 当有多个功能并且每个功能必须以不同的格式读取时,它的好处更加明显。

 #read the entire file in this placeholder serialized_tf_example = tf.placeholder(tf.string, name='tf_example') #Create a pattern in which data is to be extracted from input files feature_configs = {'image': tf.FixedLenFeature(shape=[256], dtype=tf.float32),/ 'text': tf.FixedLenFeature(shape=[128], dtype=tf.string),/ 'label': tf.FixedLenFeature(shape=[128], dtype=tf.string),} #parse the example in key: tensor dictionary tf_example = tf.parse_example(serialized_tf_example, feature_configs) #Create seperate placeholders operation and tensor for each feature image = tf.identity(tf_example['image'], name='image') text = tf.identity(tf_example['text'], name='text') label = tf.identity(tf_example['text'], name='label')

(4)In distribution training, we should use tf.identity or the workers will hang at waiting for initialization of the chief worker:

vec = tf.identity(tf.nn.embedding_lookup(embedding_tbl, id)) * mask with tf.variable_scope("BiRNN", reuse=None): out, _ = tf.nn.bidirectional_dynamic_rnn(fw, bw, vec, sequence_length=id_sz, dtype=tf.float32)

For details, without identity, the chief worker would treat some variables as local variables inappropriately and the other workers wait for an initialization operation that can not end。 

 

(5)I found another application of tf.identity in Tensorboard. If you use tf.shuffle_batch, it returns multiple tensors at once, so you see messy picture when visualizing the graph, you can’t split tensor creation pipeline from actiual input tensors:

Tensorfow中使用tf.identity()的作用

But with tf.identity you can create duplicate nodes, which don’t affect computation flow: 

Tensorfow中使用tf.identity()的作用

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/233586.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 联想服务器R630 收集日志

    联想服务器R630 收集日志

    2021年8月30日
    106
  • Log4cpp介绍及使用

    Log4cpp介绍及使用

    2021年12月1日
    38
  • python创建数组的方法_python数组和列表

    python创建数组的方法_python数组和列表另见数组创建相关API简介创建数组有5种常规机制:从其他Python结构(例如,列表,元组)转换numpy原生数组的创建(例如,arange、ones、zeros等)从磁盘读取数组,无论是标准格式还是自定义格式通过使用字符串或缓冲区从原始字节创建数组使用特殊库函数(例如,random)本节不包括复制,连接或以其他方式扩展或改变现有数组的方法。它也不会涵盖创建对象数组或结构化数组。这些都包含在他们自己的章节中。将Pythonarray_like对象转换为Numpy数组通常,在Pytho

    2025年6月21日
    1
  • python lambda表达式_Python进阶

    python lambda表达式_Python进阶Lambda表达式lambda表示的是匿名函数,不需要用def来声明,一句话就可以声明出一个函数语法函数名=lambda参数:返回值注意点1.函数的参数可以有多个,多个参数之间用逗号隔

    2022年7月28日
    5
  • C++优先队列_队列queue中添加元素的方法

    C++优先队列_队列queue中添加元素的方法1.优先级队列(priority_queue)1.1基本概念之前已经提到了队列(queue),队列是一种先进先出(FirstinFirstout,FIFO)的数据类型。每次元素的入队都只能添加到队列尾部,出队时从队列头部开始出。优先级队列(priority_queue)其实,不满足先进先出的条件,更像是数据类型中的“堆”。优先级队列每次出队的元素是队列中优先级最高的那个元素,而不是队首的元素。这个优先级可以通过元素的大小等进行定义。比如定义元素越大优先级越高,那么每次出队,都是将当前队.

    2022年9月23日
    2
  • bi报表工具有哪些_bi报表工具排名

    bi报表工具有哪些_bi报表工具排名  随着现在数据量井喷式的爆发以及企业对数据的重视程度逐渐提供,高灵活性、易使用、具有高度数据治理能力的自定义bi报表工具被越来越多的人青睐,逐渐取代传统报表工具成为企业内报表平台的首选。  接下来,我们了解一下好用的bi报表工具应该具备哪些功能特性以及能力呢。  一、数据标准化能力  上面我们讲到传统报表的一个突出劣势就是对数据的标准化处理能力欠缺,影响报表的最终使用效果。很多企业标准化能力不足,主要是由于报表是由很多指标组成,企业内基本指标是固定的,但是指标的组合方式却是纷…

    2025年7月25日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号