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 conteneur et le modèle d'inférence personnalisés en local
  • Tester le conteneur de diffusion personnalisé sur Vertex AI Predictions

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 de forêt aléatoire pour prédire le prix d'un diamant en fonction d'attributs tels que la taille, la pureté 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 écrirez également 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 d'effectuer 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 de modèle et traduit les sorties de modèle en réponses.

Avec les routines de prédiction personnalisées, Vertex AI vous fournit les composants liés au service, ce qui vous permet de vous concentrer sur votre modèle et vos 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 afin de 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, puis sélectionnez CRÉER.

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

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

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

Étape 1 : Créez un bucket Cloud Storage

Vous stockerez le modèle et les artefacts de prétraitement dans un bucket Cloud Storage. Si vous disposez déjà d'un bucket dans votre projet que vous souhaitez utiliser, 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. Veillez à 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 maintenant 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

L'ensemble des dépendances préinstallées du modèle que vous déployez sera différent de celui de votre environnement de 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. Vous testerez ensuite le modèle en local avant de le déployer sur Vertex AI pour vérifier que les environnements correspondent.

Installez les dépendances dans le notebook à l'aide de pip.

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

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

restart_kernel

Ensuite, créez les répertoires dans lesquels vous stockerez 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 maintenant 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 depuis la bibliothèque Seaborn, puis créez deux DataFrames, l'un avec les caractéristiques et l'autre avec le libellé.

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 d'arbres décisionnels

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

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

my_pipeline = make_pipeline(column_transform, regr)

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

my_pipeline.fit(x_train, y_train)

Testons 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 maintenant 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"). Au moment de la diffusion, nous voulons vérifier que les données de cette caractéristique sont également abrégées. En effet, notre modèle sait comment effectuer un encodage one-hot de "FL", mais pas de "Flawless". Vous écrirez cette logique de prétraitement personnalisée plus tard. 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 général, 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 (généré automatiquement par le SDK et stocké dans scr_dir/)
    • Serveur HTTP qui héberge le modèle
    • Responsable de la configuration des routes/ports/etc.
  2. Gestionnaire de requêtes
    • 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. Predictor
    • 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 le traitement d'une demande de prédiction, comme le prétraitement et le post-traitement personnalisés. Pour écrire une logique de prédiction personnalisée, vous devez créer une sous-classe de l'interface Vertex AI Predictor.

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 de prédicteur Sklearn. Il s'agit de 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 le SklearnPredictor et écrivez-le dans un fichier Python dans le 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 plus en détail chacune de ces méthodes.

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

Ensuite, utilisez le SDK Vertex AI pour Python pour créer l'image. Si vous utilisez des 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.

Configurez d'abord Docker pour accéder à 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 apparaître dans la console :

model_registry

Ensuite, déployez 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. À partir de l'interface utilisateur de Workbench dans la console Google Cloud, sélectionnez le notebook et cliquez sur Arrêter.

Si vous souhaitez supprimer le notebook définitivement, cliquez sur le bouton Supprimer 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 de conteneur, accédez à Artifact Registry, sélectionnez le dépôt que vous avez créé, puis cliquez sur 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