在TensorFlow中,tf.identity用于什么?

时间:2016-01-19 13:01:42

标签: python tensorflow

我已经在一些地方看到了tf.identity,例如官方的CIFAR-10教程和stackoverflow上的批量规范化实现,但我不明白为什么它'必要的。

它用于什么?任何人都可以提供一两个用例吗?

一个建议的答案是它可以用于CPU和GPU之间的传输。这对我来说并不清楚。基于this loss = tower_loss(scope)的问题的扩展位于GPU块下,这表明tower_loss中定义的所有运算符都映射到GPU。然后,在tower_loss的末尾,我们会在total_loss = tf.identity(total_loss)返回之前看到tf.identity。为什么?在这里不使用function showValues() { var store = $( ":radio" ).serializeArray(); var frequency = {}; // array of frequency. var max = 0; // holds the max frequency. var result; // holds the max frequency element. for(var v in store) { frequency[store[v]]=(frequency[store[v]] || 0)+1; // increment frequency. if(frequency[store[v]] > max) { // is this frequency > max so far ? max = frequency[store[v]]; // update max. result = store[v]; // update result. } } alert(result); } 会有什么缺陷?

8 个答案:

答案 0 :(得分:58)

经过一番磕磕绊绊之后,我想我已经注意到一个适合我所见过的所有例子的用例。如果还有其他用例,请详细说明。

用例:

假设您每次评估特定变量时都要运行运算符。例如,假设您每次评估变量x时都要向y添加一个。看起来这可能会起作用:

x = tf.Variable(0.0)
x_plus_1 = tf.assign_add(x, 1)

with tf.control_dependencies([x_plus_1]):
    y = x
init = tf.initialize_all_variables()

with tf.Session() as session:
    init.run()
    for i in xrange(5):
        print(y.eval())

它没有:它会打印0,0,0,0,0而是我们需要在control_dependencies块中向图表添加新节点。所以我们使用这个技巧:

x = tf.Variable(0.0)
x_plus_1 = tf.assign_add(x, 1)

with tf.control_dependencies([x_plus_1]):
    y = tf.identity(x)
init = tf.initialize_all_variables()

with tf.Session() as session:
    init.run()
    for i in xrange(5):
        print(y.eval())

这有效:它可以打印1,2,3,4,5。

如果在CIFAR-10教程中我们删除了tf.identity,则loss_averages_op将永远无法运行。

答案 1 :(得分:30)

当您想要在设备之间显式传输张量(例如,从GPU到CPU)时,

tf.identity非常有用。 op将send / recv节点添加到图形中,当输入和输出的设备不同时,它们会复制。

默认行为是当操作发生在不同的设备上时隐式添加send / recv节点但是你可以想象一些情况(特别是在多线程/分布式设置中),当它可能对获取值有用时在session.run的单次执行中多次变量。 tf.identity允许更多地控制何时应从源设备读取值。对于此操作,可能更合适的名称是read

另外,请注意,在tf.Variable link的实现中,在构造函数中添加了标识操作,这确保了对变量的所有访问仅从源复制数据一次。如果变量存在于GPU上但多个CPU操作(或其他方式)读取,则多个副本可能会很昂贵。用户可以在需要时多次调用tf.identity来更改行为。

编辑:编辑问题后更新了答案。

此外,tf.identity可用作虚拟节点来更新对张量的引用。这对于各种控制流程操作非常有用。在CIFAR案例中,我们希望强制执行ExponentialMovingAverageOp将在检索损失值之前更新相关变量。这可以实现为:

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

此处,tf.identity除了在评估total_loss后标记要运行的loss_averages_op张量之外,还没有做任何有用的事情。

答案 2 :(得分:15)

除了上述内容之外,我只需在需要为没有名称参数的操作分配名称时使用它,就像在RNN中初始化状态时一样:

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")

答案 3 :(得分:5)

我遇到了另一个用例,其他答案没有完全涵盖。

def conv_layer(input_tensor, kernel_shape, output_dim, layer_name, decay=None, act=tf.nn.relu):
    """Reusable code for making a simple convolutional layer.
    """
    # Adding a name scope ensures logical grouping of the layers in the graph.
    with tf.name_scope(layer_name):
        # This Variable will hold the state of the weights for the layer
        with tf.name_scope('weights'):
            weights = weight_variable(kernel_shape, decay)
            variable_summaries(weights, layer_name + '/weights')
        with tf.name_scope('biases'):
            biases = bias_variable([output_dim])
            variable_summaries(biases, layer_name + '/biases')
        with tf.name_scope('convolution'):
            preactivate = tf.nn.conv2d(input_tensor, weights, strides=[1, 1, 1, 1], padding='SAME')
            biased = tf.nn.bias_add(preactivate, biases)
            tf.histogram_summary(layer_name + '/pre_activations', biased)
        activations = act(biased, 'activation')
        tf.histogram_summary(layer_name + '/activations', activations)
        return activations

大多数情况下,在构建卷积层时,您只需要返回激活,这样您就可以将它们提供给下一层。但有时 - 例如在构建自动编码器时 - 您需要预激活值。

在这种情况下,一个优雅的解决方案是将tf.identity作为激​​活函数传递,实际上不会激活图层。

答案 4 :(得分:3)

我在Tensorboard中找到了另一个tf.identity应用程序。 如果你使用tf.shuffle_batch,它会一次返回多个张量,所以你在看到图形时会看到凌乱的图片,你不能从临时输入张量中分割出张量创建管道:messy

但是使用tf.identity可以创建重复的节点,这些节点不会影响计算流程:nice

答案 5 :(得分:1)

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

  #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')

答案 6 :(得分:0)

在分发培训中,我们应该使用tf.identity,否则工人将等待主要工作人员的初始化:

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)

有关详细信息,如果没有标识,主要工作人员会将一些变量视为局部变量,而其他工作人员则等待无法结束的初始化操作

答案 7 :(得分:0)

我看到了这种检查断言的技巧:

assertion = tf.assert_equal(tf.shape(image)[-1], 3, message="image must have 3 color channels")
with tf.control_dependencies([assertion]):
    image = tf.identity(image)

它也只是用来命名:

image = tf.identity(image, name='my_image')