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

Verteiltes Training mit TensorFlow

Ansicht auf TensorFlow.org Führen Sie in Google Colab aus Quelle auf GitHub anzeigen Notizbuch herunterladen

Überblick

tf.distribute.Strategy ist eine TensorFlow-API zum Verteilen von Schulungen auf mehrere GPUs, mehrere Computer oder TPUs. Mit dieser API können Sie Ihre vorhandenen Modelle und den Trainingscode mit minimalen Codeänderungen verteilen.

tf.distribute.Strategy wurde unter tf.distribute.Strategy der folgenden Hauptziele entwickelt:

  • Einfache Verwendung und Unterstützung mehrerer Benutzersegmente, einschließlich Forscher, ML-Ingenieure usw.
  • Bieten Sie sofort eine gute Leistung.
  • Einfacher Wechsel zwischen Strategien.

tf.distribute.Strategy kann mit einer High-Level-API wie Keras verwendet werden und kann auch zum Verteilen von benutzerdefinierten Trainingsschleifen (und im Allgemeinen für jede Berechnung mit TensorFlow) verwendet werden.

In TensorFlow 2.x können Sie Ihre Programme eifrig oder in einem Diagramm mit tf.function . tf.distribute.Strategy beabsichtigt, beide Ausführungsmodi zu unterstützen, funktioniert jedoch am besten mit tf.function . Der Eifersuchtsmodus wird nur zum Debuggen empfohlen und für TPUStrategy nicht unterstützt. Obwohl die Schulung im Mittelpunkt dieses Handbuchs steht, kann diese API auch zum Verteilen von Bewertungen und Vorhersagen auf verschiedenen Plattformen verwendet werden.

Sie können tf.distribute.Strategy mit sehr wenigen Änderungen an Ihrem Code verwenden, da wir die zugrunde liegenden Komponenten von TensorFlow geändert haben, um strategiebewusst zu werden. Dies umfasst Variablen, Ebenen, Modelle, Optimierer, Metriken, Zusammenfassungen und Prüfpunkte.

In diesem Handbuch erklären wir verschiedene Arten von Strategien und wie Sie sie in verschiedenen Situationen einsetzen können. Informationen zum Debuggen von Leistungsproblemen finden Sie im Handbuch Optimieren der TensorFlow-GPU-Leistung .

# Import TensorFlow
import tensorflow as tf

Arten von Strategien

tf.distribute.Strategy beabsichtigt, eine Reihe von Anwendungsfällen entlang verschiedener Achsen abzudecken. Einige dieser Kombinationen werden derzeit unterstützt, andere werden in Zukunft hinzugefügt. Einige dieser Achsen sind:

  • Synchrones oder asynchrones Training: Dies sind zwei gängige Methoden zum Verteilen von Training mit Datenparallelität. Während des Synchronisierungstrainings trainieren alle Mitarbeiter synchron über verschiedene Teile der Eingabedaten und aggregieren bei jedem Schritt die Gradienten. Bei der asynchronen Schulung trainieren alle Mitarbeiter unabhängig voneinander die Eingabedaten und aktualisieren die Variablen asynchron. In der Regel wird das Synchronisierungstraining über All-Reduce und Async über die Parameterserver-Architektur unterstützt.
  • Hardwareplattform: Möglicherweise möchten Sie Ihr Training auf mehrere GPUs auf einem Computer oder auf mehrere Computer in einem Netzwerk (mit jeweils 0 oder mehr GPUs) oder auf Cloud-TPUs skalieren.

Um diese Anwendungsfälle zu unterstützen, stehen sechs Strategien zur Verfügung. Im nächsten Abschnitt wird erläutert, welche davon in welchen Szenarien in TF unterstützt werden. Hier ist eine kurze Übersicht:

Trainings-API MirroredStrategy TPUS-Strategie MultiWorkerMirroredStrategy CentralStorageStrategy ParameterServerStrategy
Keras API Unterstützt Unterstützt Experimentelle Unterstützung Experimentelle Unterstützung Unterstützte geplante Post 2.3
Benutzerdefinierte Trainingsschleife Unterstützt Unterstützt Experimentelle Unterstützung Experimentelle Unterstützung Unterstützte geplante Post 2.3
Schätzer-API Eingeschränkter Support Nicht unterstützt Eingeschränkter Support Eingeschränkter Support Eingeschränkter Support

MirroredStrategy

tf.distribute.MirroredStrategy unterstützt synchrones verteiltes Training auf mehreren GPUs auf einem Computer. Es wird ein Replikat pro GPU-Gerät erstellt. Jede Variable im Modell wird über alle Replikate gespiegelt. Zusammen bilden diese Variablen eine einzige konzeptionelle Variable namens MirroredVariable . Diese Variablen werden durch Anwenden identischer Aktualisierungen miteinander synchronisiert.

Effiziente All-Reduce-Algorithmen werden verwendet, um die variablen Aktualisierungen zwischen den Geräten zu kommunizieren. Reduzieren Sie die Aggregattensoren auf allen Geräten, indem Sie sie addieren, und stellen Sie sie auf jedem Gerät zur Verfügung. Es ist ein fusioniertes Algorithmus, der sehr effizient ist und den Aufwand für die Synchronisation erheblich reduzieren. Abhängig von der Art der Kommunikation zwischen Geräten stehen viele All-Reduce-Algorithmen und -Implementierungen zur Verfügung. Standardmäßig wird NVIDIA NCCL als All-Reduce-Implementierung verwendet. Sie können aus einigen anderen Optionen auswählen oder Ihre eigenen schreiben.

Hier ist die einfachste Möglichkeit, MirroredStrategy erstellen:

mirrored_strategy = tf.distribute.MirroredStrategy()
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)

Dadurch wird eine MirroredStrategy Instanz erstellt, die alle für TensorFlow sichtbaren GPUs verwendet und NCCL als geräteübergreifende Kommunikation verwendet.

Wenn Sie nur einige der GPUs auf Ihrem Computer verwenden möchten, können Sie dies folgendermaßen tun:

mirrored_strategy = tf.distribute.MirroredStrategy(devices=["/gpu:0", "/gpu:1"])
WARNING:tensorflow:Some requested devices in `tf.distribute.Strategy` are not visible to TensorFlow: /job:localhost/replica:0/task:0/device:GPU:0,/job:localhost/replica:0/task:0/device:GPU:1
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1')

Wenn Sie die geräteübergreifende Kommunikation überschreiben möchten, können Sie dies mit dem Argument cross_device_ops tun, indem cross_device_ops eine Instanz von tf.distribute.CrossDeviceOps . Derzeit sind tf.distribute.HierarchicalCopyAllReduce und tf.distribute.ReductionToOneDevice zwei andere Optionen als tf.distribute.NcclAllReduce (Standardeinstellung).

mirrored_strategy = tf.distribute.MirroredStrategy(
    cross_device_ops=tf.distribute.HierarchicalCopyAllReduce())
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)

TPUS-Strategie

tf.distribute.TPUStrategy können Sie Ihr TensorFlow-Training für Tensor Processing Units (TPUs) durchführen. TPUs sind Googles spezialisierte ASICs, mit denen die Arbeitslast beim maschinellen Lernen erheblich beschleunigt werden soll. Sie sind in Google Colab, der TensorFlow Research Cloud und der Cloud TPU verfügbar.

In Bezug auf die verteilte Trainingsarchitektur ist TPUStrategy dieselbe MirroredStrategy - sie implementiert synchrones verteiltes Training. TPUs bieten ihre eigene Implementierung effizienter All- TPUStrategy und anderer kollektiver Operationen über mehrere TPU-Kerne hinweg, die in TPUStrategy .

So würden Sie TPUStrategy instanziieren:

cluster_resolver = tf.distribute.cluster_resolver.TPUClusterResolver(
    tpu=tpu_address)
tf.config.experimental_connect_to_cluster(cluster_resolver)
tf.tpu.experimental.initialize_tpu_system(cluster_resolver)
tpu_strategy = tf.distribute.TPUStrategy(cluster_resolver)

Die TPUClusterResolver Instanz hilft beim Auffinden der TPUs. In Colab müssen Sie keine Argumente dafür angeben.

Wenn Sie dies für Cloud-TPUs verwenden möchten:

  • Sie müssen den Namen Ihrer TPU-Ressource im Argument tpu .
  • Sie müssen das TPU-System explizit zu Beginn des Programms initialisieren. Dies ist erforderlich, bevor TPUs für die Berechnung verwendet werden können. Durch die Initialisierung des TPU-Systems wird auch der TPU-Speicher gelöscht. Daher ist es wichtig, diesen Schritt zuerst auszuführen, um einen Statusverlust zu vermeiden.

MultiWorkerMirroredStrategy

tf.distribute.experimental.MultiWorkerMirroredStrategy ist MirroredStrategy sehr ähnlich. Es implementiert synchron verteilte Schulungen für mehrere Mitarbeiter mit jeweils möglicherweise mehreren GPUs. Ähnlich wie bei MirroredStrategy werden Kopien aller Variablen im Modell auf jedem Gerät für alle Worker erstellt.

Es verwendet CollectiveOps als Multi-Worker-All-Reduce-Kommunikationsmethode, mit der Variablen synchron gehalten werden. Eine kollektive Operation ist eine einzelne Operation im TensorFlow-Diagramm, mit der automatisch ein All-Reduction-Algorithmus in der TensorFlow-Laufzeit je nach Hardware, Netzwerktopologie und Tensorgröße ausgewählt werden kann.

Außerdem werden zusätzliche Leistungsoptimierungen implementiert. Zum Beispiel enthält es eine statische Optimierung, die mehrere Allreduktionen bei kleinen Tensoren in weniger Allreduktionen bei größeren Tensoren umwandelt. Darüber hinaus verfügt es über eine Plugin-Architektur, sodass Sie in Zukunft Algorithmen einstecken können, die besser auf Ihre Hardware abgestimmt sind. Beachten Sie, dass kollektive Operationen auch andere kollektive Operationen wie Broadcast und All-Gather implementieren.

Hier ist die einfachste Methode zum Erstellen von MultiWorkerMirroredStrategy :

multiworker_strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy()
WARNING:tensorflow:Collective ops is not configured at program startup. Some performance features may not be enabled.
INFO:tensorflow:Using MirroredStrategy with devices ('/device:GPU:0',)
INFO:tensorflow:Single-worker MultiWorkerMirroredStrategy with local_devices = ('/device:GPU:0',), communication = CollectiveCommunication.AUTO

MultiWorkerMirroredStrategy können Sie derzeit zwischen zwei verschiedenen Implementierungen von kollektiven MultiWorkerMirroredStrategy wählen. CollectiveCommunication.RING implementiert ringbasierte Kollektive unter Verwendung von gRPC als Kommunikationsschicht. CollectiveCommunication.NCCL verwendet Nvidias NCCL , um Kollektive zu implementieren. CollectiveCommunication.AUTO die Auswahl auf die Laufzeit. Die beste Wahl für die kollektive Implementierung hängt von der Anzahl und Art der GPUs sowie der Netzwerkverbindung im Cluster ab. Sie können sie folgendermaßen angeben:

multiworker_strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy(
    tf.distribute.experimental.CollectiveCommunication.NCCL)
WARNING:tensorflow:Collective ops is not configured at program startup. Some performance features may not be enabled.
INFO:tensorflow:Using MirroredStrategy with devices ('/device:GPU:0',)
INFO:tensorflow:Single-worker MultiWorkerMirroredStrategy with local_devices = ('/device:GPU:0',), communication = CollectiveCommunication.NCCL

Einer der Hauptunterschiede, um das Multi-Worker-Training im Vergleich zum Multi-GPU-Training in Gang zu bringen, ist das Multi-Worker-Setup. Die Umgebungsvariable TF_CONFIG ist die Standardmethode in TensorFlow, um die Clusterkonfiguration für jeden Worker anzugeben, der Teil des Clusters ist. Weitere Informationen zum Einrichten von TF_CONFIG .

ParameterServerStrategy

Das Parameterserver-Training ist eine gängige datenparallele Methode, um das Modelltraining auf mehreren Computern zu skalieren. Ein Parameterserver-Trainingscluster besteht aus Arbeitern und Parameterservern. Variablen werden auf Parameterservern erstellt und von den Mitarbeitern in jedem Schritt gelesen und aktualisiert. Weitere Informationen finden Sie im Tutorial zum Parameterserver-Training .

Das TensorFlow 2-Parameterserver-Training verwendet eine auf Zentralkoordinatoren basierende Architektur über die Klasse tf.distribute.experimental.coordinator.ClusterCoordinator .

In dieser Implementierung der worker und parameter server - tf.distribute.Server parameter server - Tasks ausführen tf.distribute.Server s , die für die Aufgaben des Koordinators hören. Der Koordinator erstellt Ressourcen, sendet Schulungsaufgaben, schreibt Prüfpunkte und behandelt Aufgabenfehler.

In der auf dem Koordinator ausgeführten Programmierung verwenden Sie ein ParameterServerStrategy Objekt, um einen Schulungsschritt zu definieren, und verwenden einen ClusterCoordinator , um Schulungsschritte an Remote-Mitarbeiter zu ClusterCoordinator . Hier ist der einfachste Weg, sie zu erstellen:

strategy = tf.distribute.experimental.ParameterServerStrategy(
    tf.distribute.cluster_resolver.TFConfigClusterResolver(),
    variable_partitioner=variable_partitioner)
coordinator = tf.distribute.experimental.coordinator.ClusterCoordinator(
    strategy)

Beachten Sie, dass Sie die Umgebungsvariable TF_CONFIG konfigurieren müssen, wenn Sie TFConfigClusterResolver . Es ähnelt TF_CONFIG in MultiWorkerMirroredStrategy , weist jedoch zusätzliche Einschränkungen auf.

In TF 1 ist ParameterServerStrategy nur mit einem Schätzer über tf.compat.v1.distribute.experimental.ParameterServerStrategy Symbol tf.compat.v1.distribute.experimental.ParameterServerStrategy verfügbar.

CentralStorageStrategy

tf.distribute.experimental.CentralStorageStrategy führt auch synchrones Training durch. Variablen werden nicht gespiegelt, sondern auf der CPU platziert und Vorgänge werden auf alle lokalen GPUs repliziert. Wenn nur eine GPU vorhanden ist, werden alle Variablen und Operationen auf dieser GPU platziert.

Erstellen Sie eine Instanz von CentralStorageStrategy mit:

central_storage_strategy = tf.distribute.experimental.CentralStorageStrategy()
INFO:tensorflow:ParameterServerStrategy (CentralStorageStrategy if you are using a single machine) with compute_devices = ['/job:localhost/replica:0/task:0/device:GPU:0'], variable_device = '/job:localhost/replica:0/task:0/device:GPU:0'

Dadurch wird eine CentralStorageStrategy Instanz erstellt, die alle sichtbaren GPUs und die CPU verwendet. Aktualisierungen von Variablen in Replikaten werden aggregiert, bevor sie auf Variablen angewendet werden.

Andere Strategien

Zusätzlich zu den oben genannten Strategien gibt es zwei weitere Strategien, die für das Prototyping und Debuggen bei Verwendung von tf.distribute APIs tf.distribute .

Standardstrategie

Die Standardstrategie ist eine Verteilungsstrategie, die vorhanden ist, wenn keine explizite Verteilungsstrategie im Geltungsbereich liegt. Es implementiert die Schnittstelle tf.distribute.Strategy , ist jedoch ein Pass-Through und bietet keine tatsächliche Verteilung. Zum Beispiel ruft strategy.run(fn) einfach fn . Mit dieser Strategie geschriebener Code sollte sich genauso verhalten wie Code, der ohne Strategie geschrieben wurde. Sie können sich das als "No-Op" -Strategie vorstellen.

Die Standardstrategie ist ein Singleton - und man kann keine weiteren Instanzen davon erstellen. Es kann mit tf.distribute.get_strategy() außerhalb des Bereichs einer expliziten Strategie abgerufen werden tf.distribute.get_strategy() dieselbe API, mit der die aktuelle Strategie innerhalb des Bereichs einer expliziten Strategie abgerufen werden kann).

default_strategy = tf.distribute.get_strategy()

Diese Strategie dient zwei Hauptzwecken:

  • Es ermöglicht das bedingungslose Schreiben von verteilungsbewusstem Bibliothekscode. In tf.optimizer s beispielsweise tf.distribute.get_strategy() und diese Strategie zum Reduzieren von Verläufen verwenden. Es wird immer ein Strategieobjekt zurückgegeben, für das wir die Reduktions-API aufrufen können.
# In optimizer or other library code
# Get currently active strategy
strategy = tf.distribute.get_strategy()
strategy.reduce("SUM", 1., axis=None)  # reduce some values
1.0
  • Ähnlich wie Bibliothekscode können damit Endbenutzerprogramme für die Arbeit mit und ohne Verteilungsstrategie geschrieben werden, ohne dass eine bedingte Logik erforderlich ist. Ein Beispielcode-Snippet, das dies veranschaulicht:
if tf.config.list_physical_devices('gpu'):
  strategy = tf.distribute.MirroredStrategy()
else:  # use default strategy
  strategy = tf.distribute.get_strategy() 

with strategy.scope():
  # do something interesting
  print(tf.Variable(1.))
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=1.0>

OneDeviceStrategy

tf.distribute.OneDeviceStrategy ist eine Strategie zum Platzieren aller Variablen und Berechnungen auf einem einzelnen angegebenen Gerät.

strategy = tf.distribute.OneDeviceStrategy(device="/gpu:0")

Diese Strategie unterscheidet sich in vielerlei Hinsicht von der Standardstrategie. In der Standardstrategie bleibt die Logik für die variable Platzierung im Vergleich zur Ausführung von TensorFlow ohne Verteilungsstrategie unverändert. Bei Verwendung von OneDeviceStrategy werden jedoch alle in seinem Bereich erstellten Variablen explizit auf dem angegebenen Gerät platziert. Darüber hinaus werden alle über OneDeviceStrategy.run aufgerufenen Funktionen auch auf dem angegebenen Gerät platziert.

Über diese Strategie verteilte Eingaben werden auf das angegebene Gerät vorab abgerufen. In der Standardstrategie gibt es keine Eingabeverteilung.

Ähnlich wie bei der Standardstrategie kann diese Strategie auch zum Testen Ihres Codes verwendet werden, bevor zu anderen Strategien gewechselt wird, die tatsächlich auf mehrere Geräte / Maschinen verteilt werden. Dadurch wird die Verteilungsstrategie-Maschinerie etwas mehr als die Standardstrategie ausgeführt, jedoch nicht in vollem Umfang wie bei Verwendung von MirroredStrategy oder TPUStrategy usw. Wenn Sie Code möchten, der sich so verhält, als ob keine Strategie vorliegt, verwenden Sie die Standardstrategie.

Bisher haben Sie die verschiedenen verfügbaren Strategien gesehen und wie Sie sie instanziieren können. In den nächsten Abschnitten werden die verschiedenen Möglichkeiten gezeigt, wie Sie sie zur Verteilung Ihres Trainings verwenden können.

Verwenden von tf.distribute.Strategy mit tf.keras.Model.fit

tf.distribute.Strategy ist in tf.keras integriert. tf.keras ist TensorFlows Implementierung der Keras-API-Spezifikation . tf.keras ist eine API auf hoher Ebene zum Erstellen und Trainieren von Modellen. Durch die Integration in das tf.keras Backend haben wir es für Sie nahtlos gemacht, Ihr im Keras-Trainingsframework geschriebenes Training mit model.fit .

Folgendes müssen Sie in Ihrem Code ändern:

  1. Erstellen Sie eine Instanz der entsprechenden tf.distribute.Strategy .
  2. Verschieben Sie die Erstellung von Keras-Modell, Optimierer und Metriken in strategy.scope .

Wir unterstützen alle Arten von Keras-Modellen - sequentiell, funktional und in Unterklassen.

Hier ist ein Codeausschnitt, um dies für ein sehr einfaches Keras-Modell mit einer dichten Ebene zu tun:

mirrored_strategy = tf.distribute.MirroredStrategy()

with mirrored_strategy.scope():
  model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])

model.compile(loss='mse', optimizer='sgd')
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)

In diesem Beispiel wird MirroredStrategy damit Sie dies auf einem Computer mit mehreren GPUs ausführen können. strategy.scope() gibt Keras an, mit welcher Strategie das Training verteilt werden soll. Durch das Erstellen von Modellen / Optimierern / Metriken in diesem Bereich können verteilte Variablen anstelle von regulären Variablen erstellt werden. Sobald dies eingerichtet ist, können Sie Ihr Modell wie gewohnt anpassen. MirroredStrategy kümmert sich darum, das Training des Modells auf den verfügbaren GPUs zu replizieren, Farbverläufe zu aggregieren und vieles mehr.

dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100).batch(10)
model.fit(dataset, epochs=2)
model.evaluate(dataset)
Epoch 1/2
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/data/ops/multi_device_iterator_ops.py:601: get_next_as_optional (from tensorflow.python.data.ops.iterator_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.data.Iterator.get_next_as_optional()` instead.
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
10/10 [==============================] - 0s 2ms/step - loss: 0.2137
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
Epoch 2/2
10/10 [==============================] - 0s 2ms/step - loss: 0.0945
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
10/10 [==============================] - 0s 1ms/step - loss: 0.0587

0.0586698018014431

Hier liefert eintf.data.Dataset das Training und dietf.data.Dataset . Sie können auch Numpy-Arrays verwenden:

import numpy as np
inputs, targets = np.ones((100, 1)), np.ones((100, 1))
model.fit(inputs, targets, epochs=2, batch_size=10)
Epoch 1/2
10/10 [==============================] - 0s 2ms/step - loss: 0.0418
Epoch 2/2
10/10 [==============================] - 0s 2ms/step - loss: 0.0185

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

In beiden Fällen (Datensatz oder Anzahl) wird jeder Stapel der angegebenen Eingabe zu gleichen Teilen auf die mehreren Replikate aufgeteilt. Wenn Sie beispielsweise MirroredStrategy mit 2 GPUs verwenden, wird jeder Stapel der Größe 10 auf die 2 GPUs aufgeteilt, wobei jeder in jedem Schritt 5 Eingabebeispiele erhält. Jede Epoche wird dann schneller trainiert, wenn Sie weitere GPUs hinzufügen. In der Regel möchten Sie Ihre Stapelgröße erhöhen, wenn Sie weitere Beschleuniger hinzufügen, um die zusätzliche Rechenleistung effektiv zu nutzen. Sie müssen auch Ihre Lernrate je nach Modell neu einstellen. Sie können strategy.num_replicas_in_sync , um die Anzahl der Replikate abzurufen.

# Compute global batch size using number of replicas.
BATCH_SIZE_PER_REPLICA = 5
global_batch_size = (BATCH_SIZE_PER_REPLICA *
                     mirrored_strategy.num_replicas_in_sync)
dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100)
dataset = dataset.batch(global_batch_size)

LEARNING_RATES_BY_BATCH_SIZE = {5: 0.1, 10: 0.15}
learning_rate = LEARNING_RATES_BY_BATCH_SIZE[global_batch_size]

Was wird jetzt unterstützt?

Trainings-API MirroredStrategy TPUS-Strategie MultiWorkerMirroredStrategy ParameterServerStrategy CentralStorageStrategy
Keras-APIs Unterstützt Unterstützt Experimentelle Unterstützung Experimentelle Unterstützung Experimentelle Unterstützung

Beispiele und Tutorials

Hier ist eine Liste von Tutorials und Beispielen, die die obige Integration von Keras zu Ende veranschaulichen:

  1. Tutorial zum Trainieren von MNIST mit MirroredStrategy .
  2. Tutorial zum Trainieren von MNIST mit MultiWorkerMirroredStrategy .
  3. Leitfaden zum Training von MNIST mit TPUStrategy .
  4. Tutorial zum Parameterserver-Training in TensorFlow 2 mit ParameterServerStrategy .
  5. TensorFlow Model Garden- Repository mit Sammlungen modernster Modelle, die mit verschiedenen Strategien implementiert wurden.

Verwenden von tf.distribute.Strategy mit benutzerdefinierten Trainingsschleifen

Wie Sie gesehen haben, müssen für die Verwendung von tf.distribute.Strategy mit Keras model.fit nur einige Zeilen Ihres Codes model.fit werden. Mit etwas mehr Aufwand können Sie auch tf.distribute.Strategy mit benutzerdefinierten Trainingsschleifen verwenden.

Wenn Sie mehr Flexibilität und Kontrolle über Ihre Trainingsschleifen benötigen, als dies mit Estimator oder Keras möglich ist, können Sie benutzerdefinierte Trainingsschleifen schreiben. Wenn Sie beispielsweise ein GAN verwenden, möchten Sie möglicherweise in jeder Runde eine andere Anzahl von Generator- oder Diskriminatorschritten ausführen. In ähnlicher Weise eignen sich die übergeordneten Frameworks nicht sehr gut für das Reinforcement Learning-Training.

Die Klassen tf.distribute.Strategy bieten einen Kernsatz von Methoden zur Unterstützung benutzerdefinierter Trainingsschleifen. Die Verwendung dieser Elemente erfordert möglicherweise zunächst eine geringfügige Umstrukturierung des Codes. Sobald dies erledigt ist, sollten Sie in der Lage sein, zwischen GPUs, TPUs und mehreren Computern zu wechseln, indem Sie einfach die Strategieinstanz ändern.

Hier zeigen wir einen kurzen Ausschnitt, der diesen Anwendungsfall für ein einfaches Trainingsbeispiel mit demselben Keras-Modell wie zuvor veranschaulicht.

Erstellen Sie zunächst das Modell und den Optimierer im Rahmen der Strategie. Dadurch wird sichergestellt, dass alle mit dem Modell und dem Optimierer erstellten Variablen gespiegelte Variablen sind.

with mirrored_strategy.scope():
  model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])
  optimizer = tf.keras.optimizers.SGD()

Erstellen Sie als Nächstes das Eingabedatensatz und rufen Sie tf.distribute.Strategy.experimental_distribute_dataset auf, um das Dataset basierend auf der Strategie zu verteilen.

dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100).batch(
    global_batch_size)
dist_dataset = mirrored_strategy.experimental_distribute_dataset(dataset)

Definieren Sie dann einen Schritt des Trainings. Verwenden Sietf.GradientTape , um Verläufe zu berechnen, und Optimierer, um diese Verläufe anzuwenden, um die Variablen unseres Modells zu aktualisieren. Um diesen Trainingsschritt zu verteilen, train_step Sie ihn in eine Funktion train_step und übergeben Sie tf.distrbute.Strategy.run zusammen mit den tf.distrbute.Strategy.run die Sie aus dem dist_dataset erstellten tf.distrbute.Strategy.run an dist_dataset :

loss_object = tf.keras.losses.BinaryCrossentropy(
  from_logits=True,
  reduction=tf.keras.losses.Reduction.NONE)

def compute_loss(labels, predictions):
  per_example_loss = loss_object(labels, predictions)
  return tf.nn.compute_average_loss(per_example_loss, global_batch_size=global_batch_size)

def train_step(inputs):
  features, labels = inputs

  with tf.GradientTape() as tape:
    predictions = model(features, training=True)
    loss = compute_loss(labels, predictions)

  gradients = tape.gradient(loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))
  return loss

@tf.function
def distributed_train_step(dist_inputs):
  per_replica_losses = mirrored_strategy.run(train_step, args=(dist_inputs,))
  return mirrored_strategy.reduce(tf.distribute.ReduceOp.SUM, per_replica_losses,
                         axis=None)

Ein paar andere Dinge, die im obigen Code zu beachten sind:

  1. Es wurde tf.nn.compute_average_loss , um den Verlust zu berechnen. tf.nn.compute_average_loss summiert den Verlust pro Beispiel und dividiert die Summe durch die global_batch_size. Dies ist wichtig, da die Gradienten später, nachdem sie für jedes Replikat berechnet wurden, durch Summieren über die Replikate hinweg aggregiert werden.
  2. Es verwendet , um die tf.distribute.Strategy.reduce API die Ergebnisse zurück von aggregieren tf.distribute.Strategy.run . tf.distribute.Strategy.run gibt Ergebnisse von jedem lokalen Replikat in der Strategie zurück, und es gibt mehrere Möglichkeiten, dieses Ergebnis zu verwenden. Sie können sie reduce , um einen aggregierten Wert zu erhalten. Sie können auch tf.distribute.Strategy.experimental_local_results , um die Liste der im Ergebnis enthaltenen Werte tf.distribute.Strategy.experimental_local_results , einen pro lokalem Replikat.
  3. Wenn apply_gradients innerhalb eines Verteilungsstrategiebereichs apply_gradients wird, wird sein Verhalten geändert. Insbesondere wird vor dem Anwenden von Verläufen auf jede parallele Instanz während des synchronen Trainings eine Summe aller Replikate der Verläufe durchgeführt.

dist_dataset Sie den Trainingsschritt definiert haben, können wir dist_dataset und das Training in einer Schleife ausführen:

for dist_inputs in dist_dataset:
  print(distributed_train_step(dist_inputs))
tf.Tensor(0.18279998, shape=(), dtype=float32)
tf.Tensor(0.18224256, shape=(), dtype=float32)
tf.Tensor(0.18168819, shape=(), dtype=float32)
tf.Tensor(0.1811369, shape=(), dtype=float32)
tf.Tensor(0.18058868, shape=(), dtype=float32)
tf.Tensor(0.18004347, shape=(), dtype=float32)
tf.Tensor(0.17950125, shape=(), dtype=float32)
tf.Tensor(0.178962, shape=(), dtype=float32)
tf.Tensor(0.17842571, shape=(), dtype=float32)
tf.Tensor(0.17789237, shape=(), dtype=float32)
tf.Tensor(0.17736195, shape=(), dtype=float32)
tf.Tensor(0.17683437, shape=(), dtype=float32)
tf.Tensor(0.17630969, shape=(), dtype=float32)
tf.Tensor(0.17578785, shape=(), dtype=float32)
tf.Tensor(0.17526883, shape=(), dtype=float32)
tf.Tensor(0.17475258, shape=(), dtype=float32)
tf.Tensor(0.17423911, shape=(), dtype=float32)
tf.Tensor(0.17372845, shape=(), dtype=float32)
tf.Tensor(0.17322046, shape=(), dtype=float32)
tf.Tensor(0.1727152, shape=(), dtype=float32)

Im obigen Beispiel haben Sie das dist_dataset , um Eingaben für Ihr Training bereitzustellen. Wir stellen auch das tf.distribute.Strategy.make_experimental_numpy_dataset zur Verfügung, um numpy-Eingaben zu unterstützen. Mit dieser API können Sie ein Dataset erstellen, bevor Sie tf.distribute.Strategy.experimental_distribute_dataset aufrufen.

Eine andere Möglichkeit, Ihre Daten zu iterieren, besteht darin, explizit Iteratoren zu verwenden. Möglicherweise möchten Sie dies tun, wenn Sie für eine bestimmte Anzahl von Schritten ausgeführt werden möchten, anstatt über das gesamte Dataset zu iterieren. Die obige Iteration würde jetzt modifiziert werden , um zunächst einen Iterator zu erstellen und dann explizit aufrufen next sie auf, die Eingangsdaten zu erhalten.

iterator = iter(dist_dataset)
for _ in range(10):
  print(distributed_train_step(next(iterator)))
tf.Tensor(0.17221266, shape=(), dtype=float32)
tf.Tensor(0.17171277, shape=(), dtype=float32)
tf.Tensor(0.17121558, shape=(), dtype=float32)
tf.Tensor(0.17072096, shape=(), dtype=float32)
tf.Tensor(0.17022902, shape=(), dtype=float32)
tf.Tensor(0.16973962, shape=(), dtype=float32)
tf.Tensor(0.16925281, shape=(), dtype=float32)
tf.Tensor(0.1687686, shape=(), dtype=float32)
tf.Tensor(0.1682869, shape=(), dtype=float32)
tf.Tensor(0.16780771, shape=(), dtype=float32)

Dies deckt den einfachsten Fall der Verwendung der API tf.distribute.Strategy zum Verteilen benutzerdefinierter Trainingsschleifen ab.

Was wird jetzt unterstützt?

Trainings-API MirroredStrategy TPUS-Strategie MultiWorkerMirroredStrategy ParameterServerStrategy CentralStorageStrategy
Benutzerdefinierte Trainingsschleife Unterstützt Unterstützt Experimentelle Unterstützung Experimentelle Unterstützung Experimentelle Unterstützung

Beispiele und Tutorials

Hier einige Beispiele für die Verwendung der Verteilungsstrategie mit benutzerdefinierten Trainingsschleifen:

  1. Tutorial zum Trainieren von MNIST mit MirroredStrategy .
  2. Leitfaden zum Training von MNIST mit TPUStrategy .
  3. TensorFlow Model Garden- Repository mit Sammlungen modernster Modelle, die mit verschiedenen Strategien implementiert wurden.

Andere Themen

Dieser Abschnitt behandelt einige Themen, die für mehrere Anwendungsfälle relevant sind.

Einrichten der Umgebungsvariablen TF_CONFIG

Wie bereits erwähnt, müssen Sie für die TF_CONFIG Umgebungsvariable TF_CONFIG für jede in Ihrem Cluster ausgeführte Binärdatei TF_CONFIG . Die Umgebungsvariable TF_CONFIG ist eine JSON-Zeichenfolge, die angibt, welche Aufgaben einen Cluster bilden, ihre Adressen und die Rolle jeder Aufgabe im Cluster. Das Tensorflow / Ökosystem- Repo bietet eine Kubernetes-Vorlage, in der TF_CONFIG für Ihre Trainingsaufgaben festgelegt wird.

TF_CONFIG besteht aus zwei Komponenten: Cluster und Task. Der Cluster bietet Informationen zum Schulungscluster, bei dem es sich um ein Diktat handelt, das aus verschiedenen Arten von Jobs besteht, z. B. Arbeiter. In der Schulung für mehrere Mitarbeiter übernimmt normalerweise ein Mitarbeiter etwas mehr Verantwortung wie das Speichern des Prüfpunkts und das Schreiben einer Zusammenfassungsdatei für TensorBoard, zusätzlich zu dem, was ein regulärer Mitarbeiter tut. Ein solcher Arbeiter wird als "Chefarbeiter" bezeichnet, und es ist üblich, dass der Arbeiter mit dem Index 0 zum Chefarbeiter ernannt wird (tatsächlich wird auf diese Weise tf.distribute.Strategy implementiert). Aufgabe hingegen liefert Informationen über die aktuelle Aufgabe. Der erste Komponentencluster ist für alle Worker gleich, und die zweite Komponentenaufgabe ist für jeden Worker unterschiedlich und gibt den Typ und den Index dieses Workers an.

Ein Beispiel für TF_CONFIG ist:

os.environ["TF_CONFIG"] = json.dumps({
    "cluster": {
        "worker": ["host1:port", "host2:port", "host3:port"],
        "ps": ["host4:port", "host5:port"]
    },
   "task": {"type": "worker", "index": 1}
})

Diese TF_CONFIG gibt an, dass der Cluster drei Worker und zwei ps-Tasks zusammen mit ihren Hosts und Ports enthält. Der Teil "Aufgabe" gibt an, dass die Rolle der aktuellen Aufgabe im Cluster Arbeiter 1 (der zweite Arbeiter) ist. Gültige Rollen in einem Cluster sind "Chef", "Arbeiter", "PS" und "Bewerter". Es sollte keinen "ps" tf.distribute.experimental.ParameterServerStrategy außer wenn tf.distribute.experimental.ParameterServerStrategy .

Was kommt als nächstes?

tf.distribute.Strategy befindet sich in der Entwicklung. Probieren Sie es aus und geben Sie Ihr Feedback mithilfe von GitHub-Problemen .