Diese Seite wurde von der Cloud Translation API übersetzt.
Switch to English

Einführung in der grafischen Darstellungen und Funktionen

Auf TensorFlow.org Führen Sie in Google Colab Quelltext anzeigen auf GitHub Herunterladen Notebook

Einführung in Graphen und tf.function

Dieses Handbuch geht unter der Oberfläche der TensorFlow und Keras zu sehen, wie TensorFlow funktioniert. Wenn Sie stattdessen sofort wollen mit Keras loszulegen, finden Sie in unserer Sammlung von Keras Führer .

In diesem Handbuch finden Sie den Kern zu sehen, wie TensorFlow können Sie einfache Änderungen an Ihrem Code, um Graphen zu bekommen, und wie sie gespeichert und dargestellt ist, und wie man sie nutzen, um Ihre Modelle zu beschleunigen und exportieren.

Dies ist eine Kurzform Einführung; für eine vollständige Einführung in diesen Konzepten finden Sie die tf.function Führung .

Was sind Graphen?

In den letzten drei Führungen haben Sie TensorFlow eifrig laufen gesehen. Dies bedeutet, TensorFlow Operationen werden von Python, den Betrieb durch Operation ausgeführt, und welche Ergebnisse zu Python zurück. Eager TensorFlow nutzt GPUs, so dass Sie Platz Variablen, Tensoren und sogar Operationen auf GPUs und TPUs. Es ist auch leicht zu debuggen.

Für einige Benutzer, können Sie nie wollen, müssen oder Python verlassen.

Allerdings laufen TensorFlow op-by-op in Python verhindert eine Vielzahl von Beschleunigungen anderweitig zur Verfügung. Wenn Sie Tensor Berechnungen von Python extrahieren, können Sie sie in ein Diagramm machen.

Graphs sind Datenstrukturen , die einen Satz enthalten tf.Operation Objekte, die Einheiten der Berechnung darstellen; und tf.Tensor Objekte, die die Dateneinheiten darstellen , die zwischen den Operationen fließen. Sie werden in einem definierten tf.Graph Kontext. Da diese Diagramme Datenstrukturen sind, können sie gespeichert, ausgeführt werden, und wieder alles ohne den Original-Code Python.

Dies ist, was eine einfache zweischichtige Graph aussieht, wenn in TensorBoard visualisiert mag.

eine zweischichtige tensorflow Graph

Die Vorteile von Graphen

Mit einem Graphen, haben Sie ein hohes Maß an Flexibilität. Sie können Ihre TensorFlow Graph in Umgebungen verwenden, die, wie mobile Anwendungen, Embedded-Geräte und Back-End-Server keine Python-Interpreter haben. TensorFlow verwendet Graphen als Format für die gespeicherten Modelle, wenn es sie von Python exportiert.

Graphen werden auch leicht optimiert, den Compiler ermöglicht Transformationen zu tun:

  • Statisch schließen , um den Wert von Tensoren durch ständigen Knoten in Ihrer Berechnung Faltung ( „konstante Faltung“).
  • Getrennte Unterteile einer Berechnung, die unabhängig sind und zwischen ihnen aufgeteilt Fäden oder Geräten.
  • Vereinfachen Sie arithmetische Operationen durch gemeinsame Unterausdrücke zu beseitigen.

Es gibt eine ganze Optimierungssystem, Grappler , diese und andere speedups auszuführen.

Kurz gesagt, Grafiken sind äußerst nützlich und lassen Sie Ihren TensorFlow schnell laufen, parallel laufen und effizient auf mehreren Geräten ausgeführt werden .

Sie möchten jedoch noch unsere Modelle für maschinelles Lernen (oder andere Berechnungen) in Python für Bequemlichkeit definieren, und dann automatisch Graphen konstruieren, wenn Sie sie benötigen.

Tracing Graphen

Die Art und Weise Sie eine Grafik in TensorFlow erstellen verwenden tf.function , entweder als direkter Anruf oder als Dekorateur.

 import tensorflow as tf
import timeit
from datetime import datetime
 
 # Define a Python function
def function_to_get_faster(x, y, b):
  x = tf.matmul(x, y)
  x = x + b
  return x

# Create a `Function` object that contains a graph
a_function_that_uses_a_graph = tf.function(function_to_get_faster)

# Make some tensors
x1 = tf.constant([[1.0, 2.0]])
y1 = tf.constant([[2.0], [3.0]])
b1 = tf.constant(4.0)

# It just works!
a_function_that_uses_a_graph(x1, y1, b1).numpy()
 
array([[12.]], dtype=float32)

tf.function -ized Funktionen sind Python Callables , die die gleichen wie ihre Äquivalente Python arbeiten. Sie haben eine bestimmte Klasse ( python.eager.def_function.Function ), aber Sie wirken sie ebenso wie die nicht-zurückverfolgt Version.

tf.function rekursiv verfolgt jede Python - Funktion es nennt.

 def inner_function(x, y, b):
  x = tf.matmul(x, y)
  x = x + b
  return x

# Use the decorator
@tf.function
def outer_function(x):
  y = tf.constant([[2.0], [3.0]])
  b = tf.constant(4.0)

  return inner_function(x, y, b)

# Note that the callable will create a graph that
# includes inner_function() as well as outer_function()
outer_function(tf.constant([[1.0, 2.0]])).numpy()
 
array([[12.]], dtype=float32)

Wenn Sie TensorFlow 1.x verwendet haben, werden Sie feststellen , dass zu keinem Zeitpunkt haben Sie einen definieren müssen Placeholder oder tf.Sesssion .

Flusskontrolle und Nebenwirkungen

Durchflussregelung und Schleifen werden zu TensorFlow über umgewandelt tf.autograph standardmäßig. Autograph verwendet eine Kombination von Methoden, einschließlich der Standardisierung Schleifenkonstrukte, Abrollen und AST Manipulation.

 def my_function(x):
  if tf.reduce_sum(x) <= 1:
    return x * x
  else:
    return x-1

a_function = tf.function(my_function)

print("First branch, with graph:", a_function(tf.constant(1.0)).numpy())
print("Second branch, with graph:", a_function(tf.constant([5.0, 5.0])).numpy())
 
First branch, with graph: 1.0
Second branch, with graph: [4. 4.]

Sie können die Autograph Umwandlung direkt aufrufen, um zu sehen, wie Python in TensorFlow ops umgewandelt wird. Dies ist vor allem, nicht lesbar, aber man kann die Transformation sehen.

 # Don't read the output too carefully.
print(tf.autograph.to_code(my_function))
 
def tf__my_function(x):
    with ag__.FunctionScope('my_function', 'fscope', ag__.ConversionOptions(recursive=True, user_requested=True, optional_features=(), internal_convert_user_code=True)) as fscope:
        do_return = False
        retval_ = ag__.UndefinedReturnValue()

        def get_state():
            return (retval_, do_return)

        def set_state(vars_):
            nonlocal retval_, do_return
            (retval_, do_return) = vars_

        def if_body():
            nonlocal retval_, do_return
            try:
                do_return = True
                retval_ = (ag__.ld(x) * ag__.ld(x))
            except:
                do_return = False
                raise

        def else_body():
            nonlocal retval_, do_return
            try:
                do_return = True
                retval_ = (ag__.ld(x) - 1)
            except:
                do_return = False
                raise
        ag__.if_stmt((ag__.converted_call(ag__.ld(tf).reduce_sum, (ag__.ld(x),), None, fscope) <= 1), if_body, else_body, get_state, set_state, ('retval_', 'do_return'), 2)
        return fscope.ret(retval_, do_return)


Autograph automatisch konvertiert if-then - Klauseln, Schleifen, break , return , continue und mehr.

Die meiste Zeit wird Autogramm ohne besondere Überlegungen arbeiten. Allerdings gibt es einige Einschränkungen, und die tf.function Führung kann hier helfen, sowie die vollständige Autoreferenz

Sehen Sie die Geschwindigkeit nach oben

Nur Wickel eine Tensor-Funktion unter Verwendung von in tf.function nicht automatisch den Code beschleunigen. Für kleine Funktionen aufgerufen ein paar Mal auf einer einzigen Maschine, den Aufwand für ein Diagramm oder ein Diagramm Fragment kann dominieren Laufzeit aufrufen. Auch wenn die meisten der Berechnung bereits auf einem Beschleuniger geschehen, wie Stapel von GPU-schweren Faltungen, wird die Graph Speedup nicht groß sein.

Für komplizierte Berechnungen können Graphen, die eine signficiant Speedup bieten. Dies liegt daran, Graphen, die den Python-zu-Gerät-Kommunikation zu verringern, und einige speedups durchführen.

Dieser Code mal ein paar läuft auf einigen kleinen, dichten Schichten.

 # Create an oveerride model to classify pictures
class SequentialModel(tf.keras.Model):
  def __init__(self, **kwargs):
    super(SequentialModel, self).__init__(**kwargs)
    self.flatten = tf.keras.layers.Flatten(input_shape=(28, 28))
    self.dense_1 = tf.keras.layers.Dense(128, activation="relu")
    self.dropout = tf.keras.layers.Dropout(0.2)
    self.dense_2 = tf.keras.layers.Dense(10)

  def call(self, x):
    x = self.flatten(x)
    x = self.dense_1(x)
    x = self.dropout(x)
    x = self.dense_2(x)
    return x

input_data = tf.random.uniform([60, 28, 28])

eager_model = SequentialModel()
graph_model = tf.function(eager_model)

print("Eager time:", timeit.timeit(lambda: eager_model(input_data), number=10000))
print("Graph time:", timeit.timeit(lambda: graph_model(input_data), number=10000))

 
Eager time: 4.9249971129993355
Graph time: 2.026840765000088

polymorphe Funktionen

Wenn Sie eine Funktion verfolgen, erstellen Sie eine Function Objekt polymorph ist. Eine polymorphe Funktion ist eine Python aufrufbar, die mehrere konkrete Funktionsgraphen hinter einem API kapselt.

Sie können diese verwenden Function auf allen verschiedenen Arten von dtypes und Formen. Jedes Mal, wenn Sie es mit einem neuen Argument Unterschrift aufrufen, wird die ursprüngliche Funktion zurückverfolgt mit den neuen Argumenten. Die Function speichert dann die tf.Graph in einer zu dieser Spur entsprechende concrete_function . Wird die Funktion bereits mit dieser Art von Argumentation verfolgt worden, erhalten Sie nur Ihre Pre-verfolgten Graphen.

Konzeptionell, dann gilt:

  • Ein tf.Graph ist die rohe, tragbare Datenstruktur , die eine Berechnung der Beschreibung
  • Eine Function ist ein Caching, Tracing, Dispatcher über ConcreteFunctions
  • Ein ConcreteFunction ist ein eifriger-kompatible Wrapper um ein Diagramm , das Sie die Grafik von Python kann ausführen

Inspizieren polymorphe Funktionen

Sie können prüfen a_function , die das Ergebnis des Aufrufs ist tf.function auf der Python - Funktion my_function . In diesem Beispiel ruft a_function mit drei Arten von Argumenten Ergebnisse in drei verschiedenen konkreten Funktionen.

 print(a_function)

print("Calling a `Function`:")
print("Int:", a_function(tf.constant(2)))
print("Float:", a_function(tf.constant(2.0)))
print("Rank-1 tensor of floats", a_function(tf.constant([2.0, 2.0, 2.0])))
 
<tensorflow.python.eager.def_function.Function object at 0x7f466417bf60>
Calling a `Function`:
Int: tf.Tensor(1, shape=(), dtype=int32)
Float: tf.Tensor(1.0, shape=(), dtype=float32)
Rank-1 tensor of floats tf.Tensor([1. 1. 1.], shape=(3,), dtype=float32)

 # Get the concrete function that works on floats
print("Inspecting concrete functions")
print("Concrete function for float:")
print(a_function.get_concrete_function(tf.TensorSpec(shape=[], dtype=tf.float32)))
print("Concrete function for tensor of floats:")
print(a_function.get_concrete_function(tf.constant([2.0, 2.0, 2.0])))

 
Inspecting concrete functions
Concrete function for float:
ConcreteFunction my_function(x)
  Args:
    x: float32 Tensor, shape=()
  Returns:
    float32 Tensor, shape=()
Concrete function for tensor of floats:
ConcreteFunction my_function(x)
  Args:
    x: float32 Tensor, shape=(3,)
  Returns:
    float32 Tensor, shape=(3,)

 # Concrete functions are callable
# Note: You won't normally do this, but instead just call the containing `Function`
cf = a_function.get_concrete_function(tf.constant(2))
print("Directly calling a concrete function:", cf(tf.constant(2)))
 
Directly calling a concrete function: tf.Tensor(1, shape=(), dtype=int32)

In diesem Beispiel sehen Sie ziemlich weit in den Stapel. Sofern Sie nicht ausdrücklich Tracing verwalten, werden Sie normalerweise nicht benötigen direkt konkrete Funktionen aufrufen, wie hier gezeigt.

Zurückkehren zu eifrig Ausführung

Sie können sich finden , auf lange Stack - Traces suchen, speziell diejenigen , die Bezug zu nehmen tf.Graph oder with tf.Graph().as_default() . Das heißt, Sie sind in einem Diagramm Kontext wahrscheinlich ausgeführt wird. Kernfunktionen in TensorFlow Verwendung Graph Kontexten, wie Keras des model.fit() .

Es ist oft viel einfacher zu debuggen eifrig Ausführung. Stack-Traces sollte relativ kurz und leicht verständlich sein.

In Situationen, in denen der Graph heikel macht das Debuggen, können Sie zur Verwendung von eifriger Ausführung zu debuggen zurück.

Hier sind Möglichkeiten, wie Sie sicherstellen können Sie laufen mit Spannung:

  • Rufen Sie Modelle und Schichten direkt als Callables

  • Bei der Verwendung von Keras Kompilierung / fit, bei der Kompilierung Gebrauch Zeit model.compile(run_eagerly=True)

  • Set globalen Ausführungsmodus über tf.config.run_functions_eagerly(True)

Mit run_eagerly=True

 # Define an identity layer with an eager side effect
class EagerLayer(tf.keras.layers.Layer):
  def __init__(self, **kwargs):
    super(EagerLayer, self).__init__(**kwargs)
    # Do some kind of initialization here

  def call(self, inputs):
    print("\nCurrently running eagerly", str(datetime.now()))
    return inputs
 
 # Create an override model to classify pictures, adding the custom layer
class SequentialModel(tf.keras.Model):
  def __init__(self):
    super(SequentialModel, self).__init__()
    self.flatten = tf.keras.layers.Flatten(input_shape=(28, 28))
    self.dense_1 = tf.keras.layers.Dense(128, activation="relu")
    self.dropout = tf.keras.layers.Dropout(0.2)
    self.dense_2 = tf.keras.layers.Dense(10)
    self.eager = EagerLayer()

  def call(self, x):
    x = self.flatten(x)
    x = self.dense_1(x)
    x = self.dropout(x)
    x = self.dense_2(x)
    return self.eager(x)

# Create an instance of this model
model = SequentialModel()

# Generate some nonsense pictures and labels
input_data = tf.random.uniform([60, 28, 28])
labels = tf.random.uniform([60])

loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
 

Zuerst kompilieren das Modell ohne eifrig. Beachten Sie, dass das Modell nicht verfolgt wird; trotz seines Namens, der compile setzt nur Verlustfunktionen auf, Optimierung und andere Trainingsparameter.

 model.compile(run_eagerly=False, loss=loss_fn)
 

Nun Anruf fit und sieht , dass die Funktion verfolgt wird (zweimal) und dann die eifrige Wirkung nie wieder läuft.

 model.fit(input_data, labels, epochs=3)
 
Epoch 1/3

Currently running eagerly 2020-08-04 01:22:21.848492

Currently running eagerly 2020-08-04 01:22:21.955102
2/2 [==============================] - 0s 1ms/step - loss: 1.4056
Epoch 2/3
2/2 [==============================] - 0s 1ms/step - loss: 0.0037
Epoch 3/3
2/2 [==============================] - 0s 1ms/step - loss: 0.0019

<tensorflow.python.keras.callbacks.History at 0x7f45f03c5630>

Wenn Sie auch nur eine einzige Epoche in eifrig laufen, jedoch können Sie den eifrigen Nebeneffekt zweimal sehen.

 print("Running eagerly")
# When compiling the model, set it to run eagerly
model.compile(run_eagerly=True, loss=loss_fn)

model.fit(input_data, labels, epochs=1)

 
Running eagerly

Currently running eagerly 2020-08-04 01:22:22.152979
1/2 [==============>...............] - ETA: 0s - loss: 8.7806e-04
Currently running eagerly 2020-08-04 01:22:22.173295
2/2 [==============================] - 0s 5ms/step - loss: 4.6877e-04

<tensorflow.python.keras.callbacks.History at 0x7f45f0312940>

Mit run_functions_eagerly

Sie können auch alles global gesetzt eifrig zu laufen. Beachten Sie, dass dies nur funktioniert, wenn Sie erneut Spur; verfolgt Funktionen bleiben als Diagramm verfolgt und ausgeführt werden.

 # Now, globally set everything to run eagerly
tf.config.run_functions_eagerly(True)
print("Run all functions eagerly.")

# First, trace the model, triggering the side effect
polymorphic_function = tf.function(model)

# It was traced...
print(polymorphic_function.get_concrete_function(input_data))

# But when you run the function again, the side effect happens (both times).
result = polymorphic_function(input_data)
result = polymorphic_function(input_data)
 
Run all functions eagerly.

Currently running eagerly 2020-08-04 01:22:22.202726
ConcreteFunction function(self)
  Args:
    self: float32 Tensor, shape=(60, 28, 28)
  Returns:
    float32 Tensor, shape=(60, 10)

Currently running eagerly 2020-08-04 01:22:22.206521

Currently running eagerly 2020-08-04 01:22:22.207818

 # Don't forget to set it back when you are done
tf.config.experimental_run_functions_eagerly(False)

 
WARNING:tensorflow:From <ipython-input-17-782fe9ce7b18>:2: experimental_run_functions_eagerly (from tensorflow.python.eager.def_function) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.config.run_functions_eagerly` instead of the experimental version.

Tracing und Leistung

Tracing Kosten einigen Aufwand. Obwohl Tracing kleine Funktionen schnell ist, können große Modelle nehmen spürbar Wandtaktzeit zu verfolgen. Diese Investition ist in der Regel schnell wieder mit einer Leistungssteigerung bezahlt, aber es ist wichtig, sich bewusst zu sein, dass die ersten Epochen jeder größeren Modellausbildung Tracing langsamer durch sein kann.

Egal wie groß Ihr Modell, möchten Sie häufig Verfolgung zu vermeiden. Dieser Abschnitt der tf.function Führung beschreibt , wie Set - Eingang Spezifikationen und Argumente verwenden Tensor zurückzuverfolgen zu vermeiden. Wenn Sie, Sie werden immer ungewöhnlich schlechte Leistung finden, ist es gut zu sehen, zu überprüfen, ob Sie versehentlich sind zurückzuverfolgen.

Sie können einen eifrigen nur für Nebenwirkungen (wie Drucken eines Python Argument) hinzufügen, damit Sie sehen können, wenn die Funktion zurückgeführt wird. Hier finden Sie zusätzliche Nachvollziehen weil neue Python Argumente immer zurückzuverfolgen auslösen.

 # Use @tf.function decorator
@tf.function
def a_function_with_python_side_effect(x):
  print("Tracing!")  # This eager
  return x * x + tf.constant(2)

# This is traced the first time
print(a_function_with_python_side_effect(tf.constant(2)))
# The second time through, you won't see the side effect
print(a_function_with_python_side_effect(tf.constant(3)))

# This retraces each time the Python argument chances
# as a Python argument could be an epoch count or other
# hyperparameter
print(a_function_with_python_side_effect(2))
print(a_function_with_python_side_effect(3))

 
Tracing!
tf.Tensor(6, shape=(), dtype=int32)
tf.Tensor(11, shape=(), dtype=int32)
Tracing!
tf.Tensor(6, shape=(), dtype=int32)
Tracing!
tf.Tensor(11, shape=(), dtype=int32)

Nächste Schritte

Sie können eine tiefer gehende Diskussion sowohl auf der lesen tf.function API Referenzseite und an der Führung .