Créer et déployer un modèle avec Vertex AI

1. Présentation

Dans cet atelier, vous allez apprendre à utiliser Vertex AI, la nouvelle plate-forme de ML gérée de Google Cloud, pour créer des workflows de ML de bout en bout. Vous apprendrez à passer des données brutes au modèle déployé. Cet atelier sera également prêt à développer et mettre en production vos propres projets de ML avec Vertex AI. Dans cet atelier, nous allons créer une image Docker personnalisée à l'aide de Cloud Shell afin d'illustrer les conteneurs personnalisés pour l'entraînement avec Vertex AI.

Même si nous utilisons TensorFlow pour le code du modèle, vous pouvez facilement le remplacer par un autre framework.

Objectifs

Vous allez apprendre à effectuer les opérations suivantes :

  • Créer et conteneuriser le code d'entraînement du modèle à l'aide de Cloud Shell
  • Envoyer un job d'entraînement de modèle personnalisé à Vertex AI
  • Déployer le modèle entraîné sur un point de terminaison, et utiliser ce point de terminaison pour obtenir des prédictions

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

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. Pour envoyer un commentaire, consultez la page d'assistance.

Vertex inclut de nombreux outils différents pour vous aider à chaque étape du workflow de ML, comme vous pouvez le voir dans le schéma ci-dessous. Nous allons nous concentrer sur l'utilisation de Vertex Training et de Vertex Prediction, qui sont présentés ci-dessous.

Services Vertex

3. Configurer votre environnement

Configuration de l'environnement au rythme de chacun

Connectez-vous à la console Cloud, puis créez un projet ou réutilisez un projet existant. (Si vous ne possédez pas encore de compte Gmail ou Google Workspace, vous devez en créer un.)

Mémorisez l'ID du projet. Il s'agit d'un nom unique permettant de différencier chaque projet Google Cloud (le nom ci-dessus est déjà pris ; vous devez en trouver un autre).

Vous devez ensuite activer la facturation dans Cloud Console pour pouvoir utiliser les ressources Google Cloud.

L'exécution de cet atelier de programmation est très peu coûteuse, voire gratuite. Veillez à suivre les instructions de la section "Nettoyer" qui indique comment désactiver les ressources afin d'éviter les frais une fois ce tutoriel terminé. Les nouveaux utilisateurs de Google Cloud peuvent participer au programme d'essai sans frais pour bénéficier d'un crédit de 300$.

Étape 1: Démarrez Cloud Shell

Dans cet atelier, vous allez travailler dans une session Cloud Shell, un interpréteur de commandes hébergé par une machine virtuelle exécutée dans le cloud de Google. Vous pourriez tout aussi facilement effectuer les tâches de cette section en local sur votre propre ordinateur, mais le fait d'utiliser Cloud Shell permet à chacun de bénéficier d'une expérience reproductible dans un environnement cohérent. Après l'atelier, libre à vous de reproduire cette section sur votre ordinateur.

Autoriser Cloud Shell

Activer Cloud Shell

Dans l'angle supérieur droit de la console Cloud, cliquez sur le bouton ci-dessous pour activer Cloud Shell:

Activer Cloud Shell

Si vous n'avez jamais démarré Cloud Shell auparavant, un écran intermédiaire (en dessous de la ligne de flottaison) vous explique de quoi il s'agit. Dans ce cas, cliquez sur Continuer (elle ne s'affichera plus). Voici à quoi il ressemble :

Configuration de Cloud Shell

Le provisionnement et la connexion à Cloud Shell ne devraient pas prendre plus de quelques minutes.

Cloud Shell init

Cette machine virtuelle contient tous les outils de développement dont vous avez besoin. Elle comprend un répertoire d'accueil persistant de 5 Go et s'exécute sur Google Cloud, ce qui améliore nettement les performances du réseau et l'authentification. Vous pouvez réaliser une grande partie, voire la totalité, des activités de cet atelier dans un simple navigateur ou sur votre Chromebook.

Une fois connecté à Cloud Shell, vous êtes en principe authentifié et le projet est défini avec votre ID de projet.

Exécutez la commande suivante dans Cloud Shell pour vérifier que vous êtes authentifié :

gcloud auth list

Résultat de la commande

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`

Exécutez la commande suivante dans Cloud Shell pour vérifier que la commande gcloud connaît votre projet:

gcloud config list project

Résultat de la commande

[core]
project = <PROJECT_ID>

Si vous obtenez un résultat différent, exécutez cette commande :

gcloud config set project <PROJECT_ID>

Résultat de la commande

Updated property [core/project].

Cloud Shell comporte quelques variables d'environnement, y compris GOOGLE_CLOUD_PROJECT qui contient le nom de notre projet Cloud actuel. Nous l'utiliserons à différents endroits tout au long de cet atelier. Pour la voir, exécutez la commande suivante :

echo $GOOGLE_CLOUD_PROJECT

Étape 2 : Activez les API

Dans les étapes suivantes, vous verrez où ces services sont nécessaires (et pourquoi). Pour le moment, exécutez la commande suivante afin d'autoriser votre projet à accéder aux services Compute Engine, Container Registry et Vertex AI:

gcloud services enable compute.googleapis.com         \
                       containerregistry.googleapis.com  \
                       aiplatform.googleapis.com

Un message semblable à celui qui suit s'affiche pour vous indiquer que l'opération s'est correctement déroulée :

Operation "operations/acf.cc11852d-40af-47ad-9d59-477a12847c9e" finished successfully.

Étape 3: Créez un bucket Cloud Storage

Pour exécuter un job d'entraînement sur Vertex AI, nous avons besoin d'un bucket de stockage afin de stocker les ressources de modèle enregistrées. Exécutez les commandes suivantes dans votre terminal Cloud Shell afin de créer un bucket :

BUCKET_NAME=gs://$GOOGLE_CLOUD_PROJECT-bucket
gsutil mb -l us-central1 $BUCKET_NAME

Étape 4: Alias Python 3

Le code de cet atelier utilise Python 3. Pour vous assurer d'utiliser Python 3 lorsque vous exécuterez les scripts que vous allez créer dans cet atelier, créez un alias en exécutant la commande suivante dans Cloud Shell:

alias python=python3

Le modèle que nous allons entraîner et exécuter dans cet atelier s'appuie sur ce tutoriel issu de la documentation TensorFlow. Le tutoriel utilise l'ensemble de données Auto MPG de Kaggle pour prédire la consommation de carburant d'un véhicule.

4. Conteneuriser le code d'entraînement

Nous allons envoyer ce job d'entraînement à Vertex en plaçant le code d'entraînement dans un conteneur Docker et en transférant ce conteneur vers Google Container Registry. Cette approche nous permet d'entraîner un modèle créé avec n'importe quel framework.

Étape 1: Configurez les fichiers

Pour commencer, dans le terminal de Cloud Shell, exécutez les commandes suivantes pour créer les fichiers dont nous avons besoin pour notre conteneur Docker:

mkdir mpg
cd mpg
touch Dockerfile
mkdir trainer
touch trainer/train.py

Vous devez maintenant disposer d'un répertoire mpg/ semblable à celui-ci:

+ Dockerfile
+ trainer/
    + train.py

Pour afficher et modifier ces fichiers, nous allons utiliser l'éditeur de code intégré à Cloud Shell. Vous pouvez passer de l'éditeur au terminal en cliquant sur le bouton situé dans la barre de menu en haut à droite de Cloud Shell:

Passer à l&#39;éditeur dans Cloud Shell

Étape 2 : Créez un Dockerfile

Pour conteneuriser notre code, nous allons d'abord créer un Dockerfile. Nous allons inclure toutes les commandes nécessaires à l'exécution de l'image dans notre Dockerfile. Il installera toutes les bibliothèques que nous utilisons et configurera le point d'entrée de notre code d'entraînement.

Dans l'éditeur de fichiers Cloud Shell, ouvrez votre répertoire mpg/, puis double-cliquez pour ouvrir le Dockerfile:

Ouvrir le Dockerfile

Ensuite, copiez le code suivant dans ce fichier:

FROM gcr.io/deeplearning-platform-release/tf2-cpu.2-3
WORKDIR /

# Copies the trainer code to the docker image.
COPY trainer /trainer

# Sets up the entry point to invoke the trainer.
ENTRYPOINT ["python", "-m", "trainer.train"]

Ce Dockerfile utilise l'image Docker de TensorFlow Enterprise 2.3 comme conteneur de deep learning. Les conteneurs de deep learning de Google Cloud sont fournis avec de nombreux frameworks de ML et de data science courants préinstallés. Celui que nous utilisons inclut TF Enterprise 2.3, Pandas, Scikit-learn, etc. Après avoir téléchargé cette image, ce Dockerfile configure le point d'entrée de notre code d'entraînement, que nous ajouterons à l'étape suivante.

Étape 3: Ajoutez le code d'entraînement du modèle

Dans l'éditeur Cloud Shell, ouvrez le fichier train.py et copiez le code ci-dessous (ceci a été adapté à partir du tutoriel de la documentation TensorFlow).

# This will be replaced with your bucket name after running the `sed` command in the tutorial
BUCKET = "BUCKET_NAME"

import numpy as np
import pandas as pd
import pathlib
import tensorflow as tf

from tensorflow import keras
from tensorflow.keras import layers

print(tf.__version__)

"""## The Auto MPG dataset

The dataset is available from the [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/).

### Get the data
First download the dataset.
"""

"""Import it using pandas"""

dataset_path = "https://storage.googleapis.com/io-vertex-codelab/auto-mpg.csv"
dataset = pd.read_csv(dataset_path, na_values = "?")

dataset.tail()

"""### Clean the data

The dataset contains a few unknown values.
"""

dataset.isna().sum()

"""To keep this initial tutorial simple drop those rows."""

dataset = dataset.dropna()

"""The `"origin"` column is really categorical, not numeric. So convert that to a one-hot:"""

dataset['origin'] = dataset['origin'].map({1: 'USA', 2: 'Europe', 3: 'Japan'})

dataset = pd.get_dummies(dataset, prefix='', prefix_sep='')
dataset.tail()

"""### Split the data into train and test

Now split the dataset into a training set and a test set.

We will use the test set in the final evaluation of our model.
"""

train_dataset = dataset.sample(frac=0.8,random_state=0)
test_dataset = dataset.drop(train_dataset.index)

"""### Inspect the data

Have a quick look at the joint distribution of a few pairs of columns from the training set.

Also look at the overall statistics:
"""

train_stats = train_dataset.describe()
train_stats.pop("mpg")
train_stats = train_stats.transpose()
train_stats

"""### Split features from labels

Separate the target value, or "label", from the features. This label is the value that you will train the model to predict.
"""

train_labels = train_dataset.pop('mpg')
test_labels = test_dataset.pop('mpg')

"""### Normalize the data

Look again at the `train_stats` block above and note how different the ranges of each feature are.

It is good practice to normalize features that use different scales and ranges. Although the model *might* converge without feature normalization, it makes training more difficult, and it makes the resulting model dependent on the choice of units used in the input.

Note: Although we intentionally generate these statistics from only the training dataset, these statistics will also be used to normalize the test dataset. We need to do that to project the test dataset into the same distribution that the model has been trained on.
"""

def norm(x):
  return (x - train_stats['mean']) / train_stats['std']
normed_train_data = norm(train_dataset)
normed_test_data = norm(test_dataset)

"""This normalized data is what we will use to train the model.

Caution: The statistics used to normalize the inputs here (mean and standard deviation) need to be applied to any other data that is fed to the model, along with the one-hot encoding that we did earlier.  That includes the test set as well as live data when the model is used in production.

## The model

### Build the model

Let's build our model. Here, we'll use a `Sequential` model with two densely connected hidden layers, and an output layer that returns a single, continuous value. The model building steps are wrapped in a function, `build_model`, since we'll create a second model, later on.
"""

def build_model():
  model = keras.Sequential([
    layers.Dense(64, activation='relu', input_shape=[len(train_dataset.keys())]),
    layers.Dense(64, activation='relu'),
    layers.Dense(1)
  ])

  optimizer = tf.keras.optimizers.RMSprop(0.001)

  model.compile(loss='mse',
                optimizer=optimizer,
                metrics=['mae', 'mse'])
  return model

model = build_model()

"""### Inspect the model

Use the `.summary` method to print a simple description of the model
"""

model.summary()

"""Now try out the model. Take a batch of `10` examples from the training data and call `model.predict` on it.

It seems to be working, and it produces a result of the expected shape and type.

### Train the model

Train the model for 1000 epochs, and record the training and validation accuracy in the `history` object.

Visualize the model's training progress using the stats stored in the `history` object.

This graph shows little improvement, or even degradation in the validation error after about 100 epochs. Let's update the `model.fit` call to automatically stop training when the validation score doesn't improve. We'll use an *EarlyStopping callback* that tests a training condition for  every epoch. If a set amount of epochs elapses without showing improvement, then automatically stop the training.

You can learn more about this callback [here](https://www.tensorflow.org/api_docs/python/tf/keras/callbacks/EarlyStopping).
"""

model = build_model()

EPOCHS = 1000

# The patience parameter is the amount of epochs to check for improvement
early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)

early_history = model.fit(normed_train_data, train_labels, 
                    epochs=EPOCHS, validation_split = 0.2, 
                    callbacks=[early_stop])


# Export model and save to GCS
model.save(BUCKET + '/mpg/model')

Une fois que vous avez copié le code ci-dessus dans le fichier mpg/trainer/train.py, revenez au terminal dans Cloud Shell et exécutez la commande suivante pour ajouter votre propre nom de bucket au fichier:

sed -i "s|BUCKET_NAME|$BUCKET_NAME|g" trainer/train.py

Étape 4: Créez et testez le conteneur localement

Depuis votre terminal, exécutez la commande suivante pour définir une variable avec l'URI de votre image de conteneur dans Google Container Registry:

IMAGE_URI="gcr.io/$GOOGLE_CLOUD_PROJECT/mpg:v1"

Ensuite, créez le conteneur en exécutant la commande suivante à partir de la racine de votre répertoire mpg :

docker build ./ -t $IMAGE_URI

Une fois le conteneur créé, transférez-le vers Google Container Registry:

docker push $IMAGE_URI

Pour vérifier que votre image a bien été transférée vers Container Registry, un message semblable au suivant doit s'afficher lorsque vous accédez à la section Container Registry de votre console:

Aperçu de Container Registry

Maintenant que notre conteneur a été transféré vers Container Registry, nous sommes prêts à lancer un job d'entraînement de modèle personnalisé.

5. Exécuter un job d'entraînement sur Vertex AI

Vertex vous propose deux options pour entraîner des modèles:

  • AutoML, qui vous permet d'entraîner facilement des modèles de grande qualité, quel que soit votre niveau d'expertise en ML
  • Entraînement personnalisé: exécutez vos applications d'entraînement personnalisé dans le cloud à l'aide de l'un des conteneurs prédéfinis de Google Cloud ou de votre propre conteneur.

Dans cet atelier, vous allez utiliser l'entraînement personnalisé via notre propre conteneur personnalisé sur Google Container Registry. Pour commencer, accédez à l'onglet Entraînement de la section Vertex de votre console Cloud :

Menu latéral des sommets – Entraînement

Étape 1: Lancer le job d'entraînement

Cliquez sur Créer pour saisir les paramètres du job d'entraînement et du modèle déployé :

  • Sous Ensemble de données, sélectionnez Aucun ensemble de données géré.
  • Sélectionnez ensuite Entraînement personnalisé (avancé) comme méthode d'entraînement, puis cliquez sur Continuer.
  • Saisissez mpg (ou tout autre nom que vous souhaitez donner à votre modèle) dans Nom du modèle.
  • Cliquez sur Continuer.

À l'étape des paramètres du conteneur, sélectionnez Conteneur personnalisé :

Option de conteneur personnalisé

Dans le premier champ "Image du conteneur", cliquez sur Parcourir et recherchez le conteneur que vous venez de transférer vers Container Registry. Voici un exemple :

Rechercher un conteneur

Laissez les autres champs vides et cliquez sur Continuer.

Le réglage des hyperparamètres n'est pas utilisé dans ce tutoriel. Laissez la case "Activer le réglage des hyperparamètres" décochée et cliquez sur Continuer.

Dans Options de calcul et tarifs, ne modifiez pas la région sélectionnée et choisissez le type de machine n1-standard-4:

Type de machine

Comme le modèle de cette démonstration est entraîné rapidement, nous utilisons un type de machine plus petit.

Sous l'étape Conteneur de prédiction, sélectionnez Aucun conteneur de prédiction:

Aucun conteneur de prédiction

6. Déployer un point de terminaison du modèle

Au cours de cette étape, nous allons créer un point de terminaison pour le modèle entraîné. Nous pouvons l'utiliser pour obtenir des prédictions sur notre modèle via l'API Vertex AI. Pour ce faire, nous avons mis à disposition une version des éléments de modèle entraînés exportés dans un bucket GCS public.

Dans une entreprise, il est courant qu'une équipe ou une personne soit chargée de créer le modèle et qu'une autre équipe soit chargée de le déployer. Les étapes que nous allons suivre ici vous montreront comment prendre un modèle déjà entraîné et le déployer pour obtenir des prédictions.

Dans cet atelier, nous allons utiliser le SDK Vertex AI pour créer un modèle, le déployer sur un point de terminaison et obtenir une prédiction.

Étape 1: Installer le SDK Vertex

Depuis votre terminal Cloud Shell, exécutez la commande suivante pour installer le SDK Vertex AI:

pip3 install google-cloud-aiplatform --upgrade --user

Nous pouvons utiliser ce SDK pour interagir avec de nombreuses parties différentes de Vertex.

Étape 2: Créer le modèle et déployer le point de terminaison

Nous allons maintenant créer un fichier Python et utiliser le SDK pour créer une ressource de modèle et la déployer sur un point de terminaison. Dans l'éditeur de fichiers de Cloud Shell, sélectionnez File (Fichier), puis New File (Nouveau fichier) :

Nouveau fichier dans Cloud Shell

Attribuez le nom suivant au fichier : deploy.py. Ouvrez ce fichier dans votre éditeur et copiez le code suivant:

from google.cloud import aiplatform

# Create a model resource from public model assets
model = aiplatform.Model.upload(
    display_name="mpg-imported",
    artifact_uri="gs://io-vertex-codelab/mpg-model/",
    serving_container_image_uri="gcr.io/cloud-aiplatform/prediction/tf2-cpu.2-3:latest"
)

# Deploy the above model to an endpoint
endpoint = model.deploy(
    machine_type="n1-standard-4"
)

Revenez ensuite au terminal dans Cloud Shell, cd dans votre répertoire racine, puis exécutez le script Python que vous venez de créer:

cd ..
python3 deploy.py | tee deploy-output.txt

Les mises à jour sont consignées dans votre terminal à mesure que des ressources sont créées. Cette opération prend entre 10 et 15 minutes. Pour vous assurer que tout fonctionne correctement, accédez à la section Modèles de votre console dans Vertex AI:

Modèle dans la console Vertex

Cliquez sur mgp-imported. Le point de terminaison de ce modèle doit s'afficher:

Point de terminaison en attente

Dans votre terminal Cloud Shell, un journal semblable au suivant s'affiche une fois le déploiement de votre point de terminaison terminé:

Endpoint model deployed. Resource name: projects/your-project-id/locations/us-central1/endpoints/your-endpoint-id

Vous l'utiliserez à l'étape suivante pour obtenir une prédiction sur votre endopint déployé.

Étape 3: Obtenez des prédictions sur le point de terminaison déployé

Dans votre éditeur Cloud Shell, créez un fichier nommé predict.py:

Créer un fichier de prédiction

Ouvrez predict.py et collez-y le code suivant:

from google.cloud import aiplatform

endpoint = aiplatform.Endpoint(
    endpoint_name="ENDPOINT_STRING"
)

# A test example we'll send to our model for prediction
test_mpg = [1.4838871833555929,
 1.8659883497083019,
 2.234620276849616,
 1.0187816540094903,
 -2.530890710602246,
 -1.6046416850441676,
 -0.4651483719733302,
 -0.4952254087173721,
 0.7746763768735953]

response = endpoint.predict([test_mpg])

print('API response: ', response)

print('Predicted MPG: ', response.predictions[0][0])

Revenez ensuite à votre terminal et saisissez la commande suivante pour remplacer ENDPOINT_STRING dans le fichier de prédiction par votre propre point de terminaison:

ENDPOINT=$(cat deploy-output.txt | sed -nre 's:.*Resource name\: (.*):\1:p' | tail -1)
sed -i "s|ENDPOINT_STRING|$ENDPOINT|g" predict.py

Il est maintenant temps d'exécuter le fichier predict.py pour obtenir une prédiction à partir du point de terminaison du modèle déployé:

python3 predict.py

La réponse de l'API doit s'afficher, ainsi que la consommation de carburant estimée pour notre prédiction de test.

🎉 Félicitations ! 🎉

Vous savez désormais utiliser Vertex AI pour :

  • Entraîner un modèle en fournissant le code d'entraînement dans un conteneur personnalisé : dans cet exemple, vous avez utilisé un modèle TensorFlow, mais vous pouvez entraîner un modèle créé avec n'importe quel framework à l'aide de conteneurs personnalisés.
  • Déployer un modèle TensorFlow à l'aide d'un conteneur préconfiguré dans le cadre du workflow que vous avez déjà utilisé pour l'entraînement
  • Créer un point de terminaison de modèle et générer une prédiction

Pour en savoir plus sur les différentes parties de Vertex AI, consultez la documentation. Si vous souhaitez afficher les résultats du job d'entraînement que vous avez démarré à l'étape 5, accédez à la section "Entraînement" de votre console Vertex.

7. Nettoyage

Pour supprimer le point de terminaison que vous avez déployé, accédez à la section Points de terminaison de votre console Vertex et cliquez sur l'icône de suppression:

Supprimer un point de terminaison

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