En TensorFlow, ce qui est tf.identité utilisée pour?

j'ai vu tf.identity utilisé dans quelques endroits, comme le tutoriel officiel CIFAR-10 et l'implémentation de la normalisation par lots sur stackoverflow, mais je ne vois pas pourquoi c'est nécessaire.

à quoi sert-il? Quelqu'un peut-il donner un ou deux cas d'utilisation?

une réponse proposée est qu'il peut être utilisé pour le transfert entre le CPU et le GPU. Ce n'est pas clair pour moi. Extension à la question, basée sur :loss = tower_loss(scope) est sous le bloc GPU, ce qui me suggère que tous les opérateurs définis dans tower_loss sont mappés sur le GPU. Puis, à la fin de <!-- 2, on voit total_loss = tf.identity(total_loss) avant son retour. Pourquoi? Quel serait le défaut de ne pas utiliser tf.identity ici?

40
demandé sur Salvador Dali 2016-01-19 16:01:41

7 réponses

après quelques trébuchements, je pense que j'ai remarqué un cas d'utilisation unique qui correspond à tous les exemples que j'ai vus. S'il existe d'autres cas d'utilisation, veuillez donner un exemple.

de cas d'Utilisation:

supposons que vous souhaitiez exécuter un opérateur à chaque fois qu'une Variable particulière est évaluée. Par exemple, si vous souhaitez en ajouter un à x chaque fois la variable y est évaluée. Il pourrait sembler que cela va fonctionner:

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

Il n'a pas: il va imprimer 0, 0, 0, 0, 0. Au lieu de cela, il semble que nous ayons besoin d'ajouter un nouveau noeud au graphe dans le control_dependencies bloc. Nous utilisons donc cette astuce:

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

cela fonctionne: il imprime 1, 2, 3, 4, 5.

si dans le tutoriel CIFAR-10 nous avons laissé tomber tf.identity, puis loss_averages_op ne jamais exécuter.

45
répondu rd11 2016-04-25 17:05:40

tf.identity est utile quand vous voulez explicitement transporter tenseur entre les appareils (comme, de GPU à un CPU). L'op ajoute send/recv les nœuds du graphe, qui rendent une copie lorsque les périphériques d'entrée et de sortie sont différents.

un comportement par défaut est que les noeuds send/recv sont ajoutés implicitement lorsque l'opération se produit sur un périphérique différent mais vous pouvez imaginer certaines situations (en particulier dans un paramétrage multi-threadé/distribué) où il pourrait être utile de récupérer la valeur de la variable plusieurs fois dans une seule exécution de l' session.run. tf.identity permet plus de contrôle en ce qui concerne le moment où la valeur doit être lue à partir du périphérique source. Éventuellement un nom plus approprié pour cette op serait read.

veuillez également noter que dans la mise en œuvre de tf.Variablelien, l'option identity est ajoutée dans le constructeur, ce qui permet de s'assurer que tous les accès à la variable copient les données de la source une seule fois. Plusieurs copies peuvent être coûteuses dans les cas où la variable vit sur un GPU, mais elle est lue par plusieurs CPU ops (ou l'inverse). Les utilisateurs peuvent modifier le comportement avec plusieurs appels à tf.identity lorsque vous le souhaitez.

modifier: réponse mise à jour après la modification de la question.

en outre,tf.identity peut être utilisé comme noeud fictif pour mettre à jour une référence au tenseur. Ceci est utile pour diverses opérations d'écoulement de contrôle. Dans le cas de la CIFAR, nous voulons faire respecter le ExponentialMovingAverageOp mettra à jour les variables pertinentes avant de récupérer la valeur de la perte. Cela peut être mis en œuvre comme:

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

Ici tf.identity ne fait rien d'utile à part marquer le total_loss tenseur d'être couru après l'évaluation de loss_averages_op.

22
répondu Rafał Józefowicz 2016-01-19 18:04:00

en plus de ce qui précède, je l'utilise simplement quand j'ai besoin d'assigner un nom à ops qui n'ont pas d'argument nom, tout comme lors de l'initialisation d'un État dans RN'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")
7
répondu ahmedhosny 2017-12-24 06:07:44

je suis tombé sur un autre cas d'utilisation qui n'est pas couvert par les autres réponses.

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

la plupart du temps lors de la construction d'une couche de convolution, vous voulez juste que les activations soient retournées pour que vous puissiez les insérer dans la couche suivante. Parfois, cependant - par exemple lors de la construction d'un encodeur automatique-vous voulez les valeurs de pré - activation.

dans cette situation une solution élégante est de passer tf.identity comme la fonction d'activation, n'activant pas effectivement couche.

4
répondu Arthelais 2016-08-25 09:33:22

j'ai trouvé une autre application de tf.identité en Tensorboard. Si vous utilisez tf.shuffle_batch, il renvoie plusieurs tenseurs à la fois, donc vous voyez une image désordonnée lors de la visualisation du Graphe, vous ne pouvez pas diviser le pipeline de création de tenseurs à partir des tenseurs d'entrée actiual: malpropre

mais avec tf.d'identité, vous pouvez créer des copies de nœuds, qui n'affectent pas le calcul du flux: nice

3
répondu grihabor 2017-06-23 10:25:16

lorsque nos données d'entrée sont sérialisées en octets, et nous voulons extraire des fonctionnalités de cet ensemble de données. Nous pouvons le faire dans le format clé-valeur et ensuite obtenir un placeholder pour elle. Ses avantages sont plus réalisé lorsqu'il y a plusieurs caractéristiques et chaque fonctionnalité doit être lu en format différent.

  #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')
1
répondu Shyam Swaroop 2018-02-08 22:37:25

dans la formation de distribution, nous devrions utiliser tf.l'identité ou les travailleurs vais accrocher à l'attente pour l'initialisation du chef du travailleur:

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)

pour plus de détails, sans identité, le chef traiterait certaines variables comme des variables locales de façon inappropriée et les autres travailleurs attendent une opération d'initialisation qui ne peut pas se terminer

0
répondu Ju Xuan 2017-12-25 14:29:40