Diffuser des modèles Spark ML à l'aide de Vertex AI

Last reviewed 2024-08-14 UTC

Les data scientists et les ingénieurs en machine learning (ML) ont souvent besoin d'une architecture de diffusion suffisamment rapide pour répondre aux besoins de génération de prédictions en ligne (ou en temps réel) à partir de leurs modèles de ML. Vertex AI peut répondre à ce besoin.

Avec Vertex AI, vous pouvez diffuser des modèles à partir de divers frameworks de ML. Pour les frameworks tels que TensorFlow, PyTorch, XGBoost et scikit-learn, Vertex AI fournit des conteneurs prédéfinis dans lesquels exécuter ces modèles de ML. Si vous n'utilisez aucun de ces frameworks de ML, vous devrez créer votre propre conteneur personnalisé pour que Vertex AI l'utilise.

Ce document s'adresse aux utilisateurs qui doivent créer un conteneur personnalisé pour diffuser leurs modèles de ML Spark. Ce document comprend à la fois une description de l'architecture de diffusion nécessaire pour les conteneurs personnalisés et une implémentation de référence qui illustre cette architecture pour un modèle Spark MLlib.

Pour tirer le meilleur parti de la partie d'implémentation de référence de ce document, vous devez être familiarisé avec l'exportation de modèles Spark MLlib au format MLeap, savoir comment utiliser Vertex AI pour diffuser des prédictions et avoir de l'expérience dans l'utilisation d'images de conteneur.

Architecture

Bien que des conteneurs prédéfinis soient disponibles pour certains frameworks de ML, les utilisateurs d'autres frameworks de ML, tels que Spark, doivent créer des conteneurs personnalisés dans lesquels Vertex AI peut exécuter des prédictions. Le schéma suivant illustre l'architecture de diffusion dont vous avez besoin pour diffuser des modèles Spark MLib et d'autres modèles nécessitant un conteneur personnalisé:

Architecture de diffusion du modèle utilisé dans le document

Cette architecture comprend les composants suivants :

  • Cloud Storage: fournit un espace de stockage pour les artefacts de modèle nécessaires à l'exécution de votre modèle. Pour le modèle Spark ML utilisé dans l'implémentation de référence associée, les artefacts du modèle se composent d'un groupe MLeap et d'un schéma de modèle.
  • Cloud Build: utilise l'image du compilateur pour créer une image de conteneur personnalisé appelée image de conteneur de diffusion. Le processus de compilation compile et empaquette le code de diffusion du modèle, crée l'image du conteneur de diffusion, puis transfère l'image du conteneur de diffusion vers Artifact Registry.
  • Artifact Registry:contient les objets suivants :
    • Image de conteneur de compilateur scala-sbt utilisée par Cloud Build pour créer l'image de conteneur de diffusion.
    • Image de conteneur de diffusion créée par Cloud Build.
  • Vertex AI:contient le modèle de ML importé depuis Cloud Storage. Le modèle importé est configuré avec l'emplacement des artefacts de modèle dans Cloud Storage et avec l'emplacement de l'image de conteneur de diffusion dans Artifact Registry. Vertex AI inclut également un point de terminaison sur lequel le modèle a été déployé. Une fois le modèle déployé sur le point de terminaison, Vertex AI associe des ressources physiques au modèle afin qu'il puisse diffuser des prédictions en ligne.

Pour implémenter cette architecture de diffusion, vous devez exporter votre modèle de ML pour qu'il soit utilisé par d'autres applications et définir votre propre image de conteneur de diffusion. L'implémentation de référence fournie dans ce document fournit le code utilisé pour définir et créer l'image du conteneur de diffusion. Ce code inclut également les artefacts de modèle pour un modèle Spark ML précédemment exporté. Avec quelques modifications de configuration, vous pouvez utiliser cette implémentation de référence pour diffuser vos propres modèles de ML Spark.

Toutefois, vous pouvez implémenter cette architecture de diffusion par vous-même et ne pas utiliser l'implémentation de référence. Si vous décidez d'implémenter votre propre architecture, procédez comme suit:

  • Exportez votre modèle afin qu'il puisse être utilisé par d'autres applications. Ce processus dépend des frameworks et des outils de ML que vous utilisez. Par exemple, vous pouvez choisir d'exporter vos modèles Spark MLlib en créant un groupe MLeap, comme décrit dans l'implémentation de référence. Vous pouvez consulter d'autres exemples d'exportation de modèles dans Exporter des artefacts de modèle pour la prédiction.
  • Concevez votre image de conteneur de diffusion pour qu'elle réponde aux exigences concernant les conteneurs personnalisés qui la rendent compatible avec Vertex AI. Le code peut être dans le langage de programmation de votre choix.
  • Emballez le code dans un format de fichier de package compatible avec le langage de programmation que vous avez utilisé. Par exemple, vous pouvez utiliser un fichier JAR pour le code Java ou un paquet Python pour le code Python.
  • Créez une image de conteneur personnalisée capable de diffuser votre code de mode personnalisé.

Implémentation de référence

L'implémentation de référence suivante fournit un modèle Spark MLlib qui prédit les espèces d'iris en fonction de la longueur et de la largeur des sépales et des pétales de la fleur.

Vous trouverez le modèle utilisé dans cette implémentation dans le répertoire example_model du dépôt vertex-ai-spark-ml-serving.git. Le répertoire contient les artefacts de modèle utilisés par le conteneur de diffusion pour exécuter des prédictions, et inclut les fichiers suivants:

  • Le fichier example_model/model.zip est un modèle de régression logistique créé à l'aide de Spark MLlib, entraîné à l'aide de l'ensemble de données Iris et converti en bundle MLeap. Le modèle prédit la variété des iris en utilisant la longueur et la largeur des sépales et des pétales des fleurs.
  • Le fichier example_model/schema.json est un fichier JSON qui décrit le schéma du modèle. Le schéma du modèle décrit les champs d'entrée attendus pour les instances de prédiction et les champs de sortie pour les résultats de prédiction requis pour le schéma MLeap.

Utiliser votre propre modèle Mlib

Pour utiliser votre propre modèle avec cette implémentation de référence, assurez-vous d'abord que votre modèle Spark MLlib a été exporté vers un groupe MLeap. Pour diffuser votre modèle Spark MLlib, vous devez fournir les artefacts de modèle appropriés: le bundle MLeap et le schéma du modèle.

Bundle MLeap

Le conteneur de diffusion détermine l'emplacement du bundle MLeap à l'aide de la variable d'environnement AIP_STORAGE_URI transmise de Vertex AI au conteneur au démarrage. La valeur de la variable AIP_STORAGE_URI est spécifiée lorsque vous importez le modèle dans Vertex AI.

Schéma de modèle

Le schéma de modèle décrit les caractéristiques d'entrée et le résultat de la prédiction d'un modèle. Le schéma de modèle est représenté à l'aide de données JSON. Voici le schéma utilisé dans cette mise en œuvre de référence pour prédire les espèces d'iris en fonction de la longueur et de la largeur de ses sépales et de ses pétales:

{
  "input": [
    {
      "name": "sepal_length",
      "type": "FLOAT"
    },
    {
      "name": "sepal_width",
      "type": "FLOAT"
    },
    {
      "name": "petal_length",
      "type": "FLOAT"
    },
    {
      "name": "petal_width",
      "type": "FLOAT"
    }
  ],
  "output": [
    {
      "name": "probability",
      "type": "DOUBLE",
      "struct": "VECTOR"
    }
  ]
}

Dans le schéma de modèle, le tableau input contient les champs d'entrée (colonnes) à destination du modèle, tandis que le tableau output contient les champs de sortie (colonnes) à renvoyer à partir du modèle. Dans les deux tableaux, chaque objet du tableau contient les propriétés suivantes :

  • name : nom du champ (colonne)
  • type : type de champ (colonne) Les types valides sont les suivants : BOOLEAN, BYTE, DOUBLE, FLOAT, INTEGER, LONG, SHORT et STRING.
  • (facultatif) struct : structure de champ, telle qu'une valeur scalaire ou un tableau. Les structures valides sont BASIC (type scalaire), ARRAY (Array Spark) et VECTOR (Spark DenseVector). BASIC est utilisé si le champ struct n'est pas présent.

Pour transmettre le schéma de modèle au conteneur de diffusion, vous pouvez appliquer l'une des méthodes suivantes :

  • Spécifiez les données JSON qui définissent le schéma dans la variable d'environnement MLEAP_SCHEMA. La variable d'environnement MLEAP_SCHEMA doit contenir les données JSON proprement dites, et non un chemin d'accès à un fichier contenant le schéma JSON.
  • Stockez les données JSON dans un fichier appelé schema.json et mettez-le à la disposition du conteneur à l'emplacement ${AIP_STORAGE_URI}/schema.json. C'est la méthode utilisée pour l'exemple de modèle MLib fourni avec cette documentation.

Si vous utilisez les deux méthodes pour transmettre le schéma du modèle au conteneur de diffusion, les données JSON stockées dans la variable d'environnement MLEAP_SCHEMA ont la priorité.

Coûts

Cette implémentation de référence utilise les composants facturables de Google Cloud suivants:

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût.

Une fois que vous aurez terminé cette mise en œuvre, vous pourrez éviter de continuer à payer des frais en supprimant les ressources créées. Pour en savoir plus, consultez la section Effectuer un nettoyage.

Avant de commencer

  1. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  2. Make sure that billing is enabled for your Google Cloud project.

  3. Enable the Vertex AI, Cloud Build, Cloud Storage, and Artifact Registry APIs.

    Enable the APIs

  4. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

  5. Recherchez votre ID de projet et définissez-le dans Cloud Shell.
    export PROJECT_ID=YOUR_PROJECT_ID
    gcloud config set project ${PROJECT_ID}
    

    en remplaçant YOUR_PROJECT_ID par l'ID de votre projet :

Créer l'image de compilateur scala-sbt

Vous utilisez Cloud Build avec le compilateur de la communauté scala-sbt pour créer l'image de conteneur de diffusion. Ce processus de compilation dépend de la présence de l'image de compilateur sbt-scala dans Container Registry pour votre projet.

  1. Dans Cloud Shell, clonez le dépôt cloud-builders-community :

    git clone https://github.com/GoogleCloudPlatform/cloud-builders-community.git
    
  2. Accédez au répertoire du projet :

    cd cloud-builders-community/scala-sbt
    
  3. Créez l'image à l'aide du compilateur scala-sbt et transférez-la vers Container Registry :

    gcloud builds submit .
    

Créer l'image de conteneur de diffusion

Vertex AI utilise le conteneur de diffusion pour exécuter des requêtes de prédiction pour l'exemple de modèle. La première étape de la création de l'image de conteneur de diffusion consiste à créer un dépôt Docker dans Artifact Registry dans lequel stocker l'image. Vous devez ensuite autoriser Vertex AI à extraire l'image de conteneur de diffusion du dépôt. Une fois le dépôt créé et les autorisations accordées, vous pouvez créer l'image de conteneur de diffusion et la transférer vers Artifact Registry.

  1. Dans Cloud Shell, créez un dépôt Docker dans Artifact Registry :

    REPOSITORY="vertex-ai-prediction"
    LOCATION="us-central1"
    
    gcloud artifacts repositories create $REPOSITORY \
        --repository-format=docker \
        --location=$LOCATION
    
  2. Attribuez le rôle de lecteur Artifact Registry à l'agent de service Vertex AI:

    PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID \
        --format="value(projectNumber)")
    SERVICE_ACCOUNT="service-$PROJECT_NUMBER@gcp-sa-aiplatform.iam.gserviceaccount.com"
    
    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member="serviceAccount:$SERVICE_ACCOUNT" \
        --role="roles/artifactregistry.reader"
    
  3. Clonez le dépôt spark-ml-serving :

    git clone https://github.com/GoogleCloudPlatform/vertex-ai-spark-ml-serving.git
    
  4. Accédez au répertoire du projet :

    cd vertex-ai-spark-ml-serving
    
  5. Créez l'image de conteneur de diffusion dans votre projet :

    IMAGE=spark-ml-serving
    
    gcloud builds submit --config=cloudbuild.yaml \
        --substitutions="_LOCATION=$LOCATION,_REPOSITORY=$REPOSITORY,_IMAGE=$IMAGE" .
    

    Le fichier cloudbuild.yaml spécifie deux compilateurs : le compilateur scala-sbt et le compilateur d'images docker. Cloud Build utilise le compilateur scala-sbt pour compiler le code de diffusion du modèle à partir de Cloud Storage, puis empaqueter le code compilé dans un fichier JAR exécutable. Cloud Build utilise le compilateur docker pour créer l'image de conteneur de diffusion contenant le fichier JAR. Une fois l'image de conteneur de diffusion créée, elle est transférée vers Artifact Registry.

Importer le modèle dans Vertex AI

Le conteneur de diffusion lit les artefacts de modèle à partir de Cloud Storage. Vous devez créer un emplacement de stockage pour ces artefacts avant d'importer le modèle dans Vertex AI. Lorsque vous importez ensuite le modèle, vous avez besoin de l'emplacement de stockage de l'artefact de modèle et de l'image de conteneur de diffusion dans Artifact Registry.

  1. Dans Cloud Shell, créez un bucket pour les artefacts du modèle :

    REGION="us-central1"
    BUCKET="YOUR_BUCKET_NAME"
    gcloud storage buckets create gs://$BUCKET --location=$REGION
    

    Remplacez YOUR_BUCKET_NAME par le nom de votre bucket :

  2. Copiez les artefacts de modèle dans le bucket :

    gcloud storage cp example_model/* gs://$BUCKET/example_model/
    
  3. Importez le modèle dans Vertex AI :

    DISPLAY_NAME="iris-$(date +'%Y%m%d%H%M%S')"
    IMAGE_URI="${LOCATION}-docker.pkg.dev/$PROJECT_ID/${REPOSITORY}/${IMAGE}"
    ARTIFACT_URI="gs://$BUCKET/example_model/"
    
    gcloud ai models upload \
        --region=$REGION \
        --display-name=$DISPLAY_NAME \
        --container-image-uri=$IMAGE_URI \
        --artifact-uri=$ARTIFACT_URI \
        --container-health-route="/health" \
        --container-predict-route="/predict"
    

    Dans la commande gcloud ai models upload, la valeur du paramètre --artifact-uri spécifie la valeur de la variable AIP_STORAGE_URI. Cette variable fournit l'emplacement du bundle MLeap importé dans Vertex AI.

Déployer le modèle sur un nouveau point de terminaison

Pour que Vertex AI exécute les prédictions, le modèle importé doit être déployé sur un point de terminaison. Vous avez besoin de l'ID du point de terminaison et de l'ID du modèle lorsque vous déployez le modèle.

  1. Dans Cloud Shell, créez le point de terminaison du modèle :

    gcloud ai endpoints create \
        --region=$REGION \
        --display-name=$DISPLAY_NAME
    

    La création du point de terminaison de l'outil de ligne de commande gcloud peut prendre quelques secondes.

  2. Obtenez l'ID du point de terminaison que vous venez de créer :

    ENDPOINT_ID=$(gcloud ai endpoints list \
        --region=$REGION \
        --filter=display_name=$DISPLAY_NAME \
        --format='value(name)')
    
    # Print ENDPOINT_ID to the console
    echo "Your endpoint ID is: $ENDPOINT_ID"
    
  3. Obtenez l'ID du modèle que vous avez importé dans la section Importer le modèle dans Vertex AI:

    MODEL_ID=$(gcloud ai models list \
        --region=$REGION \
        --filter=display_name=$DISPLAY_NAME \
        --format='value(name)')
    
    # Print MODEL_ID to the console
    echo "Your model ID is: $MODEL_ID"
    
  4. Déployez le modèle sur le point de terminaison :

    gcloud ai endpoints deploy-model $ENDPOINT_ID \
        --region=$REGION \
        --model=$MODEL_ID \
        --display-name=$DISPLAY_NAME \
        --traffic-split="0=100"
    

    La commande gcloud déploie le modèle sur le point de terminaison. Les valeurs par défaut sont utilisées pour le type de ressource de la machine, le nombre minimal et maximal de nœuds et d'autres options de configuration. Pour en savoir plus sur les options de déploiement des modèles, consultez la documentation de Vertex AI.

Tester le point de terminaison

Une fois le modèle déployé sur le point de terminaison, vous pouvez tester votre implémentation. Pour tester le point de terminaison, vous pouvez utiliser l'exemple de client inclus avec le code d'implémentation de référence. L'exemple de client génère des instances de prédiction et envoie des requêtes de prédiction au point de terminaison. Chaque instance de prédiction contient des valeurs aléatoires pour sepal_length, sepal_width, petal_length et petal_width. Par défaut, l'exemple de client combine plusieurs instances de prédiction dans une seule requête. La réponse du point de terminaison inclut une prédiction pour chaque instance envoyée dans la requête. La prédiction contient les probabilités pour chaque classe de l'ensemble de données Iris (setosa, versicolor et virginica).

  • Dans Cloud Shell, exécutez l'exemple de client de prédiction :

    cd example_client
    ./run_client.sh --project $PROJECT_ID \
        --location $LOCATION \
        --endpoint $ENDPOINT_ID
    

    Lorsque vous exécutez le script pour la première fois, il crée un environnement virtuel Python et installe des dépendances. Après avoir installé les dépendances, le script exécute l'exemple de client. Pour chaque requête, le client imprime les instances de prédiction et les probabilités de classe correspondantes sur le terminal. Voici un extrait de la sortie :

    Sending 10 asynchronous prediction requests with 3 instances per request ...
    
    ==> Response from request #10:
    
    Instance 1:     sepal_length:   5.925825137450266
                    sepal_width:    4.5047557888651
                    petal_length:   1.0432434310300223
                    petal_width:    0.5050397721287457
    
    Prediction 1:   setosa:         0.2036041134824573
                    versicolor:     0.6062980065549213
                    virginica:      0.1900978799626214
    
    Instance 2:     sepal_length:   6.121228622484405
                    sepal_width:    3.406317728235072
                    petal_length:   3.178583759980504
                    petal_width:    2.815141143581328
    
    Prediction 2:   setosa:         0.471811302254083
                    versicolor:     0.2063720436033448
                    virginica:      0.3218166541425723
    
    Instance 3:     sepal_length:   7.005781590327274
                    sepal_width:    2.532116893508745
                    petal_length:   2.6351337947193474
                    petal_width:    2.270855223519198
    
    Prediction 3:   setosa:         0.453579051699638
                    versicolor:     0.2132869980698818
                    virginica:      0.3331339502304803
    

Effectuer un nettoyage

Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez chaque ressource individuellement.

Supprimer le projet

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Supprimer des ressources individuelles

  1. Dans Cloud Shell, annulez le déploiement du modèle sur le point de terminaison :

    DEPLOYED_MODEL_ID=$(gcloud ai endpoints describe $ENDPOINT_ID \
        --region=$REGION \
        --format='value(deployedModels.id)')
    
    gcloud ai endpoints undeploy-model $ENDPOINT_ID \
        --region=$REGION \
        --deployed-model-id=$DEPLOYED_MODEL_ID
    
  2. Supprimez le point de terminaison :

    gcloud ai endpoints delete $ENDPOINT_ID \
        --region=$REGION \
        --quiet
    
  3. Supprimez le modèle :

    gcloud ai models delete $MODEL_ID \
        --region=$REGION
    
  4. Supprimez l'image de conteneur de diffusion :

    gcloud artifacts docker images delete \
        $LOCATION-docker.pkg.dev/$PROJECT_ID/$REPOSITORY/$IMAGE \
        --delete-tags \
        --quiet
    
  5. Supprimez le conteneur de compilateur scala-sbt :

    gcloud container images delete gcr.io/$PROJECT_ID/scala-sbt \
        --force-delete-tags \
        --quiet
    
  6. Supprimez tous les buckets Cloud Storage dont vous n'avez plus besoin :

    gcloud storage rm YOUR_BUCKET_NAME --recursive
    

    La suppression d'un bucket entraîne également la suppression de tous les objets qu'il contient. Une fois supprimés, les buckets et les objets ne peuvent pas être récupérés.

Étape suivante