Prototyp zur Produktion: Hyperparameter-Abstimmung

1. Übersicht

In diesem Lab verwenden Sie Vertex AI, um einen Hyperparameter-Abstimmungsjob in Vertex AI Training auszuführen.

Dieses Lab ist Teil der Videoreihe Von Prototyp zur Produktion. Sie sollten das vorherige Lab abgeschlossen haben, bevor Sie dieses hier ausprobieren. Weitere Informationen finden Sie in der zugehörigen Videoserie:

.

Lerninhalte

Die folgenden Themen werden behandelt:

  • Trainingsanwendungscode für die automatische Hyperparameter-Abstimmung ändern
  • Hyperparameter-Abstimmungsjob mit dem Vertex AI Python SDK konfigurieren und starten

Die Gesamtkosten für die Ausführung dieses Labs in Google Cloud betragen etwa 1$.

2. Einführung in Vertex AI

In diesem Lab wird das neueste KI-Produkt von Google Cloud verwendet. Vertex AI vereint die ML-Angebote von Google Cloud in einer nahtlosen Entwicklungsumgebung. Bisher musste auf mit AutoML trainierte und benutzerdefinierte Modelle über verschiedene Dienste zugegriffen werden. Das neue Angebot kombiniert diese und weitere, neue Produkte zu einer einzigen API. Sie können auch vorhandene Projekte zu Vertex AI migrieren.

Vertex AI umfasst viele verschiedene Produkte zur Unterstützung von End-to-End-ML-Workflows. In diesem Lab geht es um die unten hervorgehobenen Produkte: Training und Workbench.

Vertex-Produktübersicht

3. Umgebung einrichten

Führen Sie die Schritte im Lab Benutzerdefinierte Modelle mit Vertex AI trainieren aus, um Ihre Umgebung einzurichten.

4. Trainingsanwendungscode containerisieren

Sie senden diesen Trainingsjob an Vertex AI, indem Sie den Code Ihrer Trainingsanwendung in einen Docker-Container einfügen und diesen Container in Google Artifact Registry übertragen. Mit diesem Ansatz können Sie ein Modell trainieren und abstimmen, das mit einem beliebigen Framework erstellt wurde.

Öffnen Sie zuerst über das Launcher-Menü des Workbench-Notebooks, das Sie in den vorherigen Labs erstellt haben, ein Terminalfenster.

Terminal in Notebook öffnen

Schritt 1: Trainingscode schreiben

Erstellen Sie ein neues Verzeichnis mit dem Namen flowers-hptune und wechseln Sie dorthin:

mkdir flowers-hptune
cd flowers-hptune

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

mkdir trainer
touch trainer/task.py

Ihr flowers-hptune/-Verzeichnis sollte jetzt Folgendes enthalten:

+ trainer/
    + task.py

Öffnen Sie dann die gerade erstellte Datei task.py und kopieren Sie den folgenden Code.

Sie müssen {your-gcs-bucket} in BUCKET_ROOT durch den Cloud Storage-Bucket ersetzen, in dem Sie das Blumen-Dataset in Lab 1 gespeichert haben.

import tensorflow as tf
import numpy as np
import os
import hypertune
import argparse

## Replace {your-gcs-bucket} !!
BUCKET_ROOT='/gcs/{your-gcs-bucket}'

# Define variables
NUM_CLASSES = 5
EPOCHS=10
BATCH_SIZE = 32

IMG_HEIGHT = 180
IMG_WIDTH = 180

DATA_DIR = f'{BUCKET_ROOT}/flower_photos'

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 create_datasets(data_dir, batch_size):
  '''Creates train and validation datasets.'''

  train_dataset = tf.keras.utils.image_dataset_from_directory(
    data_dir,
    validation_split=0.2,
    subset="training",
    seed=123,
    image_size=(IMG_HEIGHT, IMG_WIDTH),
    batch_size=batch_size)

  validation_dataset = tf.keras.utils.image_dataset_from_directory(
    data_dir,
    validation_split=0.2,
    subset="validation",
    seed=123,
    image_size=(IMG_HEIGHT, IMG_WIDTH),
    batch_size=batch_size)

  train_dataset = train_dataset.cache().shuffle(1000).prefetch(buffer_size=tf.data.AUTOTUNE)
  validation_dataset = validation_dataset.cache().prefetch(buffer_size=tf.data.AUTOTUNE)

  return train_dataset, validation_dataset


def create_model(num_units, learning_rate, momentum):
  '''Creates model.'''

  model = tf.keras.Sequential([
    tf.keras.layers.Resizing(IMG_HEIGHT, IMG_WIDTH),
    tf.keras.layers.Rescaling(1./255, input_shape=(IMG_HEIGHT, IMG_WIDTH, 3)),
    tf.keras.layers.Conv2D(16, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(32, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu'),
    tf.keras.layers.MaxPooling2D(),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(num_units, activation='relu'),
    tf.keras.layers.Dense(NUM_CLASSES, activation='softmax')
  ])

  model.compile(optimizer=tf.keras.optimizers.SGD(learning_rate=learning_rate, momentum=momentum),
              loss=tf.keras.losses.SparseCategoricalCrossentropy(),
              metrics=['accuracy'])
  
  return model

def main():
  args = get_args()
  train_dataset, validation_dataset = create_datasets(DATA_DIR, BATCH_SIZE)
  model = create_model(args.num_units, args.learning_rate, args.momentum)
  history = model.fit(train_dataset, validation_data=validation_dataset, epochs=EPOCHS)

  # 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=EPOCHS)


if __name__ == "__main__":
    main()

Bevor Sie den Container erstellen, sehen wir uns den Code genauer an. Für die Verwendung des Hyperparameter-Abstimmungsdienstes sind einige spezielle Komponenten erforderlich.

  1. Das Skript importiert die hypertune-Bibliothek.
  2. Die Funktion get_args() definiert ein Befehlszeilenargument für jeden Hyperparameter, den Sie abstimmen möchten. In diesem Beispiel werden die Lernrate, der Momentum-Wert im Optimierer und die Anzahl der Einheiten in der letzten verborgenen Schicht des Modells optimiert. Sie können aber auch andere Hyperparameter verwenden. Der für diese Argumente übergebene Wert wird dann verwendet, um den entsprechenden Hyperparameter im Code festzulegen.
  3. Am Ende der Funktion main() wird die hypertune-Bibliothek verwendet, um den zu optimierenden Messwert zu definieren. In TensorFlow gibt die Keras-Methode model.fit ein History-Objekt zurück. Das Attribut History.history enthält eine Aufzeichnung der Trainingsverlustwerte und Messwerte in aufeinanderfolgenden Epochen. Wenn Sie Validierungsdaten an model.fit übergeben, enthält das Attribut History.history auch den Validierungsverlust und die Messwerte. Wenn Sie beispielsweise ein Modell für drei Epochen mit Validierungsdaten trainiert und accuracy als Messwert angegeben haben, sieht das Attribut History.history in etwa so 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 der Hyperparameter-Abstimmungsdienst die Werte ermitteln soll, mit denen die Validierungsgenauigkeit des Modells maximiert wird, definieren Sie den Messwert als letzten Eintrag (oder NUM_EPOCS - 1) der Liste val_accuracy. Übergeben Sie diesen Messwert dann an eine Instanz von HyperTune. Sie können einen beliebigen String für hyperparameter_metric_tag auswählen. Sie müssen den String jedoch später wieder verwenden, wenn Sie den Hyperparameter-Abstimmungsjob starten.

Schritt 2: Dockerfile erstellen

Um Ihren Code zu containerisieren, müssen Sie ein Dockerfile erstellen. Das Dockerfile enthält alle Befehle, die zum Ausführen des Images erforderlich sind. Dadurch werden alle erforderlichen Bibliotheken installiert und der Einstiegspunkt für den Trainingscode eingerichtet.

Erstellen Sie über Ihr Terminal ein leeres Dockerfile im Stammverzeichnis Ihres flowers-hptune-Verzeichnisses:

touch Dockerfile

Ihr flowers-hptune/-Verzeichnis sollte jetzt Folgendes enthalten:

+ Dockerfile
+ trainer/
    + task.py

Öffnen Sie das Dockerfile und kopieren Sie den folgenden Code hinein. Dieses Dockerfile ist fast identisch mit dem Dockerfile, das wir im ersten Lab verwendet haben. Der einzige Unterschied ist, dass wir jetzt die cloudml-hypertune-Bibliothek installieren.

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

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"]

Schritt 3: 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'

Repository in Artifact Registry definieren Wir verwenden das Repository, das wir im ersten Lab erstellt haben.

REPO_NAME='flower-app'

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

IMAGE_URI=us-central1-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/flower_image_hptune:latest

Docker konfigurieren

gcloud auth configure-docker \
    us-central1-docker.pkg.dev

Erstellen Sie dann den Container, indem Sie den folgenden Befehl im Stammverzeichnis Ihres flower-hptune-Verzeichnisses ausführen:

docker build ./ -t $IMAGE_URI

Übertragen Sie es schließlich per Push in Artifact Registry:

docker push $IMAGE_URI

Nachdem Sie den Container in Artifact Registry hochgeladen haben, können Sie jetzt den Trainingsjob starten.

5. Hyperparameter-Abstimmungsjob mit dem SDK ausführen

In diesem Abschnitt erfahren Sie, wie Sie den Hyperparameter-Abstimmungsjob mit der Vertex Python API konfigurieren und senden.

Erstellen Sie über den Launcher ein TensorFlow 2-Notebook.

new_notebook

Importieren Sie das Vertex AI 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, in der der Maschinentyps und das Docker-Image angegeben werden. Die folgende Spezifikation definiert eine Maschine mit zwei NVIDIA Tesla V100-GPUs.

Ersetzen Sie {PROJECT_ID} in image_uri durch Ihr Projekt.

# 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": 1
    },
    "replica_count": 1,
    "container_spec": {
        "image_uri": "us-central1-docker.pkg.dev/{PROJECT_ID}/flower-app/flower_image_hptune:latest"
    }
}]

Als Nächstes definieren Sie parameter_spec. Das ist ein Dictionary, in dem die Parameter angegeben werden, die Sie optimieren möchten. Der Dictionary-Schlüssel ist der String, den Sie dem Befehlszeilenargument für jeden Hyperparameter zugewiesen haben, und der Dictionary-Wert ist die Parameterspezifikation.

Für jeden Hyperparameter müssen Sie den Typ sowie die Grenzen für die Werte definieren, die vom Abstimmungsdienst getestet werden. 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 einen Höchstwert angeben. Wenn Sie „Kategorisch“ oder „Diskret“ auswählen, müssen Sie die Werte angeben. Für die Typen „Double“ und „Integer“ müssen Sie auch den Skalierungswert angeben. Weitere Informationen zur Auswahl der besten Skalierung

# 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. Dabei handelt es sich um ein Dictionary, das den zu optimierenden Messwert darstellt. Der Wörterbuchschlüssel ist der hyperparameter_metric_tag, den Sie im Code Ihrer Trainingsanwendung festgelegt haben, und der Wert ist das Optimierungsziel.

# Dictionary representing metric 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 einen CustomJob. Das ist die gemeinsame Spezifikation, die verwendet wird, um Ihren Job für jeden der Hyperparameter-Abstimmungstests auszuführen.

Ersetzen Sie {YOUR_BUCKET} durch den zuvor erstellten Bucket.

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

Erstellen und führen Sie dann die HyperparameterTuningJob aus.

hp_job = aiplatform.HyperparameterTuningJob(
    display_name='flowers-hptune-job',
    custom_job=my_custom_job,
    metric_spec=metric_spec,
    parameter_spec=parameter_spec,
    max_trial_count=15,
    parallel_trial_count=3)

hp_job.run()

Dabei sind einige Argumente zu beachten:

  • max_trial_count: Sie müssen eine Obergrenze für die Anzahl der Tests festlegen, die der Dienst ausführt. Mehr Tests führen in der Regel zu besseren Ergebnissen. Es gibt jedoch einen Punkt, ab dem rückläufige Ergebnisse geliefert werden und zusätzliche Tests danach wenig oder keinen Einfluss auf den Messwert haben, den Sie optimieren möchten. Es empfiehlt sich, mit einer kleineren Anzahl von Tests zu beginnen, um zu sehen, wie sich die gewählten Hyperparameter auswirken, bevor Sie die Anzahl erhöhen.
  • parallel_trial_count: Wenn Sie parallele Tests verwenden, stellt der Dienst mehrere Trainingsverarbeitungscluster bereit. Wenn Sie die Anzahl der parallelen Tests erhöhen, verkürzt sich die Laufzeit des Hyperparameter-Abstimmungsjobs. Dies kann jedoch die Effektivität des Jobs insgesamt verringern. Das liegt daran, dass bei der Standardstrategie zur Abstimmung die Ergebnisse vorheriger Tests verwendet werden, um die Zuweisung von Werten in nachfolgenden Tests zu optimieren.
  • search_algorithm: Sie können den Suchalgorithmus auf „grid“, „random“ oder „default“ (None) festlegen. Bei der Standardoption wird die Bayes'sche Optimierung verwendet, um den Bereich möglicher Hyperparameterwerte zu durchsuchen. Dies ist der empfohlene Algorithmus. Weitere Informationen zu diesem Algorithmus

In der Konsole können Sie den Fortschritt Ihres Jobs sehen.

hp_job

Nach Abschluss des Jobs können Sie die Ergebnisse der einzelnen Tests sehen und herausfinden, mit welcher Kombination von Werten die beste Leistung erzielt wurde.

hp_results

🎉 Das wars! 🎉

Sie haben gelernt, wie Sie Vertex AI für folgende Aufgaben verwenden:

  • Automatischen Hyperparameter-Abstimmungsjob ausführen

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

6. Bereinigen

Da wir das Notebook so konfiguriert haben, dass es nach 60 Minuten Inaktivität ein Zeitlimit erreicht, müssen wir uns keine Gedanken über das Herunterfahren der Instanz machen. Wenn Sie die Instanz manuell herunterfahren möchten, klicken Sie im Bereich „Vertex AI Workbench“ der Console auf die Schaltfläche „Beenden“. Wenn Sie das Notebook vollständig löschen möchten, klicken Sie auf die Schaltfläche „Löschen“.

Instanz beenden

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

Speicher löschen