Verteiltes Training

Auf dieser Seite wird beschrieben, wie Sie verteilte Trainingsjobs auf Vertex AI ausführen.

Codeanforderungen

Verwenden Sie ein ML-Framework, das verteiltes Training unterstützt. In Ihrem Trainingscode können Sie die Umgebungsvariablen CLUSTER_SPEC oder TF_CONFIG verwenden, um auf bestimmte Teile Ihres Trainingsclusters zu verweisen.

Struktur des Trainingsclusters

Wenn Sie einen verteilten Trainingsjob mit Vertex AI ausführen, legen Sie mehrere Maschinen (Knoten) in einem Trainingscluster fest. Der Trainingsdienst weist die Ressourcen für die von Ihnen angegebenen Maschinentypen zu. Der aktuell auf einem Knoten ausgeführte Job wird als Replikat bezeichnet. Eine Gruppe von Replikaten mit derselben Konfiguration wird als Worker-Pool bezeichnet.

Jedem Replikat im Trainingscluster wird eine einzelne Rolle oder Aufgabe im verteilten Training zugewiesen. Beispiel:

  • Primäres Replikat: Genau ein Replikat wird als primäres Replikat festgelegt. Es verwaltet die anderen Replikate und meldet den Gesamtstatus des Jobs.

  • Worker: Es können ein oder mehrere Replikate als Worker festgelegt werden. Diese Replikate übernehmen jeweils einen Teil der Arbeit, wie Sie dies in der Jobkonfiguration festgelegt haben.

  • Parameterserver: Wenn Ihr ML-Framework unterstützt wird, können ein oder mehrere Replikate als Parameterserver festgelegt werden. Diese Replikate speichern Modellparameter und koordinieren den gemeinsamen Modellstatus unter den Workern.

  • Evaluator(s):: Wenn Ihr ML-Framework unterstützt wird, können ein oder mehrere Replikate als Evaluators bezeichnet werden. Es ist möglich, diese Replikate zur Bewertung Ihres Modells zu verwenden. Wenn Sie TensorFlow verwenden, wird im Allgemeinen davon ausgegangen, dass Sie nicht mehr als einen Evaluator verwenden.

Verteilten Trainingsjob konfigurieren

Sie können jeden benutzerdefinierten Trainingsjob als verteilten Trainingsjob konfigurieren, indem Sie mehrere Worker-Pools definieren. Sie können verteiltes Training auch in einer Trainingspipeline oder einem Hyperparameter-Abstimmungsjob ausführen.

Zum Konfigurieren eines verteilten Trainingsjobs definieren Sie Ihre Liste der Worker-Pools (workerPoolSpecs[]) und legen Sie dabei WorkerPoolSpec für jeden Aufgabentyp fest:

Position in workerPoolSpecs[] Im Cluster ausgeführte Aufgabe
Erste (workerPoolSpecs[0]) Primary, chief, scheduler oder "master"
Zweite (workerPoolSpecs[1]) Secondary, replicas, workers
Dritte (workerPoolSpecs[2]) Parameterserver, Reduction Server
Vierte (workerPoolSpecs[3]) Evaluators

Sie müssen ein primäres Replikat angeben, das die Arbeit aller anderen Replikate koordiniert. Verwenden Sie die erste Worker-Pool-Spezifikation nur für das primäre Replikat und legen Sie deren replicaCount auf 1 fest:

{
  "workerPoolSpecs": [
     // `WorkerPoolSpec` for worker pool 0, primary replica, required
     {
       "machineSpec": {...},
       "replicaCount": 1,
       "diskSpec": {...},
       ...
     },
     // `WorkerPoolSpec` for worker pool 1, optional
     {},
     // `WorkerPoolSpec` for worker pool 2, optional
     {},
     // `WorkerPoolSpec` for worker pool 3, optional
     {}
   ]
   ...
}

Zusätzliche Worker-Pools angeben

Je nach ML-Framework können Sie zusätzliche Worker-Pools für andere Zwecke angeben. Wenn Sie beispielsweise TensorFlow verwenden, können Sie Worker-Pools angeben, um Worker-Replikate, Parameterserver-Replikate und Bewertungsreplikate zu konfigurieren.

Die Reihenfolge der Worker-Pools, die Sie in der Liste workerPoolSpecs[] angeben, bestimmt den Typ des Worker-Pools. Legen Sie leere Werte für Worker-Pools fest, die Sie nicht verwenden möchten, damit Sie sie in der Liste workerPoolSpecs[] überspringen können, um Worker-Pools anzugeben, die Sie verwenden möchten. Beispiel:

Wenn Sie einen Job angeben möchten, der nur ein primäres Replikat und einen Parameterserver-Worker-Pool enthält, müssen Sie für den Worker-Pool einen leeren Wert festlegen:

{
  "workerPoolSpecs": [
     // `WorkerPoolSpec` for worker pool 0, required
     {
       "machineSpec": {...},
       "replicaCount": 1,
       "diskSpec": {...},
       ...
     },
     // `WorkerPoolSpec` for worker pool 1, optional
     {},
     // `WorkerPoolSpec` for worker pool 2, optional
     {
       "machineSpec": {...},
       "replicaCount": 1,
       "diskSpec": {...},
       ...
     },
     // `WorkerPoolSpec` for worker pool 3, optional
     {}
   ]
   ...
}

Trainingszeit mit Reduction Server reduzieren

Wenn Sie ein großes ML-Modell mit mehreren Knoten trainieren, kann die Kommunikation von Gradienten zwischen Knoten zu einer erheblichen Latenz führen. Reduction Server ist ein All-Reduce-Algorithmus, der den Durchsatz erhöhen und die Latenz für verteiltes Training reduzieren kann. Vertex AI stellt Reduction Server in einem Docker-Container-Image zur Verfügung, das Sie während des verteilten Trainings für einen Ihrer Worker-Pools verwenden können.

Informationen zur Funktionsweise von Reduction Server finden Sie unter Schnelleres verteiltes GPU-Training mit Reduction Server auf Vertex AI.

Vorbereitung

Sie können Reduction Server verwenden, wenn Sie die folgenden Anforderungen erfüllen:

  • Sie führen verteiltes Training mit GPU-Workern durch.

  • Der Trainingscode verwendet TensorFlow oder PyTorch und ist für das datenparallele Training mit mehreren Hosts und GPUs konfiguriert. Dabei wird NCCL-All-Reduce verwendet. (Sie können auch andere ML-Frameworks verwenden, die NCCL verwenden.)

  • Die Container, die auf Ihrem primären Knoten (workerPoolSpecs[0]) und Ihren Workern (workerPoolSpecs[1]) ausgeführt werden, unterstützen Reduction Server. Jeder Container ist einer der folgenden:

    • Ein vordefinierter TensorFlow-Trainingscontainer ab Version 2.3.

    • Ein vordefinierter Pytorch-Trainingscontainer ab Version 1.4.

    • Ein benutzerdefinierter Container mit NCCL 2.7 oder höher und installiertem Paket google-reduction-server. Sie können dieses Paket auf einem benutzerdefinierten Container-Image installieren. Dazu fügen Sie Ihrem Dockerfile die folgende Zeile hinzu:

      RUN echo "deb https://packages.cloud.google.com/apt google-fast-socket main" | tee /etc/apt/sources.list.d/google-fast-socket.list && \
          curl -s -L https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
          apt update && apt install -y google-reduction-server
      

Mit Reduction Server trainieren

Wenn Sie Reduction Server verwenden, gehen Sie beim Erstellen einer benutzerdefinierten Trainingsressource so vor:

  1. Geben Sie im Feld containerSpec.imageUri des dritten Worker-Pools (workerPoolSpecs[2]) einen der folgenden URIs an:

    • us-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest
    • europe-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest
    • asia-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest

    Wenn Sie den multiregionalen Standort auswählen, der dem Ort des benutzerdefinierten Trainings am nächsten ist, kann die Latenz verringert werden.

  2. Achten Sie bei der Auswahl des Maschinentyps und der Anzahl der Knoten für den dritten Worker-Pool darauf, dass die gesamte Netzwerkbandbreite des dritten Worker-Pools mindestens der gesamten Netzwerkbandbreite des ersten und des zweiten Worker-Pools entspricht.

    Informationen zur maximal verfügbaren Bandbreite jedes Knotens im zweiten Worker-Pool finden Sie unter Netzwerkbandbreite und GPUs.

    Sie verwenden keine GPUs für Reduction Server-Knoten. Informationen zur maximalen verfügbaren Bandbreite jedes Knotens im dritten Worker-Pool finden Sie in der Spalte "Maximale Bandbreite für ausgehenden Traffic (Gbit/s)" unter Maschinenfamilie für allgemeine Zwecke.

    Wenn Sie beispielsweise den ersten und zweiten Worker-Pool für die Verwendung von 5 n1-highmem-96-Knoten mit jeweils 8 NVIDIA_TESLA_V100-GPUs konfigurieren, hat jeder Knoten eine maximale verfügbare Bandbreite von 100 Gbit/s für eine Gesamtbandbreite von 500 Gbit/s. Zum Erreichen dieser Bandbreite im dritten Worker-Pool können Sie 16 n1-highcpu-16-Knoten mit jeweils einer maximalen Bandbreite von 32 Gbit/s und einer Gesamtbandbreite von 512 Gbit/s verwenden.

    Wir empfehlen die Verwendung des Maschinentyps n1-highcpu-16 für Reduction Server-Knoten, da dieser Maschinentyp eine relativ hohe Bandbreite für seine Ressourcen bietet.

Der folgende Befehl zeigt ein Beispiel für das Erstellen einer CustomJob-Ressource, die Reduction Server verwendet:

gcloud ai custom-jobs create \
  --region=LOCATION \
  --display-name=JOB_NAME \
  --worker-pool-spec=machine-type=n1-highmem-96,replica-count=1,accelerator-type=NVIDIA_TESLA_V100,accelerator-count=8,container-image-uri=CUSTOM_CONTAINER_IMAGE_URI \
  --worker-pool-spec=machine-type=n1-highmem-96,replica-count=4,accelerator-type=NVIDIA_TESLA_V100,accelerator-count=8,container-image-uri=CUSTOM_CONTAINER_IMAGE_URI \
  --worker-pool-spec=machine-type=n1-highcpu-16,replica-count=16,container-image-uri=us-docker.pkg.dev/vertex-ai-restricted/training/reductionserver:latest

Weitere Informationen finden Sie im Leitfaden zum Erstellen eines CustomJob.

Best Practices für das Training mit Reduction Server

Maschinentyp und Anzahl

Im Training mit Reduction Server muss jeder Worker eine Verbindung zu allen Reducer-Hosts herstellen. Verwenden Sie einen Maschinentyp mit der höchsten Netzwerkbandbreite für Ihren Reducer-Host, um die Anzahl der Verbindungen auf dem Worker-Host zu minimieren.

Eine gute Wahl für Reducer-Hosts ist eine allgemeine N1/N2-VM mit mindestens 16 vCPUs, die eine Bandbreite für ausgehenden Traffic von 32 Gbit/s bietet, beispielsweise n1-highcpu-16 und n2-highcpu-16. Die Tier 1-VM-Bandbreite für N1/N2-VMs erhöht die maximale Bandbreite für ausgehenden Traffic von 50 Gbit/s bis 100 Gbit/s. Dies ist eine gute Wahl für Reducer-VM-Knoten.

Die Gesamtbandbreite für ausgehenden Traffic von Workern und Reducern sollte identisch sein. Wenn Sie beispielsweise 8 a2-megagpu-16g-VMs als Worker verwenden, sollten Sie mindestens 25 n1-highcpu-16-VMs als Reducer verwenden.

`(8 worker VMs * 100 Gbps) / 32 Gbps egress = 25 reducer VMs`.

Kleine Nachrichten im Batch zusammenfassen

Der Reduction Server funktioniert am besten, wenn die zu aggregierenden Nachrichten ausreichend groß sind. Die meisten ML-Frameworks bieten bereits Techniken mit unterschiedlichen Terminologien für das Batching kleiner Gradiententensoren, bevor der All-Reduce-Vorgang durchgeführt wird.

Horovod

Horovod unterstützt Tensor Fusion, um kleine Tensoren für den All-Reduce-Vorgang in Batches aufzuteilen. Tensoren werden in einem Fusionspuffer gefüllt, bis der Puffer vollständig gefüllt ist und der All-Reduce-Vorgang für den Zwischenspeicher ausgeführt wird. Sie können die Größe des Fusionspuffers anpassen, indem Sie die Umgebungsvariable HOROVOD_FUSION_THRESHOLD festlegen.

Der empfohlene Wert für die Umgebungsvariable HOROVOD_FUSION_THRESHOLD ist mindestens 128 MB. In diesem Fall setzen Sie die Umgebungsvariable HOROVOD_FUSION_THRESHOLD auf 134217728 (128 * 1024 * 1024).

PyTorch

PyTorch DistributedDataParallel unterstützt Batchnachrichten als „Gradient Bucketing“. Legen Sie den Parameter bucket_cap_mb im Konstruktor DistributedDataParallel fest, um die Größe Ihrer Batch-Buckets zu steuern. Die Standardgröße ist 25 MB.

BEST PRACTICE: Der empfohlene Wert von „bucket_cap_mb“ ist 64 (64 MB).

Umgebungsvariablen für Ihren Cluster

Vertex AI fügt für jedes Replikat Daten in eine CLUSTER_SPEC-Umgebungsvariable ein, die beschreibt, wie der allgemeine Cluster eingerichtet ist. Wie TF_CONFIG von TensorFlow beschreibt CLUSTER_SPEC jedes Replikat im Cluster, einschließlich Index und Rolle (primäres Replikat, Worker, Parameterserver oder Evaluator).

Wenn Sie ein verteiltes Training mit TensorFlow ausführen, wird TF_CONFIG für das Erstellen von tf.train.ClusterSpec geparst. Ähnliches gilt für die Ausführung des verteilten Trainings mit anderen ML-Frameworks. CLUSTER_SPEC muss geparst werden, um Umgebungsvariablen oder Einstellungen festzulegen, die für das Framework erforderlich sind.

Format von CLUSTER_SPEC

Die Umgebungsvariable CLUSTER_SPEC ist ein JSON-String mit dem folgenden Format:

Schlüssel Beschreibung
"cluster"

Die Clusterbeschreibung für den benutzerdefinierten Container. Wie bei TF_CONFIG wird dieses Objekt als TensorFlow-Clusterspezifikation formatiert und kann an den Konstruktor von tf.train.ClusterSpec übergeben werden.

Die Clusterbeschreibung enthält eine Liste der Replikatnamen für jeden von Ihnen angegebenen Worker-Pool.

"workerpool0" Alle verteilten Trainingsjobs haben im ersten Worker-Pool ein primäres Replikat.
"workerpool1" Dieser Worker-Pool enthält Worker-Replikate, falls Sie diese beim Erstellen des Jobs angegeben haben.
"workerpool2" Dieser Worker-Pool enthält Parameterserver, wenn Sie diese beim Erstellen Ihres Jobs angegeben haben.
"workerpool3" Dieser Worker-Pool enthält Evaluators, wenn Sie diese beim Erstellen des Jobs angegeben haben.
"environment" Der String cloud.
"task" Beschreibt die Aufgabe des jeweiligen Knotens, auf dem Ihr Code läuft. Sie können diese Informationen verwenden, um Code für bestimmte Worker in einem verteilten Job zu schreiben. Dieser Eintrag ist ein Wörterbuch mit folgenden Schlüsseln:
"type" Der Typ des Worker-Pools, in dem diese Aufgabe ausgeführt wird. Beispielsweise bezieht sich "workerpool0" auf das primäre Replikat.
"index"

Der nullbasierte Index der Aufgabe. Wenn Ihr Trainingsjob beispielsweise zwei Worker enthält, wird dieser Wert für den einen auf 0 und für den anderen auf 1 festgelegt.

"trial" Die Kennzeichnung des gerade ausgeführten Hyperparameter-Abstimmungstests. Wenn Sie die Hyperparameter-Abstimmung für Ihren Job konfigurieren, legen Sie eine Reihe von Tests fest, die trainiert werden sollen. Mit diesem Wert können Sie zwischen den verschiedenen Tests unterscheiden, die in Ihrem Code ausgeführt werden. Die Kennzeichnung ist ein Stringwert, der die Testnummer enthält, beginnend mit Test 1.
job

Der CustomJobSpec, den Sie zum Erstellen des aktuellen Trainingsjobs angegeben haben, in Form eines Wörterbuchs.

Beispiel für CLUSTER_SPEC

Hier ein Beispielwert:


{
   "cluster":{
      "workerpool0":[
         "cmle-training-workerpool0-ab-0:2222"
      ],
      "workerpool1":[
         "cmle-training-workerpool1-ab-0:2222",
         "cmle-training-workerpool1-ab-1:2222"
      ],
      "workerpool2":[
         "cmle-training-workerpool2-ab-0:2222",
         "cmle-training-workerpool2-ab-1:2222"
      ],
      "workerpool3":[
         "cmle-training-workerpool3-ab-0:2222",
         "cmle-training-workerpool3-ab-1:2222",
         "cmle-training-workerpool3-ab-2:2222"
      ]
   },
   "environment":"cloud",
   "task":{
      "type":"workerpool0",
      "index":0,
      "trial":"TRIAL_ID"
   },
   "job": {
      ...
   }
}

Format von TF_CONFIG

Zusätzlich zu CLUSTER_SPEC legt Vertex AI die Umgebungsvariable TF_CONFIG für jedes Replikat aller verteilten Trainingsjobs fest. Vertex AI legt nicht TF_CONFIG für Trainingsjobs mit einzelnem Replikat fest.

CLUSTER_SPEC und TF_CONFIG haben einige gemeinsame Werte, aber unterschiedliche Formate. Beide Umgebungsvariablen umfassen zusätzliche Felder, die über die Anforderungen von TensorFlow hinausgehen.

Verteiltes Training mit TensorFlow funktioniert genauso, wenn Sie benutzerdefinierte Container und einen vordefinierten Container verwenden.

Die Umgebungsvariable TF_CONFIG ist ein JSON-String mit dem folgenden Format:

TF_CONFIG-Felder
cluster

Die TensorFlow-Clusterbeschreibung. Ein Wörterbuch, das einen oder mehrere Aufgabennamen (chief, worker, ps oder master) Listen von Netzwerkadressen zuordnet, in denen diese Aufgaben ausgeführt werden. Für einen bestimmten Trainingsjob ist dieses Wörterbuch auf jeder VM gleich.

Dies ist ein gültiges erstes Argument für den tf.train.ClusterSpec-Konstruktor. Beachten Sie, dass dieses Wörterbuch niemals evaluator als Schlüssel enthält, da Evaluators nicht als Teil des Trainingsclusters angesehen werden, selbst wenn Sie sie für Ihren Job verwenden.

task

Die Aufgabenbeschreibung der VM, auf der diese Umgebungsvariable festgelegt ist. Bei einem bestimmten Trainingsjob ist dieses Wörterbuch auf jeder VM unterschiedlich. Anhand dieser Informationen können Sie anpassen, welcher Code auf jeder VM in einem verteilten Trainingsjob ausgeführt wird. Sie können damit auch das Verhalten Ihres Trainingscodes für verschiedene Versuche eines Hyperparameter-Abstimmungsjobs ändern.

Dieses Wörterbuch enthält die folgenden Schlüssel/Wert-Paare:

task Felder
type

Die Art der Aufgabe, die diese VM ausführt. Dieser Wert wird für Worker auf worker, für Parameterserver auf ps und für Evaluators auf evaluator gesetzt. Beim Master-Worker Ihres Jobs wird der Wert entweder auf chief oder auf master gesetzt. Weitere Informationen zum Unterschied zwischen den beiden Optionen finden Sie im Abschnitt chief im Vergleich zu master in diesem Dokument.

index

Der nullbasierte Index der Aufgabe. Wenn Ihr Trainingsjob beispielsweise zwei Worker enthält, wird dieser Wert für den einen auf 0 und für den anderen auf 1 festgelegt.

trial

Die ID des Tests zur Hyperparameter-Abstimmung, der aktuell auf dieser VM ausgeführt wird. Dieses Feld wird nur festgelegt, wenn der aktuelle Trainingsjob ein Hyperparameter-Abstimmungsjob ist.

Bei Hyperparameter-Abstimmungsjobs führt Vertex AI den Trainingscode wiederholt in vielen Tests mit unterschiedlichen Hyperparametern aus. Dieses Feld enthält die aktuelle Testnummer, beginnend mit 1 für den ersten Test.

cloud

Eine von Vertex AI verwendete ID. Dieses Feld können Sie ignorieren.

job

Der CustomJobSpec, den Sie zum Erstellen des aktuellen Trainingsjobs angegeben haben, in Form eines Wörterbuchs.

environment

Der String cloud.

Beispiel für TF_CONFIG

Der folgende Beispielcode gibt die Umgebungsvariable TF_CONFIG an Ihre Trainingslogs aus:

import json
import os

tf_config_str = os.environ.get('TF_CONFIG')
tf_config_dict  = json.loads(tf_config_str)

# Convert back to string just for pretty printing
print(json.dumps(tf_config_dict, indent=2))

Bei einem Hyperparameter-Abstimmungsjob, der in der Laufzeitversion 2.1 oder höher ausgeführt wird und einen Master-Worker, zwei Worker und einen Parameterserver verwendet, erstellt dieser Code während des ersten Hyperparameter-Abstimmungstests für einen der Worker das folgende Log. Die Beispielausgabe blendet das job-Feld aus Gründen der Übersichtlichkeit aus und ersetzt einige IDs durch generische Werte.

{
  "cluster": {
    "chief": [
      "training-workerpool0-[ID_STRING_1]-0:2222"
    ],
    "ps": [
      "training-workerpool2-[ID_STRING_1]-0:2222"
    ],
    "worker": [
      "training-workerpool1-[ID_STRING_1]-0:2222",
      "training-workerpool1-[ID_STRING_1]-1:2222"
    ]
  },
  "environment": "cloud",
  "job": {
    ...
  },
  "task": {
    "cloud": "[ID_STRING_2]",
    "index": 0,
    "trial": "1",
    "type": "worker"
  }
}

Verwendung von TF_CONFIG

TF_CONFIG wird nur für verteilte Trainingsjobs festgelegt.

Wahrscheinlich müssen Sie nicht direkt mit der Umgebungsvariable TF_CONFIG in Ihrem Trainingscode interagieren. Greifen Sie nur dann auf die Umgebungsvariable TF_CONFIG zu, wenn die Verteilungsstrategien von TensorFlow und der standardmäßige Hyperparameter-Abstimmungsworkflow von Vertex AI (beides wird in den nächsten Abschnitten beschrieben) nicht für Ihren Job geeignet sind.

Verteiltes Training

Vertex AI legt die Umgebungsvariable TF_CONFIG fest, um die Spezifikationen zu erweitern, die TensorFlow für verteiltes Training benötigt.

Verwenden Sie die tf.distribute.Strategy API, um verteiltes Training mit TensorFlow durchzuführen. Insbesondere empfehlen wir Ihnen, die Keras API zusammen mit der MultiWorkerMirroredStrategy oder, wenn Sie für den Job Parameterserver angeben, mit der ParameterServerStrategy zu verwenden. Beachten Sie jedoch, dass TensorFlow derzeit nur experimentelle Unterstützung für diese Strategien bietet.

Bei diesen Verteilungsstrategien wird die Umgebungsvariable TF_CONFIG verwendet, um jeder VM in Ihrem Trainingsjob Rollen zuzuweisen und die Kommunikation zwischen den VMs zu erleichtern. Sie müssen nicht direkt im Trainingscode auf die Umgebungsvariable TF_CONFIG zugreifen, da TensorFlow das für Sie übernimmt.

Parsen Sie die Umgebungsvariable TF_CONFIG nur dann direkt, wenn Sie anpassen möchten, wie sich die verschiedenen VMs verhalten, die Ihren Trainingsjob ausführen.

Hyperparameter-Feinabstimmung

Wenn Sie einen Hyperparameter-Abstimmungsjob ausführen, stellt Vertex AI für jeden Test verschiedene Argumente bereit. Der Trainingscode muss nicht unbedingt wissen, welcher Test gerade ausgeführt wird. Darüber hinaus können Sie den Fortschritt von Hyperparameter-Abstimmungsjobs in der Google Cloud Console überwachen.

Bei Bedarf kann Ihr Code die aktuelle Testnummer aus dem Feld trial des Felds task der Umgebungsvariablen TF_CONFIG lesen.

Nächste Schritte