Vertex AI: Benutzerdefinierte Vorhersageroutinen mit Sklearn verwenden, um Daten für Vorhersagen vor- und nachzuverarbeiten

1. Übersicht

In diesem Lab lernen Sie, wie Sie mit benutzerdefinierten Vorhersageroutinen in Vertex AI benutzerdefinierte Vorverarbeitungs- und Nachbearbeitungslogik schreiben. In diesem Beispiel wird Scikit-learn verwendet, aber benutzerdefinierte Vorhersageroutinen können auch mit anderen Python-ML-Frameworks wie XGBoost, PyTorch und TensorFlow funktionieren.

Lerninhalte

Die folgenden Themen werden behandelt:

  • Benutzerdefinierte Vorhersagelogik mit benutzerdefinierten Vorhersageroutinen schreiben
  • Benutzerdefinierten Bereitstellungscontainer und Modell lokal testen
  • Benutzerdefinierten Bereitstellungscontainer in Vertex AI Predictions testen

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

2. Einführung in Vertex AI

In diesem Lab wird das neueste KI-Produktangebot von Google Cloud verwendet. Vertex AI integriert die ML-Angebote in Google Cloud für eine nahtlose Entwicklung. Bisher konnten auf mit AutoML trainierte Modelle und benutzerdefinierte Modelle über separate Dienste zugegriffen werden. Das neue Angebot kombiniert beide zusammen mit anderen neuen Produkten in 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 hauptsächlich um Vorhersagen und die Workbench.

Vertex-Produktübersicht

3. Anwendungsfall – Übersicht

Anwendungsfall

In diesem Lab erstellen Sie ein zufälliges Regressionsmodell für den Wald, um den Preis eines Diamanten anhand von Attributen wie Schliff, Klarheit und Größe vorherzusagen.

Sie schreiben eine benutzerdefinierte Logik für die Vorverarbeitung, um zu prüfen, ob die Daten zum Zeitpunkt der Bereitstellung im vom Modell erwarteten Format sind. Außerdem schreiben Sie eine benutzerdefinierte Logik für die Nachbearbeitung, um die Vorhersagen zu runden und in Strings umzuwandeln. Dazu verwenden Sie benutzerdefinierte Vorhersageroutinen.

Einführung in benutzerdefinierte Vorhersageroutinen

Die vordefinierten Container von Vertex AI verarbeiten Vorhersageanfragen, indem sie den Vorhersagevorgang des Frameworks für maschinelles Lernen ausführen. Wenn Sie vor benutzerdefinierten Vorhersageroutinen die Eingabe vorverarbeiten oder die Vorhersage des Modells nachbearbeiten wollten, bevor das Ergebnis zurückgegeben wird, mussten Sie einen benutzerdefinierten Container erstellen.

Zum Erstellen eines benutzerdefinierten Bereitstellungscontainers muss ein HTTP-Server geschrieben werden, der das trainierte Modell umschließt, HTTP-Anfragen in Modelleingaben übersetzt und Modellausgaben in Antworten umwandelt.

Mit benutzerdefinierten Vorhersageroutinen stellt Vertex AI die Bereitstellungskomponenten für Sie bereit, sodass Sie sich auf Ihre Modelle und Datentransformationen konzentrieren können.

4. Umgebung einrichten

Sie benötigen ein Google Cloud-Projekt mit aktivierter Abrechnung, um dieses Codelab ausführen zu können. Eine Anleitung zum Erstellen eines Projekts finden Sie hier.

Schritt 1: Compute Engine API aktivieren

Gehen Sie zu Compute Engine und wählen Sie Aktivieren aus, falls dies noch nicht geschehen ist. Sie benötigen sie, um Ihre Notebookinstanz zu erstellen.

Schritt 2: Artifact Registry API aktivieren

Rufen Sie Artifact Registry auf und wählen Sie Aktivieren aus, falls dies noch nicht geschehen ist. Damit erstellen Sie einen benutzerdefinierten Bereitstellungscontainer.

Schritt 3: Vertex AI API aktivieren

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

Vertex AI-Dashboard

Schritt 4: Vertex AI Workbench-Instanz erstellen

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

Vertex AI-Menü

Aktivieren Sie die Notebooks API, falls sie noch nicht aktiviert ist.

Notebook_api

Klicken Sie nach der Aktivierung auf INSTANZEN und wählen Sie dann NEUE ERSTELLEN aus.

Akzeptieren Sie die Standardoptionen und klicken Sie auf Erstellen.

Wenn die Instanz bereit ist, klicken Sie auf JUPYTERLAB ÖFFNEN, um sie zu öffnen.

5. Trainingscode schreiben

Schritt 1: Cloud Storage-Bucket erstellen

Sie speichern das Modell und die Artefakte der Vorverarbeitung in einem Cloud Storage-Bucket. Wenn Ihr Projekt bereits einen Bucket enthält, den Sie verwenden möchten, können Sie diesen Schritt überspringen.

Öffnen Sie über den Launcher eine neue Terminalsitzung.

Open_terminal

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'

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

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

Schritt 2: Modell trainieren

Erstellen Sie im Terminal ein neues Verzeichnis mit dem Namen cpr-codelab und wechseln Sie dorthin.

mkdir cpr-codelab
cd cpr-codelab

Rufen Sie im Dateibrowser das neue Verzeichnis cpr-codelab auf und erstellen Sie dann mit dem Launcher ein neues Python 3-Notebook namens task.ipynb.

file_browser

Ihr cpr-codelab-Verzeichnis sollte jetzt so aussehen:

+ cpr-codelab/
    + task.ipynb

Fügen Sie den folgenden Code in das Notebook ein.

Schreiben Sie zuerst eine requirements.txt-Datei.

%%writefile requirements.txt
fastapi
uvicorn==0.17.6
joblib~=1.0
numpy~=1.20
scikit-learn>=1.2.2
pandas
google-cloud-storage>=1.26.0,<2.0.0dev
google-cloud-aiplatform[prediction]>=1.16.0

In dem von Ihnen bereitgestellten Modell sind andere Abhängigkeiten vorinstalliert als in Ihrer Notebookumgebung. Daher sollten Sie alle Abhängigkeiten für das Modell in requirements.txt auflisten und dann mit pip genau dieselben Abhängigkeiten im Notebook installieren. Später testen Sie das Modell lokal, bevor Sie es in Vertex AI bereitstellen, um zu prüfen, ob die Umgebungen übereinstimmen.

Installieren Sie die Abhängigkeiten im Notebook mit Pip.

!pip install -U --user -r requirements.txt

Hinweis: Sie müssen den Kernel nach Abschluss der Installation mit Pip neu starten.

restart_kernel

Erstellen Sie als Nächstes die Verzeichnisse, in denen Sie das Modell und die Preprocessing-Artefakte speichern.

USER_SRC_DIR = "src_dir"
!mkdir $USER_SRC_DIR
!mkdir model_artifacts

# copy the requirements to the source dir
!cp requirements.txt $USER_SRC_DIR/requirements.txt

Das Verzeichnis cpr-codelab sollte jetzt so aussehen:

+ cpr-codelab/
    + model_artifacts/
    + scr_dir/
        + requirements.txt
    + task.ipynb
    + requirements.txt

Nachdem die Verzeichnisstruktur eingerichtet ist, können Sie ein Modell trainieren.

Importieren Sie zuerst die Bibliotheken.

import seaborn as sns
import numpy as np
import pandas as pd

from sklearn import preprocessing
from sklearn.ensemble import RandomForestRegressor
from sklearn.pipeline import make_pipeline
from sklearn.compose import make_column_transformer

import joblib
import logging

# set logging to see the docker container logs
logging.basicConfig(level=logging.INFO)

Definieren Sie dann die folgenden Variablen. Achten Sie darauf, PROJECT_ID durch Ihre Projekt-ID und BUCKET_NAME durch den Bucket zu ersetzen, den Sie im vorherigen Schritt erstellt haben.

REGION = "us-central1"
MODEL_ARTIFACT_DIR = "sklearn-model-artifacts"
REPOSITORY = "diamonds"
IMAGE = "sklearn-image"
MODEL_DISPLAY_NAME = "diamonds-cpr"

# Replace with your project
PROJECT_ID = "{PROJECT_ID}"

# Replace with your bucket
BUCKET_NAME = "gs://{BUCKET_NAME}"

Laden Sie die Daten aus der seaborn-Bibliothek und erstellen Sie dann zwei Datenframes, einen mit den Features und einen mit dem Label.

data = sns.load_dataset('diamonds', cache=True, data_home=None)

label = 'price'

y_train = data['price']
x_train = data.drop(columns=['price'])

Sehen wir uns die Trainingsdaten an. Sie sehen, dass jede Zeile eine Raute darstellt.

x_train.head()

Und die Labels, also die entsprechenden Preise.

y_train.head()

Definieren Sie nun eine Spaltentransformation in sklearn, um die kategorischen Merkmale zu einer Hot-Codierung zu verarbeiten und die numerischen Merkmale zu skalieren.

column_transform = make_column_transformer(
    (preprocessing.OneHotEncoder(), [1,2,3]),
    (preprocessing.StandardScaler(), [0,4,5,6,7,8]))

Random Forest-Modell definieren

regr = RandomForestRegressor(max_depth=10, random_state=0)

Erstellen Sie als Nächstes eine sklearn-Pipeline. Das bedeutet, dass Daten, die in diese Pipeline eingespeist werden, zuerst codiert/skaliert und dann an das Modell übergeben werden.

my_pipeline = make_pipeline(column_transform, regr)

Pipeline an die Trainingsdaten anpassen

my_pipeline.fit(x_train, y_train)

Testen wir das Modell, um sicherzugehen, dass es wie erwartet funktioniert. Rufen Sie die Methode predict für das Modell auf und übergeben Sie ein Testbeispiel.

my_pipeline.predict([[0.23, 'Ideal', 'E', 'SI2', 61.5, 55.0, 3.95, 3.98, 2.43]])

Jetzt können wir die Pipeline im Verzeichnis model_artifacts speichern und in den Cloud Storage-Bucket kopieren.

joblib.dump(my_pipeline, 'model_artifacts/model.joblib')

!gsutil cp model_artifacts/model.joblib {BUCKET_NAME}/{MODEL_ARTIFACT_DIR}/

Schritt 3: Vorverarbeitungsartefakt speichern

Als Nächstes erstellen Sie ein Vorverarbeitungsartefakt. Dieses Artefakt wird beim Start des Modellservers in den benutzerdefinierten Container geladen. Ihr Vorverarbeitungsartefakt kann fast jedes Format haben (z. B. eine Pickle-Datei). In diesem Fall schreiben Sie jedoch ein Wörterbuch in eine JSON-Datei.

clarity_dict={"Flawless": "FL",
              "Internally Flawless": "IF",
              "Very Very Slightly Included": "VVS1",
              "Very Slightly Included": "VS2",
              "Slightly Included": "S12",
              "Included": "I3"}

Das Feature clarity lag in unseren Trainingsdaten immer in der abgekürzten Form vor (d. h. „FL“ anstelle von „Flawless“). Beim Ausliefern möchten wir prüfen, ob die Daten für diese Funktion auch abgekürzt sind. Das liegt daran, dass unser Modell weiß, wie man einen „FL“, aber nicht „Flawless“ codieren muss. Diese benutzerdefinierte Vorverarbeitungslogik wird später geschrieben. Speichern Sie diese Suchtabelle vorerst in einer JSON-Datei und schreiben Sie sie dann in den Cloud Storage-Bucket.

import json
with open("model_artifacts/preprocessor.json", "w") as f:
    json.dump(clarity_dict, f)

!gsutil cp model_artifacts/preprocessor.json {BUCKET_NAME}/{MODEL_ARTIFACT_DIR}/

Ihr lokales cpr-codelab-Verzeichnis sollte jetzt so aussehen:

+ cpr-codelab/
    + model_artifacts/
        + model.joblib
        + preprocessor.json
    + scr_dir/
        + requirements.txt
    + task.ipynb
    + requirements.txt

6. Benutzerdefinierten Bereitstellungscontainer mit dem CPR-Modellserver erstellen

Nachdem das Modell trainiert und das Artefakt für die Vorverarbeitung gespeichert wurde, ist es an der Zeit, den benutzerdefinierten Bereitstellungscontainer zu erstellen. Normalerweise ist zum Erstellen eines Bereitstellungscontainers das Schreiben von Modellservercode erforderlich. Bei benutzerdefinierten Vorhersageroutinen generiert Vertex AI Predictions jedoch einen Modellserver und erstellt ein benutzerdefiniertes Container-Image für Sie.

Ein benutzerdefinierter Bereitstellungscontainer enthält die folgenden drei Codeteile:

  1. Modellserver (wird automatisch vom SDK generiert und in scr_dir/ gespeichert)
    • HTTP-Server, auf dem das Modell gehostet wird
    • Verantwortlich für das Einrichten von Routen/Ports usw.
  2. Anfrage-Handler
    • Verantwortlich für die Webserver-Aspekte der Anfrageverarbeitung, z. B. die Deserialisierung des Anfragetexts und die Serialisierung der Antwort, das Festlegen von Antwortheadern usw.
    • In diesem Beispiel verwenden Sie den im SDK bereitgestellten Standard-Handler google.cloud.aiplatform.prediction.handler.PredictionHandler.
  3. Prognosewert
    • Verantwortlich für die ML-Logik für die Verarbeitung einer Vorhersageanfrage.

Jede dieser Komponenten kann an die Anforderungen Ihres Anwendungsfalls angepasst werden. In diesem Beispiel implementieren Sie nur den Prädiktor.

Der Prädiktor ist für die ML-Logik zur Verarbeitung einer Vorhersageanfrage verantwortlich, z. B. für die benutzerdefinierte Vor- und Nachverarbeitung. Wenn Sie benutzerdefinierte Vorhersagelogik schreiben möchten, erstellen Sie eine untergeordnete Klasse der Vertex AI Predictor-Schnittstelle.

Diese Version von benutzerdefinierten Vorhersageroutinen enthält wiederverwendbare XGBoost- und Sklearn-Vorhersagemodelle. Wenn Sie jedoch ein anderes Framework verwenden möchten, können Sie eigene Modelle erstellen, indem Sie den Basisvorhersagealgorithmus unterordnen.

Unten sehen Sie ein Beispiel für den Sklearn-Prognosealgorithmus. Diesen Code müssen Sie nicht mehr schreiben, um diesen benutzerdefinierten Modellserver zu erstellen.

sklearn_predictor

Fügen Sie den folgenden Code in Ihr Notebook ein, um eine abgeleitete Klasse von SklearnPredictor zu erstellen und in eine Python-Datei in src_dir/ zu schreiben. Beachten Sie, dass wir in diesem Beispiel nur die Methoden load, preprocess und postprocess anpassen, nicht die Methode predict.

%%writefile $USER_SRC_DIR/predictor.py

import joblib
import numpy as np
import json

from google.cloud import storage
from google.cloud.aiplatform.prediction.sklearn.predictor import SklearnPredictor


class CprPredictor(SklearnPredictor):

    def __init__(self):
        return

    def load(self, artifacts_uri: str) -> None:
        """Loads the sklearn pipeline and preprocessing artifact."""

        super().load(artifacts_uri)

        # open preprocessing artifact
        with open("preprocessor.json", "rb") as f:
            self._preprocessor = json.load(f)


    def preprocess(self, prediction_input: np.ndarray) -> np.ndarray:
        """Performs preprocessing by checking if clarity feature is in abbreviated form."""

        inputs = super().preprocess(prediction_input)

        for sample in inputs:
            if sample[3] not in self._preprocessor.values():
                sample[3] = self._preprocessor[sample[3]]
        return inputs

    def postprocess(self, prediction_results: np.ndarray) -> dict:
        """Performs postprocessing by rounding predictions and converting to str."""

        return {"predictions": [f"${value}" for value in np.round(prediction_results)]}

Sehen wir uns diese Methoden einmal genauer an.

  • Mit der Methode load wird das Vorverarbeitungsartefakt geladen, in diesem Fall ein Wörterbuch, das die Werte für die Diamantenklarheit ihren Abkürzungen zuordnet.
  • Die Methode preprocess verwendet dieses Artefakt, um dafür zu sorgen, dass die Funktion zur Klarheit zum Zeitpunkt der Bereitstellung im abgekürzten Format vorliegt. Andernfalls wird der vollständige String in seine Abkürzung umgewandelt.
  • Die Methode postprocess gibt den vorhergesagten Wert als String mit einem $-Zeichen zurück und rundet den Wert.

Verwenden Sie als Nächstes das Vertex AI Python SDK, um das Image zu erstellen. Mit benutzerdefinierten Vorhersageroutinen wird das Dockerfile generiert und das Image für Sie erstellt.

from google.cloud import aiplatform

aiplatform.init(project=PROJECT_ID, location=REGION)

import os

from google.cloud.aiplatform.prediction import LocalModel

from src_dir.predictor import CprPredictor  # Should be path of variable $USER_SRC_DIR

local_model = LocalModel.build_cpr_model(
    USER_SRC_DIR,
    f"{REGION}-docker.pkg.dev/{PROJECT_ID}/{REPOSITORY}/{IMAGE}",
    predictor=CprPredictor,
    requirements_path=os.path.join(USER_SRC_DIR, "requirements.txt"),
)

Schreiben Sie eine Testdatei mit zwei Beispielen für die Vorhersage. Eine der Instanzen hat den abgekürzten Klarnamen, aber die andere muss zuerst konvertiert werden.

import json

sample = {"instances": [
  [0.23, 'Ideal', 'E', 'VS2', 61.5, 55.0, 3.95, 3.98, 2.43],
  [0.29, 'Premium', 'J', 'Internally Flawless', 52.5, 49.0, 4.00, 2.13, 3.11]]}

with open('instances.json', 'w') as fp:
    json.dump(sample, fp)

Testen Sie den Container lokal, indem Sie ein lokales Modell bereitstellen.

with local_model.deploy_to_local_endpoint(
    artifact_uri = 'model_artifacts/', # local path to artifacts
) as local_endpoint:
    predict_response = local_endpoint.predict(
        request_file='instances.json',
        headers={"Content-Type": "application/json"},
    )

    health_check_response = local_endpoint.run_health_check()

Sie können die Vorhersageergebnisse mit folgenden Tools aufrufen:

predict_response.content

7. Modell in Vertex AI bereitstellen

Nachdem Sie den Container lokal getestet haben, ist es an der Zeit, das Image in Artifact Registry zu pushen und das Modell in Vertex AI Model Registry hochzuladen.

Konfigurieren Sie zuerst Docker für den Zugriff auf Artifact Registry.

!gcloud artifacts repositories create {REPOSITORY} --repository-format=docker \
--location=us-central1 --description="Docker repository"


!gcloud auth configure-docker {REGION}-docker.pkg.dev --quiet

Übertragen Sie dann das Image per Push.

local_model.push_image()

Laden Sie das Modell hoch.

model = aiplatform.Model.upload(local_model = local_model,
                                display_name=MODEL_DISPLAY_NAME,
                                artifact_uri=f"{BUCKET_NAME}/{MODEL_ARTIFACT_DIR}",)

Nachdem das Modell hochgeladen wurde, sollte es in der Console angezeigt werden:

model_registry

Stellen Sie als Nächstes das Modell bereit, damit Sie es für Onlinevorhersagen verwenden können. Benutzerdefinierte Vorhersageroutinen funktionieren auch mit Batchvorhersagen. Wenn Ihr Anwendungsfall also keine Onlinevorhersagen erfordert, müssen Sie das Modell nicht bereitstellen.

endpoint = model.deploy(machine_type="n1-standard-2")

Testen Sie abschließend das bereitgestellte Modell, indem Sie eine Vorhersage abrufen.

endpoint.predict(instances=[[0.23, 'Ideal', 'E', 'VS2', 61.5, 55.0, 3.95, 3.98, 2.43]])

🎉 Glückwunsch! 🎉

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

  • Benutzerdefinierte Logik für die Vor- und Nachverarbeitung mit benutzerdefinierten Vorhersageroutinen schreiben

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

8. Bereinigen

Wenn Sie das in diesem Lab erstellte Notebook weiterhin verwenden möchten, sollten Sie es deaktivieren, wenn Sie es nicht verwenden. Wählen Sie in der Workbench-Benutzeroberfläche in der Google Cloud Console das Notebook und dann Beenden aus.

Wenn Sie das Notizbuch vollständig löschen möchten, klicken Sie rechts oben auf die Schaltfläche Löschen.

Stop_nb

Wenn Sie den bereitgestellten Endpunkt löschen möchten, rufen Sie in der Console den Bereich „Endpunkte“ auf, klicken Sie auf den erstellten Endpunkt und wählen Sie dann Bereitstellung des Modells am Endpunkt aufheben aus:

delete_endpoint

Wenn Sie das Container-Image löschen möchten, rufen Sie Artifact Registry auf, wählen Sie das von Ihnen erstellte Repository aus und klicken Sie auf Löschen.

delete_image

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

Speicher löschen