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)
上一篇 2025年7月7日 上午11:01
下一篇 2025年7月7日 上午11:22


相关推荐

  • Java获取当前时间年月日_jquery获取当前时间年月日

    Java获取当前时间年月日_jquery获取当前时间年月日packagecom.ob;importjava.text.ParseException;importjava.text.SimpleDateFormat;importjava.util.Calendar;importjava.util.Date;publicclassDateTest{ publicstaticvoidmain(String[]args)

    2025年9月18日
    7
  • 以太坊钱包erc20_xvg币智能合约

    以太坊钱包erc20_xvg币智能合约以太坊被称为区块链2.0,就是因为以太坊在应用层提供了虚拟机,使得开发者可以基于它自定义逻辑,通常被称为智能合约,合约中的公共接口可以作为区块链中的普通交易执行。本文就智能合约发代币流程作一完整介绍(

    2022年8月4日
    6
  • 敏捷软件开发之原则篇

    敏捷软件开发之原则篇1 我们最优化先要做的是通过尽早的 持续的交付有减脂的软件来使客户满意 2 即使到了开发的后期 也欢迎改变需求 敏捷过程利用变化来为客户创造竞争优势 3 经常性地交付可以工作的软件 交付的间隔可以从几周到几个月 交付的时间间隔越短越好 4 在整个项目开发期间 业务人员和开发人员必须天天都在一起工作 5 围绕被激励起来的个人构建项目 给他们踢空所需的环境和支持 并且信任他们能够完成工

    2026年3月20日
    2
  • 【架构】Lambda架构

    【架构】Lambda架构一、出现的背景1.1从传统数据库到NoSQL,再到Hadoop很多人学习大数据都听说过以下发展进程,MySQL/Oracle/SQLServer→Hadoop/Hive/Spark。但还有一个时期,是大家容易忽略的——NoSQL。我们不能忽略掉它。其实,NoSQL的发展和推广要比Hadoop更早,在没有Hadoop的大数据过渡期,随着数据量急剧膨胀,大家纷纷从传统的关系型数据库转变到NoSQL数据库,各种各样的NoSQL数据库应用而生。有了NoSQL数据库,可以轻易将机器的数量扩展到.

    2022年6月25日
    35
  • route命令详解

    route命令详解route命令详解在网络中,route命令用来显示、添加、删除和修改网络的路由。1.route命令的格式route[-f][-p][Command][Destination][maskNetmask][Gateway][metricMetric][ifInterface]2.route-参数的含义:route-f:用于清除路由表。route-p:用于创建永久路由。routeComman:主要有print(打印路由)、ADD(添加路由)、DELETE(删

    2022年7月18日
    28
  • c语言计算利息答案是0.0,C语言 | 计算存款利息

    c语言计算利息答案是0.0,C语言 | 计算存款利息例 2 用 C 语言计算存款利息 假设有本金 1000 元 想存一年 有三种方法可选择 活期 年利率为 0 0036 一年期定期 年利率为 0 0225 存两次半年定期 年利率为 0 0198 请分别计算出一年后按 3 种方法所得到的本息和解题思路 这个问题的算法很简单 关键在于找到公式 若存款额为 principal 0 也就是本金活期存款一年后的本息和为 principal 0 1 interest Rate1

    2026年3月16日
    1

发表回复

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

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