web-dev-qa-db-de.com

Wozu dient TensorFlow für die Identität?

Ich habe gesehen, wie tf.identity an einigen Stellen verwendet wurde, beispielsweise im offiziellen CIFAR-10-Tutorial und der Batch-Normalisierungsimplementierung für stackoverflow, aber ich sehe nicht, warum es notwendig ist.

Wozu dient es? Kann jemand einen oder zwei Anwendungsfälle geben?

Eine vorgeschlagene Antwort ist, dass es für die Übertragung zwischen CPU und GPU verwendet werden kann. Das ist mir nicht klar. Erweiterung der Frage, basierend auf this : loss = tower_loss(scope), befindet sich unter dem GPU-Block, was mir nahe legt, dass alle in tower_loss definierten Operatoren der GPU zugeordnet sind. Am Ende von tower_loss sehen wir total_loss = tf.identity(total_loss), bevor es zurückgegeben wird. Warum? Was wäre der Fehler, wenn Sie tf.identity hier nicht verwenden?

49
rd11

Nach einigem Stolpern denke ich, dass ich einen einzigen Anwendungsfall entdeckt habe, der zu allen Beispielen passt, die ich gesehen habe. Wenn es andere Anwendungsfälle gibt, erläutern Sie bitte ein Beispiel.

Anwendungsfall:

Angenommen, Sie möchten jedes Mal einen Operator ausführen, wenn eine bestimmte Variable ausgewertet wird. Angenommen, Sie möchten jedes Mal eine Variable zu x hinzufügen, wenn die Variable y ausgewertet wird. Es könnte so aussehen, als würde dies funktionieren:

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

Das ist nicht der Fall: Es wird 0, 0, 0, 0, 0 gedruckt. Stattdessen müssen wir dem Diagramm innerhalb des control_dependencies-Blocks einen neuen Knoten hinzufügen. Also benutzen wir diesen Trick:

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

Das funktioniert: Es druckt 1, 2, 3, 4, 5.

Wenn wir im CIFAR-10-Tutorial tf.identity abgelegt haben, wird loss_averages_op niemals ausgeführt.

55
rd11

tf.identity ist nützlich, wenn Sie den Tensor explizit zwischen Geräten transportieren möchten (z. B. von einer GPU zu einer CPU) . Das op fügt dem Graphen Sende/Empfangs-Knoten hinzu, die eine Kopie erstellen, wenn sich die Geräte der Eingabe und der Ausgabe befinden anders.

Ein Standardverhalten ist, dass die send/recv-Knoten implizit hinzugefügt werden, wenn die Operation auf einem anderen Gerät ausgeführt wird. Sie können sich jedoch einige Situationen vorstellen (insbesondere in Multithread-/verteilten Einstellungen), in denen es möglicherweise nützlich ist, den Wert der Variablen abzurufen mehrfach innerhalb einer einzigen Ausführung des session.run. tf.identity bietet mehr Kontrolle darüber, wann der Wert vom Quellgerät gelesen werden soll. Möglicherweise wäre ein geeigneter Name für diese Operation read.

Bitte beachten Sie auch, dass in der Implementierung von tf.Variablelink die Identitätsoperation op im Konstruktor hinzugefügt wird. Dadurch wird sichergestellt, dass alle Zugriffe auf die Variable die Daten nur einmal aus der Quelle kopieren. Mehrere Kopien können teuer sein, wenn sich die Variable auf einer GPU befindet, sie jedoch von mehreren CPU-Operatoren gelesen wird (oder umgekehrt). Benutzer können das Verhalten bei mehreren Anrufen in tf.identity ändern, wenn dies gewünscht wird.

BEARBEITEN: Aktualisierte Antwort, nachdem die Frage bearbeitet wurde.

Außerdem kann tf.identity als Scheinknoten verwendet werden, um eine Referenz auf den Tensor zu aktualisieren. Dies ist nützlich bei verschiedenen Kontrollflussoperationen. Im CIFAR-Fall möchten wir sicherstellen, dass ExponentialMovingAverageOp relevante Variablen aktualisiert, bevor der Wert des Verlusts abgerufen wird. Dies kann implementiert werden als:

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

Hier macht tf.identity nichts Nützliches, außer den total_loss-Tensor zu markieren, der nach der Auswertung von loss_averages_op ausgeführt werden soll.

28

Darüber hinaus benutze ich es einfach, wenn ich Ops, die kein Namensargument haben, einen Namen zuweisen muss, genau wie beim Initialisieren eines Zustands in RNNs:

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

Ich bin auf einen anderen Anwendungsfall gestoßen, der von den anderen Antworten nicht vollständig abgedeckt wird.

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

Beim Konstruieren einer Faltungsebene möchten Sie meist nur, dass die Aktivierungen zurückgegeben werden, damit Sie diese der nächsten Ebene zuführen können. Manchmal möchten Sie jedoch - zum Beispiel beim Erstellen eines Auto-Encoders - die Voraktivierungswerte.

In dieser Situation ist es eine elegante Lösung, tf.identity als Aktivierungsfunktion zu übergeben, ohne die Ebene effektiv zu aktivieren.

5
Arthelais

Ich habe eine andere Anwendung von tf.identity in Tensorboard gefunden. Wenn Sie tf.shuffle_batch verwenden, werden mehrere Tensoren gleichzeitig zurückgegeben. Wenn Sie also den Graphen visualisieren, sehen Sie ein chaotisches Bild : unordentlich

Mit tf.identity können Sie jedoch doppelte Knoten erstellen, die sich nicht auf den Berechnungsablauf auswirken: Nice

3
grihabor

Wenn unsere Eingabedaten in Bytes serialisiert werden und wir Features aus diesem Datensatz extrahieren möchten. Wir können dies im Schlüsselwertformat tun und dann einen Platzhalter dafür bekommen. Die Vorteile werden eher verwirklicht, wenn mehrere Funktionen vorhanden sind und jede Funktion in einem anderen Format gelesen werden muss.

  #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
Shyam Swaroop

Ich sehe diese Art von Hack, um zu bestätigen:

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)

Es wird auch nur verwendet, um einen Namen zu vergeben:

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

Bei der Verteilungstraining sollten wir die Identität verwenden, da die Arbeiter beim Warten auf die Initialisierung des Hauptarbeiters warten müssen:

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)

Ohne Details würde der Hauptarbeiter einige Variablen unangemessen als lokale Variablen behandeln und die anderen Arbeiter warten auf eine Initialisierungsoperation, die nicht enden kann

0
Ju Xuan