Vertex AI: utiliser l'autopackaging pour affiner BERT avec Hugging Face sur Vertex AI Training

1. Présentation

Dans cet atelier, vous allez apprendre à exécuter un job d'entraînement personnalisé sur Vertex AI Training avec la fonctionnalité d'empaquetage automatique. Les jobs d'entraînement personnalisés sur Vertex AI utilisent des conteneurs. Si vous ne souhaitez pas créer votre propre image, vous pouvez utiliser l'empaquetage automatique, qui crée une image Docker personnalisée à partir de votre code, la transfère vers Container Registry et démarre une CustomJob basée sur l'image.

Objectifs

Vous allez apprendre à effectuer les opérations suivantes :

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

2. Présentation du cas d'utilisation

À l'aide des bibliothèques de Hugging Face, vous allez affiner un modèle Bert sur l'ensemble de données IMDB. Le modèle prédira si une critique de film est positive ou négative. L'ensemble de données sera téléchargé depuis la bibliothèque d'ensembles de données Hugging Face et le modèle Bert depuis la bibliothèque Hugging Face Transformers.

3. 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 Training et Workbench.

Présentation des produits Vertex

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

Cliquez ensuite sur NOTEBOOKS GÉRÉS:

Notebooks_UI

Sélectionnez ensuite NOUVEAU NOTEBOOK.

new_notebook

Attribuez un nom à votre notebook, puis cliquez sur Paramètres avancés.

create_notebook

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.

idle_timeout

Vous pouvez conserver tous les autres paramètres avancés tels quels.

Cliquez ensuite sur Créer.

Une fois l'instance créée, sélectionnez Ouvrir JupyterLab.

open_jupyterlab

La première fois que vous utilisez une nouvelle instance, vous êtes invité à vous authentifier.

authenticate

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 :

launcher_terminal

Créez un répertoire appelé autopkg-codelab et utilisez la commande cd pour y accéder.

mkdir autopkg-codelab
cd autopkg-codelab

Depuis votre terminal, exécutez le code suivant afin de créer un répertoire pour le code d'entraînement et un fichier Python dans lequel vous ajouterez le code :

mkdir trainer
touch trainer/task.py

Votre répertoire autopkg-codelab/ doit maintenant contenir les éléments suivants :

+ trainer/
    + task.py

Ouvrez ensuite le fichier task.py que vous venez de créer et copiez-y le code ci-dessous.

import argparse

import tensorflow as tf
from datasets import load_dataset
from transformers import AutoTokenizer
from transformers import TFAutoModelForSequenceClassification

CHECKPOINT = "bert-base-cased"

def get_args():
  '''Parses args.'''

  parser = argparse.ArgumentParser()
  parser.add_argument(
      '--epochs',
      required=False,
      default=3,
      type=int,
      help='number of epochs')
  parser.add_argument(
      '--job_dir',
      required=True,
      type=str,
      help='bucket to store saved model, include gs://')
  args = parser.parse_args()
  return args


def create_datasets():
    '''Creates a tf.data.Dataset for train and evaluation.'''

    raw_datasets = load_dataset('imdb')
    tokenizer = AutoTokenizer.from_pretrained(CHECKPOINT)
    tokenized_datasets = raw_datasets.map((lambda examples: tokenize_function(examples, tokenizer)), batched=True)

    # To speed up training, we use only a portion of the data.
    # Use full_train_dataset and full_eval_dataset if you want to train on all the data.
    small_train_dataset = tokenized_datasets['train'].shuffle(seed=42).select(range(1000))
    small_eval_dataset = tokenized_datasets['test'].shuffle(seed=42).select(range(1000))
    full_train_dataset = tokenized_datasets['train']
    full_eval_dataset = tokenized_datasets['test']

    tf_train_dataset = small_train_dataset.remove_columns(['text']).with_format("tensorflow")
    tf_eval_dataset = small_eval_dataset.remove_columns(['text']).with_format("tensorflow")

    train_features = {x: tf_train_dataset[x] for x in tokenizer.model_input_names}
    train_tf_dataset = tf.data.Dataset.from_tensor_slices((train_features, tf_train_dataset["label"]))
    train_tf_dataset = train_tf_dataset.shuffle(len(tf_train_dataset)).batch(8)

    eval_features = {x: tf_eval_dataset[x] for x in tokenizer.model_input_names}
    eval_tf_dataset = tf.data.Dataset.from_tensor_slices((eval_features, tf_eval_dataset["label"]))
    eval_tf_dataset = eval_tf_dataset.batch(8)

    return train_tf_dataset, eval_tf_dataset


def tokenize_function(examples, tokenizer):
    '''Tokenizes text examples.'''

    return tokenizer(examples['text'], padding='max_length', truncation=True)


def main():
    args = get_args()
    train_tf_dataset, eval_tf_dataset = create_datasets()
    model = TFAutoModelForSequenceClassification.from_pretrained(CHECKPOINT, num_labels=2)

    model.compile(
        optimizer=tf.keras.optimizers.Adam(learning_rate=0.01),
        loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
        metrics=tf.metrics.SparseCategoricalAccuracy(),
    )

    model.fit(train_tf_dataset, validation_data=eval_tf_dataset, epochs=args.epochs)
    model.save(f'{args.job_dir}/model_output')


if __name__ == "__main__":
    main()

Quelques points à noter concernant le code:

  • CHECKPOINT est le modèle que nous souhaitons ajuster. Dans ce cas, nous utilisons Bert.
  • La méthode TFAutoModelForSequenceClassification charge l'architecture du modèle de langage et les poids spécifiés dans TensorFlow, puis ajoute un nœud de classification avec des poids initialisés de manière aléatoire. Dans ce cas, nous avons un problème de classification binaire (positif ou négatif). Nous spécifions donc num_labels=2 pour ce classificateur.

6. Conteneuriser et exécuter du code d'entraînement en local

Vous pouvez utiliser la commande gcloud ai custom-jobs local-run pour créer une image de conteneur Docker basée sur votre code d'entraînement, puis exécuter l'image en tant que conteneur sur votre ordinateur local. L'exécution d'un conteneur en local exécute votre code d'entraînement de la même manière que sur Vertex AI Training. Elle peut vous aider à déboguer les problèmes liés à votre code avant d'effectuer un entraînement personnalisé sur Vertex AI.

Dans notre tâche d'entraînement, nous allons exporter notre modèle entraîné vers un bucket Cloud Storage. 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'

Créez ensuite un bucket. Si vous disposez déjà d'un bucket, n'hésitez pas à l'utiliser à la place.

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

Lorsque nous exécuterons le job d'entraînement personnalisé sur Vertex AI Training, nous utiliserons un GPU. Toutefois, comme nous n'avons pas spécifié notre instance Workbench avec des GPU, nous allons utiliser une image basée sur le processeur pour les tests en local. Dans cet exemple, nous utilisons un conteneur prédéfini pour l'entraînement Vertex AI.

Exécutez la commande suivante pour définir l'URI d'une image Docker à utiliser comme base du conteneur.

BASE_CPU_IMAGE=us-docker.pkg.dev/vertex-ai/training/tf-cpu.2-7:latest

Définissez ensuite un nom pour l'image Docker créée par la commande d'exécution locale.

OUTPUT_IMAGE=$PROJECT_ID-local-package-cpu:latest

Notre code d'entraînement utilise les ensembles de données et les bibliothèques de transformateurs Hugging Face. Ces bibliothèques ne sont pas incluses dans l'image que nous avons sélectionnée comme image de base. Nous devons donc les indiquer comme exigences. Pour ce faire, nous allons créer un fichier requirements.txt dans notre répertoire autopkg-codelab.

Assurez-vous d'être dans le répertoire autopkg-codelab, puis saisissez ce qui suit dans le terminal.

touch requirements.txt

Votre répertoire autopkg-codelab doit maintenant contenir les éléments suivants :

+ requirements.txt
+ trainer/
    + task.py

Ouvrez le fichier de spécifications et collez-y le code suivant :

datasets==1.18.2
transformers==4.16.2

Enfin, exécutez la commande gcloud ai custom-jobs local-run pour lancer l'entraînement sur notre instance gérée par Workbench.

gcloud ai custom-jobs local-run \
--executor-image-uri=$BASE_CPU_IMAGE \
--python-module=trainer.task \
--output-image-uri=$OUTPUT_IMAGE \
-- \
--job_dir=$BUCKET_NAME

L'image Docker devrait être créée. Les dépendances que nous avons ajoutées au fichier requirements.txt seront installées avec pip. La première fois que vous exécutez cette commande, l'opération peut prendre quelques minutes. Une fois l'image créée, le fichier task.py commence à s'exécuter et l'entraînement du modèle s'affiche. L'écran qui s'affiche devrait ressembler à ce qui suit :

local_training

Comme nous n'utilisons pas de GPU localement, l'entraînement du modèle prendra beaucoup de temps. Vous pouvez appuyer sur Ctrl+C pour annuler l'entraînement local au lieu d'attendre la fin de la tâche.

Notez que si vous souhaitez effectuer d'autres tests, vous pouvez également exécuter directement l'image créée ci-dessus, sans la reconditionner.

gcloud beta ai custom-jobs local-run \
--executor-image-uri=$OUTPUT_IMAGE \
-- \
--job_dir=$BUCKET_NAME \
--epochs=1

7. Créer une tâche personnalisée

Maintenant que nous avons testé le mode local, nous allons utiliser la fonctionnalité de création automatique de package pour lancer notre job d'entraînement personnalisé sur Vertex AI Training. Cette fonctionnalité permet d'effectuer les actions suivantes en une seule commande:

  • Créer une image Docker personnalisée basée sur votre code
  • Stocker l'image dans Container Registry
  • Démarrer une opération CustomJob basée sur l'image

Revenez au terminal et montez d'un niveau au-dessus de votre répertoire autopkg-codelab.

+ autopkg-codelab
  + requirements.txt
  + trainer/
      + task.py

Spécifiez l'image GPU TensorFlow prédéfinie de Vertex AI Training comme image de base pour le job d'entraînement personnalisé.

BASE_GPU_IMAGE=us-docker.pkg.dev/vertex-ai/training/tf-gpu.2-7:latest

Exécutez ensuite la commande gcloud ai custom-jobs create. Tout d'abord, cette commande crée une image Docker personnalisée basée sur le code d'entraînement. L'image de base est le conteneur prédéfini d'entraînement Vertex AI que nous avons défini sur BASE_GPU_IMAGE. La fonctionnalité d'autopackaging installe ensuite les ensembles de données et les bibliothèques de transformateurs via pip, comme indiqué dans le fichier requirements.txt.

gcloud ai custom-jobs create \
--region=us-central1 \
--display-name=fine_tune_bert \
--args=--job_dir=$BUCKET_NAME \
--worker-pool-spec=machine-type=n1-standard-4,replica-count=1,accelerator-type=NVIDIA_TESLA_V100,executor-image-uri=$BASE_GPU_IMAGE,local-package-path=autopkg-codelab,python-module=trainer.task

Examinons l'argument worker-pool-spec. Il définit la configuration du pool de nœuds de calcul utilisée par la tâche personnalisée. Vous pouvez spécifier plusieurs spécifications de pool de nœuds de calcul afin de créer un job personnalisé avec plusieurs pools de nœuds de calcul pour l'entraînement distribué. Dans cet exemple, nous ne spécifions qu'un seul pool de nœuds de calcul, car notre code d'entraînement n'est pas configuré pour l'entraînement distribué.

Voici quelques-uns des principaux champs de cette spécification:

  • machine-type (obligatoire): type de machine. Cliquez ici pour connaître les types acceptés.
  • replica-count: nombre d'instances dupliquées de nœuds de calcul à utiliser pour ce pool de nœuds de calcul. Par défaut, la valeur est 1.
  • accelerator-type: type de GPU. Cliquez ici pour connaître les types acceptés. Dans cet exemple, nous avons spécifié un GPU NVIDIA Tesla V100.
  • accelerator-count: nombre de GPU à utiliser par chaque VM du pool de nœuds de calcul. Par défaut, la valeur est 1.
  • executor-image-uri: URI d'une image de conteneur qui exécutera le package fourni. Ceci est défini sur notre image de base.
  • local-package-path: chemin d'accès local d'un dossier contenant le code d'entraînement.
  • python-module: nom du module Python à exécuter dans le package fourni.

Comme lors de l'exécution de la commande locale, vous verrez l'image Docker en cours de création, puis le job d'entraînement démarrer. Sauf qu'au lieu de voir le résultat du job d'entraînement, le message suivant confirme que le job d'entraînement a bien été lancé. Notez que la première fois que vous exécutez la commande custom-jobs create, la création et le transfert de l'image peuvent prendre quelques minutes.

training_started

Revenez à la section "Vertex AI Training" (Entraînement Vertex AI) de la console Cloud. Sous JOBS PERSONNALISÉS (Tâches personnalisées), vous devriez voir votre tâche en cours d'exécution.

training_job

L'opération prendra environ 20 minutes.

Une fois l'opération terminée, les artefacts de modèle enregistrés suivants devraient s'afficher dans le répertoire model_output de votre bucket.

model_output

🎉 Félicitations ! 🎉

Vous savez désormais utiliser Vertex AI pour :

  • Conteneuriser et exécuter du code d'entraînement en local
  • Envoyer des jobs d'entraînement à Vertex AI Training avec le packaging automatique

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

delete

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

Supprimer l'espace de stockage