1. Présentation
Dans cet atelier, vous allez apprendre à utiliser Vertex AI pour le réglage des hyperparamètres et l'entraînement distribué. Cet atelier utilise TensorFlow pour le code du modèle, mais les concepts s'appliquent également à d'autres frameworks de ML.
Objectifs
Vous allez apprendre à effectuer les opérations suivantes :
- Entraîner un modèle à l'aide de l'entraînement distribué sur un conteneur personnalisé
- Lancer plusieurs essais de votre code d'entraînement pour les réglages d'hyperparamètres automatisés
Le coût total d'exécution de cet atelier sur Google Cloud est d'environ 6 $.
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 via 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 des commentaires, accédez à 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 Training et Workbench.
3. Présentation du cas d'utilisation
Dans cet atelier, vous allez utiliser le réglage des hyperparamètres afin d'identifier les paramètres optimaux pour un modèle de classification d'images entraîné sur l'ensemble de données "chevaux et humains" à partir d'ensembles de données TensorFlow.
Réglages d'hyperparamètres
Le réglage des hyperparamètres avec Vertex AI Training consiste à exécuter plusieurs tests sur votre application d'entraînement, avec, pour les hyperparamètres que vous avez choisis, des valeurs comprises dans les limites que vous avez définies. Vertex AI effectue le suivi des résultats de chaque essai et procède aux ajustements nécessaires pour les essais ultérieurs.
Pour utiliser les réglages d'hyperparamètres avec Vertex AI Training, vous devez apporter deux modifications à votre code d'entraînement :
- Définissez un argument de ligne de commande dans votre module d'entraînement principal pour chaque hyperparamètre à régler.
- Utilisez la valeur transmise dans ces arguments afin de définir l'hyperparamètre correspondant dans le code de votre application d'entraînement.
Entraînement distribué
Si vous disposez d'un seul GPU, TensorFlow utilisera cet accélérateur pour entraîner le modèle plus rapidement, sans qu'aucune action supplémentaire de votre part ne soit nécessaire. Toutefois, si vous souhaitez bénéficier d'un avantage supplémentaire en utilisant plusieurs GPU, vous devez utiliser tf.distribute
, le module de TensorFlow qui permet d'effectuer des calculs sur plusieurs appareils.
Cet atelier utilise tf.distribute.MirroredStrategy
, que vous pouvez ajouter à vos applications d'entraînement avec un nombre réduit de modifications du code. Cette stratégie crée une copie du modèle sur chaque GPU de votre ordinateur. Les mises à jour de gradient suivantes s'effectueront de manière synchrone. Cela signifie que chaque GPU calcule la propagation avant et arrière du modèle sur une autre tranche des données d'entrée. Les gradients calculés à partir de chacune de ces tranches sont ensuite agrégés sur l'ensemble des GPU, puis une moyenne est calculée dans un processus appelé all-reduce. Les paramètres du modèle sont mis à jour à l'aide de la moyenne des gradients.
Vous n'avez pas besoin de connaître tous les détails pour suivre cet atelier, mais si vous souhaitez en savoir plus sur le fonctionnement de l'entraînement distribué dans TensorFlow, vous pouvez consulter la vidéo ci-dessous :
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.
Étape 2 : Activez l'API Container Registry
Accédez à Container Registry et cliquez sur Activer si ce n'est pas déjà fait. Vous utiliserez ce service afin de créer un conteneur pour votre tâche d'entraînement 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.
Étape 4 : Créez une instance Vertex AI Workbench
Dans la section Vertex AI de Cloud Console, cliquez sur Workbench :
Activez l'API Notebooks si ce n'est pas déjà fait.
Une fois l'API activée, cliquez sur NOTEBOOKS GÉRÉS :
Sélectionnez ensuite NOUVEAU NOTEBOOK.
Attribuez un nom à votre notebook, puis cliquez sur Paramètres avancés.
Sous "Paramètres avancés", activez l'arrêt en cas d'inactivité et définissez le nombre de minutes sur 60. Cela entraîne l'arrêt automatique du notebook lorsqu'il n'est pas utilisé. Vous ne payez donc pas de frais inutiles.
Dans la section "Sécurité", sélectionnez "Activer le terminal" si ce n'est pas déjà fait.
Vous pouvez conserver tous les autres paramètres avancés tels quels.
Cliquez ensuite sur Créer. Le provisionnement de l'instance prend quelques minutes.
Une fois l'instance créée, sélectionnez Ouvrir JupyterLab.
La première fois que vous utilisez une nouvelle instance, vous êtes invité à vous authentifier. Pour ce faire, suivez les étapes indiquées dans l'interface utilisateur.
5. Rédiger le code d'entraînement
Pour commencer, à partir du menu de lancement, ouvrez une fenêtre de terminal dans votre instance de notebook :
Créez un répertoire appelé vertex-codelab
et utilisez la commande cd pour y accéder.
mkdir vertex-codelab
cd vertex-codelab
Exécutez la commande suivante afin de créer un répertoire pour le code d'entraînement et un fichier Python dans lequel vous pourrez ajouter le code :
mkdir trainer
touch trainer/task.py
Votre répertoire vertex-codelab
doit maintenant contenir les éléments suivants :
+ trainer/
+ task.py
Ensuite, ouvrez le fichier task.py
que vous venez de créer et collez tout le code ci-dessous dans ce fichier.
import tensorflow as tf
import tensorflow_datasets as tfds
import argparse
import hypertune
import os
NUM_EPOCHS = 10
BATCH_SIZE = 64
def get_args():
'''Parses args. Must include all hyperparameters you want to tune.'''
parser = argparse.ArgumentParser()
parser.add_argument(
'--learning_rate',
required=True,
type=float,
help='learning rate')
parser.add_argument(
'--momentum',
required=True,
type=float,
help='SGD momentum value')
parser.add_argument(
'--num_units',
required=True,
type=int,
help='number of units in last hidden layer')
args = parser.parse_args()
return args
def preprocess_data(image, label):
'''Resizes and scales images.'''
image = tf.image.resize(image, (150,150))
return tf.cast(image, tf.float32) / 255., label
def create_dataset(batch_size):
'''Loads Horses Or Humans dataset and preprocesses data.'''
data, info = tfds.load(name='horses_or_humans', as_supervised=True, with_info=True)
# Create train dataset
train_data = data['train'].map(preprocess_data)
train_data = train_data.shuffle(1000)
train_data = train_data.batch(batch_size)
# Create validation dataset
validation_data = data['test'].map(preprocess_data)
validation_data = validation_data.batch(batch_size)
return train_data, validation_data
def create_model(num_units, learning_rate, momentum):
'''Defines and compiles model.'''
inputs = tf.keras.Input(shape=(150, 150, 3))
x = tf.keras.layers.Conv2D(16, (3, 3), activation='relu')(inputs)
x = tf.keras.layers.MaxPooling2D((2, 2))(x)
x = tf.keras.layers.Conv2D(32, (3, 3), activation='relu')(x)
x = tf.keras.layers.MaxPooling2D((2, 2))(x)
x = tf.keras.layers.Conv2D(64, (3, 3), activation='relu')(x)
x = tf.keras.layers.MaxPooling2D((2, 2))(x)
x = tf.keras.layers.Flatten()(x)
x = tf.keras.layers.Dense(num_units, activation='relu')(x)
outputs = tf.keras.layers.Dense(1, activation='sigmoid')(x)
model = tf.keras.Model(inputs, outputs)
model.compile(
loss='binary_crossentropy',
optimizer=tf.keras.optimizers.SGD(learning_rate=learning_rate, momentum=momentum),
metrics=['accuracy'])
return model
def main():
args = get_args()
# Create distribution strategy
strategy = tf.distribute.MirroredStrategy()
# Get data
GLOBAL_BATCH_SIZE = BATCH_SIZE * strategy.num_replicas_in_sync
train_data, validation_data = create_dataset(GLOBAL_BATCH_SIZE)
# Wrap variable creation within strategy scope
with strategy.scope():
model = create_model(args.num_units, args.learning_rate, args.momentum)
# Train model
history = model.fit(train_data, epochs=NUM_EPOCHS, validation_data=validation_data)
# Define metric
hp_metric = history.history['val_accuracy'][-1]
hpt = hypertune.HyperTune()
hpt.report_hyperparameter_tuning_metric(
hyperparameter_metric_tag='accuracy',
metric_value=hp_metric,
global_step=NUM_EPOCHS)
if __name__ == "__main__":
main()
Examinons de plus près le code et les composants spécifiques à l'entraînement distribué et au réglage des hyperparamètres.
Entraînement distribué
- L'objet
MirroredStrategy
est créé dans la fonctionmain()
. Vous devez ensuite encapsuler la création des variables du modèle dans le champ d'application de la stratégie. Cette étape indique à TensorFlow les variables à mettre en miroir sur les GPU. - La taille du lot est mise à l'échelle par la valeur
num_replicas_in_sync
. La mise à l'échelle de la taille de lot est une bonne pratique lorsque vous utilisez des stratégies de chargement de données synchrones en parallèle dans TensorFlow. Pour en savoir plus, accédez à cette page.
Réglages d'hyperparamètres
- Le script importe la bibliothèque
hypertune
. Plus tard, lors de la création de l'image de conteneur, nous devrons installer cette bibliothèque. - La fonction
get_args()
définit un argument de ligne de commande pour chaque hyperparamètre que vous souhaitez régler. Dans cet exemple, les hyperparamètres qui seront réglés sont le taux d'apprentissage, la valeur du momentum dans l'optimiseur et le nombre d'unités dans la dernière couche cachée du modèle, mais n'hésitez pas à effectuer des tests avec d'autres hyperparamètres. La valeur transmise dans ces arguments doit ensuite être utilisée pour définir l'hyperparamètre correspondant dans le code (par exemple,learning_rate = args.learning_rate
). - À la fin de la fonction
main()
, la bibliothèquehypertune
permet de définir la métrique que vous souhaitez optimiser. Dans TensorFlow, la méthode Kerasmodel.fit
renvoie un objetHistory
. L'attributHistory.history
est un enregistrement des valeurs de perte d'entraînement et des métriques à des époques successives. Si vous transmettez des données de validation àmodel.fit
, l'attributHistory.history
inclut également les valeurs de perte de validation et celles des métriques. Par exemple, si vous aviez entraîné un modèle pendant trois époques avec des données de validation et que vous aviez fourniaccuracy
comme métrique, l'attributHistory.history
ressemblerait au dictionnaire suivant.
{
"accuracy": [
0.7795261740684509,
0.9471358060836792,
0.9870933294296265
],
"loss": [
0.6340447664260864,
0.16712145507335663,
0.04546636343002319
],
"val_accuracy": [
0.3795261740684509,
0.4471358060836792,
0.4870933294296265
],
"val_loss": [
2.044623374938965,
4.100203514099121,
3.0728273391723633
]
Si vous souhaitez que le service de réglage des hyperparamètres découvre les valeurs qui maximisent la justesse de la validation du modèle, vous devez définir la métrique en tant que dernière entrée (ou NUM_EPOCS - 1
) de la liste val_accuracy
. Transmettez ensuite cette métrique à une instance de HyperTune
. Vous pouvez choisir la chaîne que vous voulez pour hyperparameter_metric_tag
, mais vous devrez la réutiliser ultérieurement lorsque vous lancerez la tâche de réglage des hyperparamètres.
6. Conteneuriser le code
La première étape pour conteneuriser votre code consiste à créer un fichier Dockerfile. Vous allez placer dans ce Dockerfile toutes les commandes nécessaires à l'exécution de l'image. Il installera toutes les bibliothèques nécessaires et configurera le point d'entrée du code d'entraînement.
Étape 1 : Écrivez un fichier Dockerfile
Depuis votre terminal, assurez-vous que vous vous trouvez dans le répertoire vertex-codelab
et créez un fichier Dockerfile vide :
touch Dockerfile
Votre répertoire vertex-codelab
doit maintenant contenir les éléments suivants :
+ Dockerfile
+ trainer/
+ task.py
Ouvrez le Dockerfile et copiez-y le code suivant :
FROM gcr.io/deeplearning-platform-release/tf2-gpu.2-7
WORKDIR /
# Installs hypertune library
RUN pip install cloudml-hypertune
# Copies the trainer code to the docker image.
COPY trainer /trainer
# Sets up the entry point to invoke the trainer.
ENTRYPOINT ["python", "-m", "trainer.task"]
Ce fichier Dockerfile utilise l'image Docker avec GPU de TensorFlow Enterprise 2.7 comme conteneur de deep learning. Les conteneurs de deep learning sur Google Cloud sont fournis avec de nombreux frameworks de ML et de science des données courants préinstallés. Une fois cette image téléchargée, ce Dockerfile configure le point d'entrée du code d'entraînement.
Étape 2 : Créez le conteneur
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'
Définissez une variable avec l'URI de votre image de conteneur dans Google Container Registry :
IMAGE_URI="gcr.io/$PROJECT_ID/horse-human-codelab:latest"
Configurer Docker
gcloud auth configure-docker
Ensuite, créez le conteneur en exécutant la commande suivante à partir de la racine de votre répertoire vertex-codelab
:
docker build ./ -t $IMAGE_URI
Enfin, transférez-le vers Google Container Registry :
docker push $IMAGE_URI
Étape 3 : Créez un bucket Cloud Storage
Dans notre tâche d'entraînement, nous allons transmettre le chemin d'accès à un bucket de préproduction.
Exécutez la commande suivante dans votre terminal pour créer un bucket dans votre projet.
BUCKET_NAME="gs://${PROJECT_ID}-hptune-bucket"
gsutil mb -l us-central1 $BUCKET_NAME
7. Lancer la tâche de réglage des hyperparamètres
Étape 1 : Créez une tâche d'entraînement personnalisée avec réglage des hyperparamètres
Depuis le menu de lancement, ouvrez un nouveau notebook TensorFlow 2.
Importez le SDK Python Vertex AI.
from google.cloud import aiplatform
from google.cloud.aiplatform import hyperparameter_tuning as hpt
Pour lancer la tâche de réglage des hyperparamètres, vous devez d'abord définir la valeur de worker_pool_specs
, qui spécifie le type de machine et l'image Docker. La spécification suivante définit une machine comportant deux GPU NVIDIA Tesla V100.
Vous devrez remplacer {PROJECT_ID}
par l'ID de votre projet dans image_uri
.
# The spec of the worker pools including machine type and Docker image
# Be sure to replace PROJECT_ID in the "image_uri" with your project.
worker_pool_specs = [{
"machine_spec": {
"machine_type": "n1-standard-4",
"accelerator_type": "NVIDIA_TESLA_V100",
"accelerator_count": 2
},
"replica_count": 1,
"container_spec": {
"image_uri": "gcr.io/{PROJECT_ID}/horse-human-codelab:latest"
}
}]
Ensuite, définissez le parameter_spec
, qui est un dictionnaire spécifiant les paramètres à optimiser. La clé du dictionnaire correspond à la chaîne que vous avez attribuée à l'argument de ligne de commande pour chaque hyperparamètre, et la valeur du dictionnaire correspond à la spécification du paramètre.
Pour chaque hyperparamètre, vous devez définir le type ainsi que les limites pour les valeurs que le service de réglage testera. Les hyperparamètres peuvent être de type Double, Entier, Catégoriel ou Discret. Si vous sélectionnez le type "Double" ou "Entier", vous devez indiquer des valeurs minimale et maximale. Si vous sélectionnez un type "Catégoriel" ou "Discret", vous devez indiquer les valeurs. Pour les types "Double" et "Entier", vous devez également fournir la valeur de scaling. Pour savoir comment choisir la meilleure valeur de scaling, consultez cette vidéo.
# Dictionary representing parameters to optimize.
# The dictionary key is the parameter_id, which is passed into your training
# job as a command line argument,
# And the dictionary value is the parameter specification of the metric.
parameter_spec = {
"learning_rate": hpt.DoubleParameterSpec(min=0.001, max=1, scale="log"),
"momentum": hpt.DoubleParameterSpec(min=0, max=1, scale="linear"),
"num_units": hpt.DiscreteParameterSpec(values=[64, 128, 512], scale=None)
}
La dernière spécification à définir est metric_spec
, le dictionnaire qui représente la métrique à optimiser. La clé du dictionnaire est l'option hyperparameter_metric_tag
, que vous avez définie dans le code de votre application d'entraînement, et sa valeur correspond à l'objectif d'optimisation.
# Dicionary representing metrics to optimize.
# The dictionary key is the metric_id, which is reported by your training job,
# And the dictionary value is the optimization goal of the metric.
metric_spec={'accuracy':'maximize'}
Une fois toutes les spécifications définies, vous allez créer une CustomJob
, c'est-à-dire la spécification commune qui sera utilisée pour exécuter votre tâche lors de chacun des tests de réglage des hyperparamètres.
Vous devez remplacer {YOUR_BUCKET}
par le bucket que vous avez créé précédemment.
# Replace YOUR_BUCKET
my_custom_job = aiplatform.CustomJob(display_name='horses-humans',
worker_pool_specs=worker_pool_specs,
staging_bucket='gs://{YOUR_BUCKET}')
Ensuite, créez et exécutez HyperparameterTuningJob
.
hp_job = aiplatform.HyperparameterTuningJob(
display_name='horses-humans',
custom_job=my_custom_job,
metric_spec=metric_spec,
parameter_spec=parameter_spec,
max_trial_count=6,
parallel_trial_count=2,
search_algorithm=None)
hp_job.run()
Voici quelques arguments à prendre en compte :
- max_trial_count : vous devez définir le nombre maximal d'essais que le service va réaliser. Un plus grand nombre d'essais permet généralement d'obtenir de meilleurs résultats, mais il existe un point de retours décroissants au-delà duquel les essais supplémentaires n'ont que peu ou pas d'effet sur la métrique que vous essayez d'optimiser. Il est recommandé de commencer avec un petit nombre d'essais et d'attendre d'avoir une idée de l'impact des hyperparamètres choisis avant d'augmenter le nombre d'essais.
- parallel_trial_count : si vous utilisez des essais en parallèle, le service provisionne plusieurs clusters de traitement pour l'entraînement. L'augmentation du nombre d'essais parallèles a pour effet de réduire le temps nécessaire à l'exécution de la tâche de réglage des hyperparamètres. Toutefois, elle peut réduire l'efficacité globale de la tâche. En effet, la stratégie de réglage par défaut utilise les résultats des essais précédents pour ajuster les valeurs affectées lors des essais suivants.
- search_algorithm : vous pouvez définir l'algorithme de recherche sur "Grille", "Aléatoire" ou utiliser la valeur par défaut (Aucun). L'option par défaut applique l'optimisation bayésienne pour rechercher l'espace des valeurs possibles pour les hyperparamètres. Il s'agit de l'algorithme recommandé. Cliquez ici pour en savoir plus sur cet algorithme.
Une fois la tâche lancée, vous pouvez suivre son état d'avancement dans l'onglet TÂCHES DE RÉGLAGE D'HYPERPARAMÈTRES de l'interface utilisateur.
Une fois la tâche terminée, vous pouvez afficher et trier les résultats de vos essais pour découvrir la meilleure combinaison de valeurs d'hyperparamètres.
🎉 Félicitations ! 🎉
Vous avez appris à utiliser Vertex AI pour :
- Exécuter une tâche de réglage des hyperparamètres avec l'entraînement distribué
Pour en savoir plus sur les différentes parties de Vertex AI, consultez la documentation.
8. Nettoyage
Comme le notebook est configuré pour expirer au bout de 60 minutes d'inactivité, il n'est pas nécessaire d'arrêter l'instance. Si vous souhaitez arrêter l'instance manuellement, cliquez sur le bouton "Arrêter" dans la section "Vertex AI Workbench" de la console. Si vous souhaitez supprimer le notebook définitivement, cliquez sur le bouton "Supprimer".
Pour supprimer le bucket de stockage, utilisez le menu de navigation de Cloud Console pour accéder à Stockage > Cloud Storage, sélectionnez votre bucket puis cliquez sur "Supprimer" :