Vertex AI: Verteilte Hyperparameter-Abstimmung

1. Übersicht

In diesem Lab erfahren Sie, wie Sie Vertex AI für die Hyperparameter-Abstimmung und verteiltes Training verwenden. In diesem Lab wird TensorFlow für den Modellcode verwendet. Die Konzepte lassen sich aber auch auf andere ML-Frameworks anwenden.

Lerninhalte

Die folgenden Themen werden behandelt:

  • Modell mit verteiltem Training in einem benutzerdefinierten Container trainieren
  • Mehrere Tests Ihres Trainingscodes für die automatisierte Hyperparameter-Abstimmung starten

Die Gesamtkosten für das Lab in Google Cloud betragen etwa $6.

2. Einführung in Vertex AI

In diesem Lab wird das neueste KI-Produktangebot von Google Cloud verwendet. Vertex AI bindet die ML-Angebote in Google Cloud in eine nahtlose Entwicklungsumgebung ein. Zuvor waren mit AutoML trainierte und benutzerdefinierte Modelle über separate Dienste zugänglich. Das neue Angebot vereint beides in einer einzigen API sowie weitere neue Produkte. Sie können auch vorhandene Projekte zu Vertex AI migrieren. Wenn Sie uns Feedback geben möchten, besuchen Sie die Supportseite.

Vertex AI enthält viele verschiedene Produkte zur Unterstützung von End-to-End-ML-Workflows. In diesem Lab konzentrieren wir uns auf Training und Workbench.

Vertex-Produktübersicht

3. Anwendungsfall – Übersicht

In diesem Lab ermitteln Sie mithilfe der Hyperparameter-Abstimmung optimale Parameter für ein Bildklassifizierungsmodell, das mit dem Pferde- oder Mensch-Dataset aus TensorFlow-Datasets trainiert wurde.

Hyperparameter-Abstimmung

Bei der Hyperparameter-Abstimmung mit Vertex AI Training werden mehrere Tests Ihrer Trainingsanwendung mit Werten für Ihre ausgewählten Hyperparameter innerhalb der von Ihnen festgelegten Limits ausgeführt. Vertex AI verfolgt die Ergebnisse jedes Tests und nimmt Anpassungen für nachfolgende Tests vor.

Wenn Sie die Hyperparameter-Abstimmung mit Vertex AI Training verwenden möchten, müssen Sie zwei Änderungen an Ihrem Trainingscode vornehmen:

  1. Definieren Sie in Ihrem Haupttrainingsmodul für jeden Hyperparameter, den Sie abstimmen möchten, ein Befehlszeilenargument.
  2. Verwenden Sie den mit diesen Argumenten übergebenen Wert, um den entsprechenden Hyperparameter im Code Ihrer Anwendung festzulegen.

Verteiltes Training

Wenn Sie eine einzelne GPU haben, verwendet TensorFlow diesen Beschleuniger, um das Modelltraining ohne zusätzlichen Aufwand für Sie zu beschleunigen. Wenn Sie jedoch durch die Verwendung mehrerer GPUs zusätzliche Leistung erzielen möchten, müssen Sie tf.distribute verwenden. Das Modul von TensorFlow ist das Modul zur Ausführung einer Berechnung auf mehreren Geräten.

In diesem Lab wird tf.distribute.MirroredStrategy verwendet, das Sie mit nur wenigen Codeänderungen Ihren Trainingsanwendungen hinzufügen können. Mit dieser Strategie wird eine Kopie des Modells auf jeder GPU auf Ihrem Computer erstellt. Die nachfolgenden Gradientenaktualisierungen erfolgen synchron. Dies bedeutet, dass jede GPU den Vor- und Rückwärtsdurchlauf durch das Modell anhand eines anderen Segments der Eingabedaten berechnet. Die berechneten Gradienten aus jedem dieser Segmente werden dann über alle GPUs aggregiert und in einem als All-Reduce bezeichneten Prozess gemittelt. Modellparameter werden mithilfe dieser gemittelten Farbverläufe aktualisiert.

Die Details sind für dieses Lab nicht erforderlich, aber wenn Sie mehr darüber erfahren möchten, wie verteiltes Training in TensorFlow funktioniert, sehen Sie sich das folgende Video an:

4. Umgebung einrichten

Sie benötigen ein Google Cloud Platform-Projekt mit aktivierter Abrechnung, um dieses Codelab auszuführen. Folgen Sie dieser Anleitung, um ein Projekt zu erstellen.

Schritt 1: Compute Engine API aktivieren

Gehen Sie zu Compute Engine und wählen Sie Aktivieren aus, falls dies noch nicht geschehen ist.

Schritt 2: Container Registry API aktivieren

Rufen Sie Container Registry auf und wählen Sie Aktivieren aus, falls noch nicht geschehen. Damit erstellen Sie einen Container für Ihren benutzerdefinierten Trainingsjob.

Schritt 3: Vertex AI API aktivieren

Rufen Sie den Bereich Vertex AI in der Cloud Console auf und klicken Sie auf Vertex AI API aktivieren.

Vertex AI-Dashboard

Schritt 4: Vertex AI Workbench-Instanz erstellen

Klicken Sie im Bereich Vertex AI der Cloud Console auf Workbench:

Vertex AI-Menü

Aktivieren Sie die Notebooks API, falls noch nicht geschehen.

Notebook_api

Klicken Sie nach der Aktivierung auf VERWALTETE NOTEBOOKS:

Notebooks_UI

Wählen Sie dann NEUES NOTEBOOK aus.

new_notebook

Geben Sie Ihrem Notebook einen Namen und klicken Sie auf Erweiterte Einstellungen.

create_notebook

Aktivieren Sie unter „Erweiterte Einstellungen“ das Herunterfahren bei Inaktivität und legen Sie die Anzahl der Minuten auf 60 fest. Das bedeutet, dass Ihr Notebook bei Nichtgebrauch automatisch heruntergefahren wird, sodass Ihnen keine unnötigen Kosten entstehen.

idle_timeout

Wähle unter „Sicherheit“ die Option „Terminal aktivieren“ aus. falls es noch nicht aktiviert ist.

Terminal aktivieren

Alle anderen erweiterten Einstellungen können Sie unverändert lassen.

Klicken Sie dann auf Erstellen. Die Bereitstellung der Instanz kann einige Minuten dauern.

Nachdem die Instanz erstellt wurde, wählen Sie JupyterLab öffnen aus.

open_jupyterlab

Wenn Sie zum ersten Mal eine neue Instanz verwenden, werden Sie zur Authentifizierung aufgefordert. Folgen Sie dazu den Schritten in der Benutzeroberfläche.

Authentifizieren

5. Trainingscode schreiben

Öffnen Sie dazu im Launcher-Menü ein Terminalfenster in Ihrer Notebookinstanz:

launcher_terminal

Erstellen Sie ein neues Verzeichnis mit dem Namen vertex-codelab und fügen Sie es mit cd ein.

mkdir vertex-codelab
cd vertex-codelab

Führen Sie den folgenden Befehl aus, um ein Verzeichnis für den Trainingscode und eine Python-Datei zu erstellen, in die Sie den Code einfügen:

mkdir trainer
touch trainer/task.py

In Ihrem vertex-codelab-Verzeichnis sollte nun Folgendes vorhanden sein:

+ trainer/
    + task.py

Öffnen Sie als Nächstes die Datei task.py, die Sie gerade erstellt haben, und fügen Sie den gesamten unten stehenden Code ein.

import tensorflow as tf
import tensorflow_datasets as tfds
import argparse
import hypertune
import os

NUM_EPOCHS = 10
BATCH_SIZE = 64

def get_args():
  '''Parses args. Must include all hyperparameters you want to tune.'''

  parser = argparse.ArgumentParser()
  parser.add_argument(
      '--learning_rate',
      required=True,
      type=float,
      help='learning rate')
  parser.add_argument(
      '--momentum',
      required=True,
      type=float,
      help='SGD momentum value')
  parser.add_argument(
      '--num_units',
      required=True,
      type=int,
      help='number of units in last hidden layer')
  args = parser.parse_args()
  return args


def preprocess_data(image, label):
  '''Resizes and scales images.'''

  image = tf.image.resize(image, (150,150))
  return tf.cast(image, tf.float32) / 255., label


def create_dataset(batch_size):
  '''Loads Horses Or Humans dataset and preprocesses data.'''

  data, info = tfds.load(name='horses_or_humans', as_supervised=True, with_info=True)

  # Create train dataset
  train_data = data['train'].map(preprocess_data)
  train_data  = train_data.shuffle(1000)
  train_data  = train_data.batch(batch_size)

  # Create validation dataset
  validation_data = data['test'].map(preprocess_data)
  validation_data  = validation_data.batch(batch_size)

  return train_data, validation_data


def create_model(num_units, learning_rate, momentum):
  '''Defines and compiles model.'''

  inputs = tf.keras.Input(shape=(150, 150, 3))
  x = tf.keras.layers.Conv2D(16, (3, 3), activation='relu')(inputs)
  x = tf.keras.layers.MaxPooling2D((2, 2))(x)
  x = tf.keras.layers.Conv2D(32, (3, 3), activation='relu')(x)
  x = tf.keras.layers.MaxPooling2D((2, 2))(x)
  x = tf.keras.layers.Conv2D(64, (3, 3), activation='relu')(x)
  x = tf.keras.layers.MaxPooling2D((2, 2))(x)
  x = tf.keras.layers.Flatten()(x)
  x = tf.keras.layers.Dense(num_units, activation='relu')(x)
  outputs = tf.keras.layers.Dense(1, activation='sigmoid')(x)
  model = tf.keras.Model(inputs, outputs)
  model.compile(
      loss='binary_crossentropy',
      optimizer=tf.keras.optimizers.SGD(learning_rate=learning_rate, momentum=momentum),
      metrics=['accuracy'])
  return model


def main():
  args = get_args()

  # Create distribution strategy
  strategy = tf.distribute.MirroredStrategy()

  # Get data
  GLOBAL_BATCH_SIZE = BATCH_SIZE * strategy.num_replicas_in_sync
  train_data, validation_data = create_dataset(GLOBAL_BATCH_SIZE)

  # Wrap variable creation within strategy scope
  with strategy.scope():
    model = create_model(args.num_units, args.learning_rate, args.momentum)

  # Train model
  history = model.fit(train_data, epochs=NUM_EPOCHS, validation_data=validation_data)

  # Define metric
  hp_metric = history.history['val_accuracy'][-1]

  hpt = hypertune.HyperTune()
  hpt.report_hyperparameter_tuning_metric(
      hyperparameter_metric_tag='accuracy',
      metric_value=hp_metric,
      global_step=NUM_EPOCHS)


if __name__ == "__main__":
    main()

Werfen wir nun einen genaueren Blick auf den Code und die spezifischen Komponenten für verteiltes Training und Hyperparameter-Abstimmung.

Verteiltes Training

  1. In der main()-Funktion wird das MirroredStrategy-Objekt erstellt. Als Nächstes schließen Sie die Erstellung Ihrer Modellvariablen in den Bereich der Strategie ein. In diesem Schritt wird TensorFlow mitgeteilt, welche Variablen in den GPUs gespiegelt werden sollen.
  2. Die Batchgröße wird um num_replicas_in_sync hochskaliert. Das Skalieren der Batchgröße ist eine Best Practice bei der Verwendung von Strategien zur synchronen Datenparallelität in TensorFlow. Weitere Informationen

Hyperparameter-Abstimmung

  1. Das Skript importiert die hypertune-Bibliothek. Wenn wir später das Container-Image erstellen, müssen wir sicherstellen, dass diese Bibliothek installiert wird.
  2. Die Funktion get_args() definiert ein Befehlszeilenargument für jeden Hyperparameter, den Sie abstimmen möchten. In diesem Beispiel sind die abgestimmten Hyperparameter die Lernrate, der Impulswert im Optimierungstool und die Anzahl der Einheiten in der letzten verborgenen Schicht des Modells. Sie können aber gerne mit anderen experimentieren. Der mit diesen Argumenten übergebene Wert wird dann verwendet, um den entsprechenden Hyperparameter im Code festzulegen (z. B. learning_rate = args.learning_rate).
  3. Am Ende der Funktion main() wird die Bibliothek hypertune verwendet, um den Messwert zu definieren, den Sie optimieren möchten. In TensorFlow gibt die Keras-Methode model.fit ein History-Objekt zurück. Das Attribut History.history ist ein Datensatz mit Trainingsverlustwerten und -messwerten in aufeinanderfolgenden Epochen. Wenn Sie Validierungsdaten an model.fit übergeben, enthält das Attribut History.history auch Validierungsverlust und Messwerte. Wenn Sie beispielsweise ein Modell über drei Epochen mit Validierungsdaten trainiert und accuracy als Messwert angegeben haben, sieht das History.history-Attribut wie im folgenden Wörterbuch aus.
{
 "accuracy": [
   0.7795261740684509,
   0.9471358060836792,
   0.9870933294296265
 ],
 "loss": [
   0.6340447664260864,
   0.16712145507335663,
   0.04546636343002319
 ],
 "val_accuracy": [
   0.3795261740684509,
   0.4471358060836792,
   0.4870933294296265
 ],
 "val_loss": [
   2.044623374938965,
   4.100203514099121,
   3.0728273391723633
 ]

Wenn Sie möchten, dass der Hyperparameter-Abstimmungsdienst die Werte erkennt, die die Validierungsgenauigkeit des Modells maximieren, definieren Sie den Messwert als letzten Eintrag (oder NUM_EPOCS - 1) der val_accuracy-Liste. Übergeben Sie diesen Messwert dann an eine Instanz von HyperTune. Sie können für hyperparameter_metric_tag einen beliebigen String auswählen, müssen den String aber später noch einmal verwenden, wenn Sie den Hyperparameter-Abstimmungsjob starten.

6. Code containerisieren

Der erste Schritt bei der Containerisierung Ihres Codes besteht darin, ein Dockerfile zu erstellen. In das Dockerfile geben Sie alle Befehle ein, die zum Ausführen des Images erforderlich sind. Damit werden alle erforderlichen Bibliotheken installiert und der Einstiegspunkt für den Trainingscode eingerichtet.

Schritt 1: Dockerfile schreiben

Prüfen Sie im Terminal, ob Sie sich im Verzeichnis vertex-codelab befinden, und erstellen Sie ein leeres Dockerfile:

touch Dockerfile

In Ihrem vertex-codelab-Verzeichnis sollte nun Folgendes vorhanden sein:

+ Dockerfile
+ trainer/
    + task.py

Öffnen Sie das Dockerfile und kopieren Sie Folgendes hinein:

FROM gcr.io/deeplearning-platform-release/tf2-gpu.2-7

WORKDIR /

# Installs hypertune library
RUN pip install cloudml-hypertune

# Copies the trainer code to the docker image.
COPY trainer /trainer

# Sets up the entry point to invoke the trainer.
ENTRYPOINT ["python", "-m", "trainer.task"]

Dieses Dockerfile verwendet das Deep Learning Container TensorFlow Enterprise 2.7 GPU Docker-Image. In den Deep-Learning-Containern in Google Cloud sind viele gängige ML- und Data-Science-Frameworks vorinstalliert. Nach dem Herunterladen des Images richtet dieses Dockerfile den Einstiegspunkt für den Trainingscode ein.

Schritt 2: Container erstellen

Führen Sie im Terminal den folgenden Befehl aus, um eine Umgebungsvariable für Ihr Projekt zu definieren. Ersetzen Sie dabei your-cloud-project durch die ID Ihres Projekts:

PROJECT_ID='your-cloud-project'

Definieren Sie in Google Container Registry eine Variable mit dem URI Ihres Container-Images:

IMAGE_URI="gcr.io/$PROJECT_ID/horse-human-codelab:latest"

Docker konfigurieren

gcloud auth configure-docker

Erstellen Sie dann den Container, indem Sie im Stammverzeichnis Ihres vertex-codelab-Verzeichnisses Folgendes ausführen:

docker build ./ -t $IMAGE_URI

Übertragen Sie die Datei abschließend per Push in Google Container Registry:

docker push $IMAGE_URI

Schritt 3: Cloud Storage-Bucket erstellen

In unserem Trainingsjob übergeben Sie den Pfad zu einem Staging-Bucket.

Führen Sie in Ihrem Terminal den folgenden Befehl aus, um einen neuen Bucket in Ihrem Projekt zu erstellen.

BUCKET_NAME="gs://${PROJECT_ID}-hptune-bucket"
gsutil mb -l us-central1 $BUCKET_NAME

7. Hyperparameter-Abstimmungsjob starten

Schritt 1: Benutzerdefinierten Trainingsjob mit Hyperparameter-Abstimmung erstellen

Öffnen Sie im Launcher ein neues TensorFlow 2-Notebook.

new_notebook

Importieren Sie das Vertex AI Python SDK.

from google.cloud import aiplatform
from google.cloud.aiplatform import hyperparameter_tuning as hpt

Um den Hyperparameter-Abstimmungsjob zu starten, müssen Sie zuerst die worker_pool_specs definieren, die den Maschinentyp und das Docker-Image angibt. In der folgenden Spezifikation wird eine Maschine mit zwei NVIDIA Tesla V100-GPUs definiert.

Sie müssen {PROJECT_ID} in image_uri durch Ihr Projekt ersetzen.

# The spec of the worker pools including machine type and Docker image
# Be sure to replace PROJECT_ID in the "image_uri" with your project.

worker_pool_specs = [{
    "machine_spec": {
        "machine_type": "n1-standard-4",
        "accelerator_type": "NVIDIA_TESLA_V100",
        "accelerator_count": 2
    },
    "replica_count": 1,
    "container_spec": {
        "image_uri": "gcr.io/{PROJECT_ID}/horse-human-codelab:latest"
    }
}]

Definieren Sie als Nächstes das parameter_spec. Dabei handelt es sich um ein Wörterbuch, in dem die zu optimierenden Parameter angegeben werden. Der Wörterbuchschlüssel ist der String, den Sie dem Befehlszeilenargument für jeden Hyperparameter zugewiesen haben, und der Wörterbuchwert ist die Parameterspezifikation.

Für jeden Hyperparameter müssen Sie den Typ sowie die Grenzen für die Werte definieren, die der Abstimmungsdienst versucht. Hyperparameter können vom Typ „Double“, „Integer“, „Categorical“ oder „Discrete“ sein. Wenn Sie den Typ "Double" oder "Integer" auswählen, müssen Sie einen Mindest- und Höchstwert angeben. Wenn Sie „Kategorial“ oder „Diskret“ auswählen, müssen Sie die Werte angeben. Für die Typen Double und Integer müssen Sie außerdem den Skalierungswert angeben. In diesem Video erfährst du mehr darüber, wie du die beste Skalierung auswählst.

# Dictionary representing parameters to optimize.
# The dictionary key is the parameter_id, which is passed into your training
# job as a command line argument,
# And the dictionary value is the parameter specification of the metric.
parameter_spec = {
    "learning_rate": hpt.DoubleParameterSpec(min=0.001, max=1, scale="log"),
    "momentum": hpt.DoubleParameterSpec(min=0, max=1, scale="linear"),
    "num_units": hpt.DiscreteParameterSpec(values=[64, 128, 512], scale=None)
}

Die letzte zu definierende Spezifikation ist metric_spec. Dies ist ein Wörterbuch, das den zu optimierenden Messwert darstellt. Der Wörterbuchschlüssel ist die hyperparameter_metric_tag, die Sie in Ihrem Trainingsanwendungscode festlegen, und der Wert ist das Optimierungsziel.

# Dicionary representing metrics to optimize.
# The dictionary key is the metric_id, which is reported by your training job,
# And the dictionary value is the optimization goal of the metric.
metric_spec={'accuracy':'maximize'}

Sobald die Spezifikationen definiert sind, erstellen Sie eine CustomJob. Dies ist die allgemeine Spezifikation, die zum Ausführen Ihres Jobs in jedem Hyperparameter-Abstimmungstest verwendet wird.

Sie müssen {YOUR_BUCKET} durch den Bucket ersetzen, den Sie zuvor erstellt haben.

# Replace YOUR_BUCKET
my_custom_job = aiplatform.CustomJob(display_name='horses-humans',
                              worker_pool_specs=worker_pool_specs,
                              staging_bucket='gs://{YOUR_BUCKET}')

Erstellen Sie dann den HyperparameterTuningJob und führen Sie ihn aus.

hp_job = aiplatform.HyperparameterTuningJob(
    display_name='horses-humans',
    custom_job=my_custom_job,
    metric_spec=metric_spec,
    parameter_spec=parameter_spec,
    max_trial_count=6,
    parallel_trial_count=2,
    search_algorithm=None)

hp_job.run()

Hier sind einige Argumente:

  • max_trial_count: Sie müssen die Anzahl der Tests, die der Dienst ausführen wird, begrenzen. Mehr Testläufe führen in der Regel zu besseren Ergebnissen, allerdings werden die Ergebnisse ab einem bestimmten Zeitpunkt zurückgehen. Weitere Tests haben anschließend nur wenig oder keinen Einfluss auf den Messwert, den Sie optimieren möchten. Es empfiehlt sich, mit einer kleineren Anzahl von Tests zu beginnen und ein Gefühl dafür zu bekommen, wie wirkungsvoll die ausgewählten Hyperparameter sind, bevor Sie hochskalieren.
  • parallel_trial_count: Wenn Sie parallele Tests verwenden, stellt der Dienst mehrere Trainingsverarbeitungscluster bereit. Wenn Sie die Anzahl der parallelen Tests erhöhen, verringert sich die Ausführungszeit des Hyperparameter-Abstimmungsjobs. kann jedoch die Effektivität des Jobs insgesamt reduzieren. Das liegt daran, dass die Standardabstimmungsstrategie Ergebnisse früherer Tests für die Zuweisung von Werten in nachfolgenden Tests verwendet.
  • search_algorithm: Sie können den Suchalgorithmus auf die Raster-, die Zufalls- oder die Standardeinstellung (Keiner) einstellen. Bei der Standardoption wird die Bayes'sche Optimierung angewendet, um den Bereich möglicher Hyperparameter-Werte zu durchsuchen. Dies ist der empfohlene Algorithmus. Weitere Informationen zu diesem Algorithmus

Sobald der Job gestartet wird, können Sie den Status in der Benutzeroberfläche auf dem Tab HYPERPARAMETER-FUNINGJOBS verfolgen.

HP_job

Sobald der Job abgeschlossen ist, können Sie die Ergebnisse Ihrer Tests anzeigen und sortieren, um die beste Kombination von Hyperparameter-Werten zu ermitteln.

HP_results

🎉 Glückwunsch! 🎉

Sie haben gelernt, wie Sie mit Vertex AI Folgendes tun können:

  • Hyperparameter-Abstimmungsjob mit verteiltem Training ausführen

Weitere Informationen zu den verschiedenen Teilen von Vertex AI finden Sie in der Dokumentation.

8. Bereinigen

Da wir das Notebook so konfiguriert haben, dass nach 60 Minuten Inaktivität eine Zeitüberschreitung auftritt, müssen wir uns nicht um das Herunterfahren der Instanz kümmern. Wenn Sie die Instanz manuell herunterfahren möchten, klicken Sie in der Console im Abschnitt Vertex AI Workbench auf die Schaltfläche „Stop“. Wenn Sie das Notizbuch vollständig löschen möchten, klicken Sie auf Löschen.

Löschen

Wenn Sie den Storage-Bucket löschen möchten, gehen Sie im Navigationsmenü der Cloud Console zu „Storage“, wählen Sie den Bucket aus und klicken Sie auf „Löschen“:

Speicher löschen