Vertex AI: entraîner et diffuser un modèle personnalisé

1. Présentation

Dans cet atelier, vous utiliserez Vertex AI pour entraîner et déployer un modèle TensorFlow en utilisant du code dans un conteneur personnalisé.

Bien que cet atelier utilise TensorFlow pour le code du modèle, vous pourriez 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 dans Vertex Workbench
  • 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 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. Pour envoyer un commentaire, consultez la page d'assistance.

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 les produits mis en évidence ci-dessous: Training, Prediction et Workbench.

Présentation des produits Vertex

3. 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 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 3: Activez l'API Container Registry

Accédez à Container Registry et cliquez sur Activer si ce n'est pas déjà fait. Vous l'utiliserez afin de créer un conteneur pour votre job d'entraînement personnalisé.

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

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

Menu Vertex AI

Dans Notebooks gérés par l'utilisateur, cliquez sur Nouveau notebook:

Créer un notebook

Sélectionnez ensuite la dernière version du type d'instance TensorFlow Enterprise (avec LTS) sans GPU:

Instance TFE

Utilisez les options par défaut, puis cliquez sur Créer.

Le modèle que nous allons entraîner et diffuser dans cet atelier est basé sur ce tutoriel des documents TensorFlow. Le tutoriel utilise l'ensemble de données Auto MPG de Kaggle pour prédire l'efficacité énergétique 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.

Pour commencer, à partir du menu de lancement, ouvrez une fenêtre de terminal dans votre instance de notebook :

Ouvrir le terminal dans le notebook

Créez un répertoire appelé mpg et utilisez la commande cd pour y accéder :

mkdir mpg
cd mpg

Étape 1: Créez un Dockerfile

La première étape de la conteneurisation de notre code consiste à créer un Dockerfile. Nous allons placer dans notre Dockerfile toutes les commandes nécessaires à l'exécution de notre image. Il installera toutes les bibliothèques que nous utilisons et configurera le point d'entrée de notre code d'entraînement. Depuis votre terminal, créez un Dockerfile vide:

touch Dockerfile

Ouvrez le Dockerfile et copiez-y le code suivant :

FROM gcr.io/deeplearning-platform-release/tf2-cpu.2-6
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 et d'autres. Une fois l'image téléchargée, ce Dockerfile configure le point d'entrée de notre code d'entraînement. Nous n'avons pas encore créé ces fichiers. À l'étape suivante, nous allons ajouter le code permettant d'entraîner et d'exporter notre modèle.

Étape 2: Créez un bucket Cloud Storage

Dans notre tâche d'entraînement, nous allons exporter le modèle TensorFlow entraîné vers un bucket Cloud Storage. Vertex utilisera ce bucket pour accéder en lecture aux ressources de notre modèle exporté ainsi que pour déployer le modèle. 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. L'option -l (emplacement) est importante, car elle doit être située dans la même région que celle où vous allez déployer un point de terminaison du modèle dans la suite de ce tutoriel:

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

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

Depuis votre terminal, exécutez la commande suivante afin de créer un répertoire pour notre code d'entraînement et un fichier Python dans lequel nous ajouterons le code:

mkdir trainer
touch trainer/train.py

Votre répertoire "mpg/" devrait à présent contenir les éléments suivants :

+ Dockerfile
+ trainer/
    + train.py

Ouvrez ensuite le fichier train.py que vous venez de créer, puis copiez-y le code ci-dessous (ce contenu a été adapté à partir du tutoriel disponible dans la documentation de TensorFlow).

Au début du fichier, remplacez la variable BUCKET par le nom du bucket Cloud Storage que vous avez créé à l'étape précédente:

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

dataset_path = keras.utils.get_file("auto-mpg.data", "http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data")
dataset_path

"""Import it using pandas"""

column_names = ['MPG','Cylinders','Displacement','Horsepower','Weight',
                'Acceleration', 'Model Year', 'Origin']
dataset = pd.read_csv(dataset_path, names=column_names,
                      na_values = "?", comment='\t',
                      sep=" ", skipinitialspace=True)

dataset.tail()

# TODO: replace `your-gcs-bucket` with the name of the Storage bucket you created earlier
BUCKET = 'gs://your-gcs-bucket'

"""### 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')

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

Depuis votre terminal, définissez une variable avec l'URI de votre image de conteneur dans Google Container Registry:

IMAGE_URI="gcr.io/$PROJECT_ID/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

Exécutez le conteneur depuis votre instance de notebook pour vérifier qu'il fonctionne correctement :

docker run $IMAGE_URI

L'entraînement du modèle devrait prendre 1 à 2 minutes et la justesse de validation devrait avoisiner les 72 % (le taux de justesse peut varier légèrement). Après avoir exécuté le conteneur localement avec succès, transférez-le vers Google Container Registry :

docker push $IMAGE_URI

Maintenant que le conteneur a été transmis à Container Registry, nous pouvons démarrer un job d'entraînement de modèle personnalisé.

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

Avec Vertex AI, vous disposez de 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é: vous permet d'exécuter vos applications d'entraînement personnalisé dans le cloud en vous servant de l'un des conteneurs préconfigurés de Google Cloud ou de votre propre conteneur.

Dans cet atelier, nous allons utiliser l'entraînement personnalisé via notre propre conteneur personnalisé sur Google Container Registry. Pour commencer, accédez à la partie Modèles de la section Vertex de votre console Cloud :

Menu Vertex

Étape 1: Lancez 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.
  • Cliquez sur Continuer.

À l'étape suivante, saisissez mpg (ou tout autre nom de votre choix) dans le champ Nom du modèle. Sélectionnez ensuite Conteneur personnalisé:

Option de conteneur personnalisé

Dans la zone de texte Image du conteneur, cliquez sur Parcourir et recherchez l'image Docker que vous venez d'importer dans Container Registry. Laissez les autres champs vides et cliquez sur Continue (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

Laissez les champs de l'accélérateur vides, puis sélectionnez Continue (Continuer). Comme le modèle de cette démonstration peut être entraîné rapidement, nous utilisons un type de machine de plus petite taille.

À l'étape Conteneur de prédiction, sélectionnez Conteneur prédéfini, puis TensorFlow 2.6.

Conservez les paramètres par défaut du conteneur préconfiguré. Dans le champ Répertoire du modèle, indiquez votre bucket GCS (en ajoutant le sous-répertoire "mpg"). Voici le chemin (dans le script d'entraînement de modèle) vers lequel vous exportez votre modèle entraîné:

Paramètres de prédiction

Vertex utilisera cet emplacement pendant le déploiement de votre modèle. Vous pouvez à présent cliquer sur Démarrer l'entraînement pour lancer le job d'entraînement. La section "Entraînement" de votre console ressemblera à ceci:

Jobs d'entraînement

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

Lorsque nous avons configuré notre job d'entraînement, nous avons spécifié l'emplacement dans lequel Vertex AI doit rechercher les ressources de notre modèle exporté. Dans notre pipeline d'entraînement, Vertex va créer une ressource de modèle basée sur ce chemin d'accès. Cette ressource de modèle n'est pas un modèle déployé en soi, mais une fois que vous avez un modèle, vous pouvez effectuer le déploiement sur un point de terminaison. Pour en savoir plus sur les modèles et les points de terminaison dans Vertex AI, consultez la documentation.

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 à partir du modèle via l'API Vertex AI.

Étape 1: Déployer le point de terminaison

Une fois que votre job d'entraînement est terminé, un modèle nommé mpg (ou tout autre nom que vous avez préalablement spécifié) doit apparaître dans la section Modèles de votre console :

Jobs terminés

Pendant l'exécution du job d'entraînement, Vertex a créé pour vous une ressource de modèle. Pour utiliser ce modèle, vous devez le déployer sur un point de terminaison. Un modèle peut avoir plusieurs points de terminaison. Cliquez sur le modèle, puis choisissez Déployer sur un point de terminaison.

Sélectionnez Créer un point de terminaison et donnez-lui un nom, par exemple "v1". Laissez l'option Standard sélectionnée pour l'accès, puis cliquez sur Continue (Continuer).

Laissez la Répartition du trafic réglée sur 100 et saisissez 1 dans le champ Nombre minimal de nœuds de calcul. Sous Type de machine, sélectionnez n1-standard-2 (ou tout autre type de machine de votre choix). Laissez les autres valeurs par défaut sélectionnées, puis cliquez sur Continue (Continuer). Nous n'allons pas activer la surveillance pour ce modèle. Cliquez donc sur Déployer pour lancer le déploiement du point de terminaison.

Le déploiement du point de terminaison prendra 10 à 15 minutes. Vous recevrez un e-mail une fois le déploiement terminé. Une fois le déploiement terminé, vous verrez apparaître le contenu suivant, qui montre un point de terminaison déployé pour votre ressource de modèle:

Déployer sur un point de terminaison

Étape 2: Obtenir des prédictions à partir du modèle déployé

Nous obtiendrons des prédictions sur notre modèle entraîné à partir d'un notebook Python, à l'aide de l'API Vertex pour Python. Retournez dans votre instance de notebook et créez un notebook Python 3 à partir du menu de lancement :

Ouvrir le notebook

Dans votre notebook, exécutez le code suivant dans une cellule pour installer le SDK Vertex AI :

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

Ajoutez ensuite une cellule dans votre notebook pour importer le SDK et créer une référence au point de terminaison que vous venez de déployer :

from google.cloud import aiplatform

endpoint = aiplatform.Endpoint(
    endpoint_name="projects/YOUR-PROJECT-NUMBER/locations/us-central1/endpoints/YOUR-ENDPOINT-ID"
)

Vous devrez remplacer les deux valeurs (indiquées en majuscules) de la chaîne endpoint_name ci-dessus par votre numéro de projet et l'ID de votre point de terminaison. Le numéro de votre projet est indiqué dans le tableau de bord du projet.

Vous pouvez retrouver l'ID du point de terminaison dans la section "Points de terminaison" de la console :

Rechercher l'ID du point de terminaison

Enfin, vous allez générer une prédiction sur votre point de terminaison en copiant et en exécutant le code ci-dessous dans une nouvelle cellule :

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

Cet exemple présente déjà des valeurs normalisées, soit le format attendu par notre modèle.

Après avoir exécuté cette cellule, vous devriez obtenir un résultat de prédiction d'environ 16 mpg.

🎉 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érents composants de Vertex, consultez la documentation.

7. 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 Cloud, sélectionnez le notebook, puis cliquez sur Arrêter.

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

Pour supprimer le point de terminaison que vous avez déployé, accédez à la section Points de terminaison de votre console Vertex AI, 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:

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'espace de stockage