Vertex AI: utiliser des routines de prédiction personnalisées avec Sklearn pour prétraiter et post-traiter les données afin d'obtenir des prédictions

1. Présentation

Dans cet atelier, vous allez apprendre à utiliser des routines de prédiction personnalisées sur Vertex AI pour écrire une logique de prétraitement et de post-traitement personnalisée. Bien que cet exemple utilise Scikit-learn, les routines de prédiction personnalisées peuvent fonctionner avec d'autres frameworks de ML Python tels que XGBoost, PyTorch et TensorFlow.

Objectifs

Vous allez apprendre à effectuer les opérations suivantes :

  • Écrire une logique de prédiction personnalisée avec des routines de prédiction personnalisées
  • Tester le modèle et le conteneur de diffusion personnalisé en local
  • Tester le conteneur de diffusion personnalisé dans Vertex AI Prediction

Le coût total d'exécution de cet atelier sur Google Cloud est d'environ 1$.

2. Présentation de Vertex AI

Cet atelier utilise la toute dernière offre de produits d'IA de Google Cloud. Vertex AI simplifie l'expérience de développement en intégrant toutes les offres de ML de Google Cloud. Auparavant, les modèles entraînés avec AutoML et les modèles personnalisés étaient accessibles depuis des services distincts. La nouvelle offre regroupe ces deux types de modèles mais aussi d'autres nouveaux produits en une seule API. Vous pouvez également migrer des projets existants vers Vertex AI.

Vertex AI comprend de nombreux produits différents qui permettent de gérer les workflows de ML de bout en bout. Cet atelier se concentre sur Predictions et Workbench.

Présentation des produits Vertex

3. Présentation du cas d'utilisation

Cas d'utilisation

Dans cet atelier, vous allez créer un modèle de régression par forêt aléatoire pour prédire le prix d'un diamant en fonction d'attributs tels que la taille, la clarté et la taille.

Vous allez écrire une logique de prétraitement personnalisée pour vérifier que les données au moment de la diffusion sont au format attendu par le modèle. Vous allez également écrire une logique de post-traitement personnalisée pour arrondir les prédictions et les convertir en chaînes. Pour écrire cette logique, vous utiliserez des routines de prédiction personnalisées.

Présentation des routines de prédiction personnalisées

Les conteneurs prédéfinis Vertex AI gèrent les requêtes de prédiction en effectuant l'opération de prédiction du framework de machine learning. Avant les routines de prédiction personnalisées, si vous souhaitiez prétraiter l'entrée avant l'exécution de la prédiction ou post-traiter la prédiction du modèle avant de renvoyer le résultat, vous deviez créer un conteneur personnalisé.

Pour créer un conteneur de diffusion personnalisé, vous devez écrire un serveur HTTP qui encapsule le modèle entraîné, traduit les requêtes HTTP en entrées du modèle et traduit les sorties du modèle en réponses.

Avec les routines de prédiction personnalisées, Vertex AI vous fournit les composants liés à l'inférence pour que vous puissiez vous concentrer sur votre modèle et les transformations de données.

4. Configurer votre environnement

Pour suivre cet atelier de programmation, vous aurez besoin d'un projet Google Cloud Platform dans lequel la facturation est activée. Pour créer un projet, suivez ces instructions.

Étape 1 : Activez l'API Compute Engine

Accédez à Compute Engine et cliquez sur Activer si ce n'est pas déjà fait. Vous en aurez besoin pour créer votre instance de notebook.

Étape 2 : Activez l'API Artifact Registry

Accédez à Artifact Registry et cliquez sur Activer si ce n'est pas déjà fait. Vous l'utiliserez pour créer un conteneur de diffusion personnalisé.

Étape 3 : Activez l'API Vertex AI

Accédez à la section Vertex AI de Cloud Console, puis cliquez sur Activer l'API Vertex AI.

Tableau de bord Vertex AI

Étape 4 : Créez une instance Vertex AI Workbench

Dans la section Vertex AI de Cloud Console, cliquez sur Workbench :

Menu Vertex AI

Activez l'API Notebooks si ce n'est pas déjà fait.

Notebook_api

Une fois l'API activée, cliquez sur INSTANCES (INSTANCES), puis sélectionnez CREATE NEW (CRÉER).

Acceptez les options par défaut et cliquez sur Créer.

Lorsque l'instance est prête, cliquez sur OPEN JUPYTERLAB (OUVRIR JUPYTERLAB) pour l'ouvrir.

5. Rédiger le code d'entraînement

Étape 1: Créez un bucket Cloud Storage

Vous allez stocker le modèle et les artefacts de prétraitement dans un bucket Cloud Storage. Si vous souhaitez utiliser un bucket déjà présent dans votre projet, vous pouvez ignorer cette étape.

Depuis le lanceur, ouvrez une nouvelle session de terminal.

Open_terminal

Depuis votre terminal, exécutez la commande suivante afin de définir une variable d'environnement pour votre projet, en veillant à remplacer your-cloud-project par l'ID de votre projet:

PROJECT_ID='your-cloud-project'

Ensuite, exécutez la commande suivante dans votre terminal pour créer un bucket dans votre projet.

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

Étape 2: Entraîner le modèle

Dans le terminal, créez un répertoire appelé cpr-codelab et utilisez la commande cd pour y accéder.

mkdir cpr-codelab
cd cpr-codelab

Dans l'explorateur de fichiers, accédez au nouveau répertoire cpr-codelab, puis utilisez le lanceur pour créer un notebook Python 3 nommé task.ipynb.

file_browser

Votre répertoire cpr-codelab devrait se présenter comme suit:

+ cpr-codelab/
    + task.ipynb

Dans le notebook, collez le code suivant.

Commencez par écrire un fichier requirements.txt.

%%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

Le modèle que vous déployez aura un ensemble de dépendances préinstallées différent de celui de votre environnement Notebook. Pour cette raison, vous devez lister toutes les dépendances du modèle dans requirements.txt, puis utiliser pip pour installer exactement les mêmes dépendances dans le notebook. Plus tard, vous testerez le modèle localement avant de le déployer sur Vertex AI pour vérifier que les environnements correspondent.

Pip installe les dépendances dans le notebook.

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

Notez que vous devrez redémarrer le noyau une fois l'installation de pip terminée.

restart_kernel

Ensuite, créez les répertoires dans lesquels vous allez stocker le modèle et les artefacts de prétraitement.

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

Votre répertoire cpr-codelab devrait se présenter comme suit:

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

Maintenant que la structure de répertoires est configurée, il est temps d'entraîner un modèle.

Commencez par importer les bibliothèques.

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)

Définissez ensuite les variables suivantes. Veillez à remplacer PROJECT_ID par l'ID de votre projet et BUCKET_NAME par le bucket que vous avez créé à l'étape précédente.

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

Chargez les données de la bibliothèque Seaborn, puis créez deux DataFrames, l'un avec les caractéristiques et l'autre avec l'étiquette.

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

label = 'price'

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

Examinons les données d'entraînement. Vous pouvez voir que chaque ligne représente un losange.

x_train.head()

Et les étiquettes, qui sont les prix correspondants.

y_train.head()

Définissez maintenant une transformation de colonne sklearn pour effectuer un encodage one-hot des caractéristiques catégorielles et ajuster les caractéristiques numériques.

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

Définir le modèle de forêt aléatoire

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

Créez ensuite un pipeline sklearn. Cela signifie que les données transmises à ce pipeline seront d'abord encodées/mises à l'échelle, puis transmises au modèle.

my_pipeline = make_pipeline(column_transform, regr)

Adapter le pipeline aux données d'entraînement

my_pipeline.fit(x_train, y_train)

Essayons le modèle pour nous assurer qu'il fonctionne comme prévu. Appelez la méthode predict sur le modèle en transmettant un échantillon de test.

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

Nous pouvons maintenant enregistrer le pipeline dans le répertoire model_artifacts et le copier dans le bucket Cloud Storage.

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

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

Étape 3: Enregistrer un artefact de prétraitement

Vous allez ensuite créer un artefact de prétraitement. Cet artefact sera chargé dans le conteneur personnalisé au démarrage du serveur de modèles. Votre artefact de prétraitement peut se présenter sous n'importe quel format, par exemple un fichier pickle, mais dans ce cas, vous allez écrire un dictionnaire dans un fichier JSON.

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

La caractéristique clarity de nos données d'entraînement était toujours au format abrégé (par exemple, "FL" au lieu de "Flawless"). Lors de l'inférence, nous voulons vérifier que les données de cette caractéristique sont également abrégées. En effet, notre modèle sait comment encoder "FL" à chaud, mais pas "Flawless". Vous écrirez cette logique de prétraitement personnalisée ultérieurement. Pour le moment, il vous suffit d'enregistrer cette table de conversion dans un fichier JSON, puis de l'écrire dans le bucket Cloud Storage.

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}/

Votre répertoire cpr-codelab local devrait maintenant se présenter comme suit:

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

6. Créer un conteneur de diffusion personnalisé à l'aide du serveur de modèles CPR

Maintenant que le modèle a été entraîné et que l'artefact de prétraitement a été enregistré, il est temps de créer le conteneur de diffusion personnalisé. En règle générale, la création d'un conteneur de diffusion nécessite d'écrire du code de serveur de modèle. Toutefois, avec les routines de prédiction personnalisées, Vertex AI Predictions génère un serveur de modèle et crée une image de conteneur personnalisée pour vous.

Un conteneur de diffusion personnalisé contient les trois éléments de code suivants:

  1. Serveur de modèle (il sera généré automatiquement par le SDK et stocké dans scr_dir/)
    • Serveur HTTP qui héberge le modèle
    • Chargé de la configuration des routes, des ports, etc.
  2. Gestionnaire de requêtes
    • Il est responsable des aspects du serveur Web liés au traitement d'une requête, tels que la désérialisation du corps de la requête, la sérialisation de la réponse, la définition des en-têtes de réponse, etc.
    • Dans cet exemple, vous utiliserez le gestionnaire par défaut, google.cloud.aiplatform.prediction.handler.PredictionHandler, fourni dans le SDK.
  3. Prédicteur
    • Responsable de la logique de ML pour le traitement d'une requête de prédiction.

Chacun de ces composants peut être personnalisé en fonction des exigences de votre cas d'utilisation. Dans cet exemple, vous n'implémenterez que le prédicteur.

Le prédicteur est responsable de la logique de ML pour traiter une requête de prédiction, comme le prétraitement et le posttraitement personnalisés. Pour écrire une logique de prédiction personnalisée, vous sous-classez l'interface du prédicteur Vertex AI.

Cette version des routines de prédiction personnalisées est fournie avec des prédicteurs XGBoost et Sklearn réutilisables. Toutefois, si vous devez utiliser un autre framework, vous pouvez créer le vôtre en sous-classant le prédicteur de base.

Vous trouverez ci-dessous un exemple du prédicteur Sklearn. Voici tout le code que vous devez écrire pour créer ce serveur de modèle personnalisé.

sklearn_predictor

Dans votre notebook, collez le code suivant pour sous-classer SklearnPredictor et écrivez-le dans un fichier Python dans src_dir/. Notez que dans cet exemple, nous ne personnalisons que les méthodes load, preprocess et postprocess, et non la méthode 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)]}

Examinons chacune de ces méthodes plus en détail.

  • La méthode load se charge dans l'artefact de prétraitement, qui est dans ce cas un dictionnaire mappant les valeurs de clarté des diamants à leurs abréviations.
  • La méthode preprocess utilise cet artefact pour s'assurer qu'au moment de la diffusion, la fonctionnalité de clarté est au format abrégé. Sinon, il convertit la chaîne complète en abréviation.
  • La méthode postprocess renvoie la valeur prédite sous forme de chaîne avec un signe $ et arrondit la valeur.

Ensuite, utilisez le SDK Vertex AI pour Python pour créer l'image. À l'aide de routines de prédiction personnalisées, le fichier Dockerfile sera généré et l'image sera créée automatiquement.

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"),
)

Écrivez un fichier de test avec deux exemples de prédiction. L'une des instances porte le nom abrégé, mais l'autre doit d'abord être convertie.

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)

Testez le conteneur localement en déployant un modèle local.

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()

Vous pouvez afficher les résultats de la prédiction avec :

predict_response.content

7. Déployer le modèle dans Vertex AI

Maintenant que vous avez testé le conteneur localement, il est temps de transférer l'image vers Artifact Registry et d'importer le modèle dans Vertex AI Model Registry.

Commencez par configurer Docker pour qu'il accède à 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

Transférez ensuite l'image.

local_model.push_image()

Importez le modèle.

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

Une fois le modèle importé, il doit s'afficher dans la console:

model_registry

Déployez ensuite le modèle pour pouvoir l'utiliser pour les prédictions en ligne. Les routines de prédiction personnalisées fonctionnent également avec la prédiction par lot. Par conséquent, si votre cas d'utilisation ne nécessite pas de prédictions en ligne, vous n'avez pas besoin de déployer le modèle.

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

Enfin, testez le modèle déployé en obtenant une prédiction.

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

🎉 Félicitations ! 🎉

Vous savez désormais utiliser Vertex AI pour :

  • Écrire une logique de prétraitement et de post-traitement personnalisée avec des routines de prédiction personnalisées

Pour en savoir plus sur les différentes parties de Vertex AI, consultez la documentation.

8. Nettoyage

Si vous souhaitez continuer à utiliser le notebook que vous avez créé dans cet atelier, nous vous recommandons de le désactiver quand vous ne vous en servez pas. Dans l'interface utilisateur de Workbench dans la console Google Cloud, sélectionnez le notebook, puis Arrêter.

Si vous souhaitez supprimer le notebook définitivement, cliquez sur le bouton Supprimer situé en haut à droite.

Stop_nb

Pour supprimer le point de terminaison que vous avez déployé, accédez à la section "Points de terminaison" de la console, cliquez sur le point de terminaison que vous avez créé, puis sélectionnez Annuler le déploiement du modèle sur le point de terminaison:

delete_endpoint

Pour supprimer l'image du conteneur, accédez à Artifact Registry, sélectionnez le dépôt que vous avez créé, puis Supprimer.

delete_image

Pour supprimer le bucket de stockage, utilisez le menu de navigation de la console Cloud pour accéder à Stockage, sélectionnez votre bucket puis cliquez sur Supprimer:

Supprimer l&#39;espace de stockage