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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 地理加权回归模型步骤_地理加权回归中的拟合度

    地理加权回归模型步骤_地理加权回归中的拟合度目录数据准备加载需要的R包导入空间数据空间自相关分析空间邻域面数据空间邻域点数据空间邻域全局空间自相关局部空间自相关空间回归分析线性回归分析地理加权回归经典的线性回归模型是建立在最小二乘法(OLS模型)基础上对参数进行“平均”或“全局”估计。如果自变量为空间数据,且自变量间存在空间自相关性,传统回归模型(OLS模型)残差项独立的假设将无法满足。地理加权回归(GWR)模型能够反映参数在不同空间的空间非平稳性,使变量间的关系可以随空间位置的变化而变化,其结果更符合客观实际,能反映局部情况。杨晴青,刘倩

    2022年10月7日
    4
  • 请注意,面试中有这7个行为肯定会被拒绝!

    请注意,面试中有这7个行为肯定会被拒绝!

    2022年2月14日
    51
  • Java实现静态代理[通俗易懂]

    Java实现静态代理[通俗易懂]使用静态代理时需要让目标对象和代理对象一起实现相同的接口或者继承相同的父类。这样做的目的就是为了通过调用代理对象中和目标对象相同的方法来实现调用目标对象的方法,从而达到代理的效果。第一步定义接口publicinterfaceIStatictProxy{voidprint();}第二步实现接口(目标对象)@Slf4jpublicclassTargetImplimplementsIStatictProxy{@Overridepublic

    2022年10月16日
    6
  • origin画图怎么拟合曲线_origin拟合平滑曲线

    origin画图怎么拟合曲线_origin拟合平滑曲线需要用到matlab的拟合曲线中的smoothingspline功能,同时origin画的图又比较好看且可以后续做多条切线,因此记录下matlab与origin联合使用的方法,并加上用origin的tangent插件做曲线多条切线的方法。

    2022年9月21日
    5
  • pycharm是下载社区版本的还是专业版本_vs专业版和企业版区别

    pycharm是下载社区版本的还是专业版本_vs专业版和企业版区别好多初用pycharm的朋友,不知道PyCharm专业版和PyCharm社区版的区别,总体而说pycharmpro2019mac是一种PythonIDE,带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,比如调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制。此外,该IDE提供了一些高级功能,以用于支持Django框架下的专业Web开发。…

    2022年8月29日
    4
  • js倒计时跳转页面_什么代码可以实现网页的跳转

    js倒计时跳转页面_什么代码可以实现网页的跳转以下是倒计时120秒跳转代码,对于需要倒计时的页面非常实用,如果倒计时后不想跳转,可以注销掉location.href=这行代码<spanclass=”time”></span><script>vart=120;vartime=document.getElementsByClassName(“time”)[0];functionfun(){t–;time.innerHTML=t;if(t<=0

    2022年8月12日
    5

发表回复

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

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