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 à l'aide de la fonctionnalité d'empaquetage automatique. Les jobs d'entraînement personnalisé sur Vertex AI utilisent des conteneurs. Si vous ne souhaitez pas créer votre propre image, vous pouvez utiliser auotpackaging, qui va créer une image Docker personnalisée basée sur votre code, transférer l'image vers Container Registry et démarrer 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 va prédire si une critique de film est positive ou négative. L'ensemble de données sera téléchargé à partir de la bibliothèque d'ensembles de données Hugging Face et le modèle BERT de la bibliothèque de transformateurs Hugging Face.

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

Ensuite, cliquez 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 remarques concernant le code:

  • CHECKPOINT est le modèle que nous voulons affiner. Dans le cas présent, nous utilisons BERT.
  • La méthode TFAutoModelForSequenceClassification charge l'architecture du modèle de langage spécifiée et les pondérations dans TensorFlow, puis ajoute une tête de classification au-dessus avec des pondérations initialisées de manière aléatoire. Dans le cas présent, 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 et exécuter l'image en tant que conteneur sur votre machine locale. 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 job d'entraînement, nous allons exporter le 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'

Ensuite, créez 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écutons le job d'entraînement personnalisé sur Vertex AI Training, nous utilisons 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 dans Vertex AI Training.

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

Donnez ensuite un nom à 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 devrons donc les fournir selon les besoins. 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 et saisissez la commande suivante dans votre terminal :

touch requirements.txt

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

+ requirements.txt
+ trainer/
    + task.py

Ouvrez le fichier d'exigences 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 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 doit s'afficher. 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 vous pouvez voir l'entraînement du modèle. L'écran qui s'affiche devrait ressembler à ce qui suit :

local_training

Comme nous n'utilisons pas de GPU en local, l'entraînement du modèle prendra beaucoup de temps. Vous pouvez utiliser la combinaison de touches Ctrl+C et annuler l'entraînement en 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 repackaging.

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é d'autopackaging pour lancer notre job d'entraînement personnalisé sur Vertex AI Training. À l'aide d'une seule commande, cette fonctionnalité:

  • 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 utilisez la commande cd au-dessus de votre répertoire autopkg-codelab.

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

Spécifiez l'image GPU TensorFlow préconfigurée de Vertex AI Training en tant qu'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 Vertex AI Training que nous avons défini en tant que BASE_GPU_IMAGE. La fonctionnalité d'autopackaging installe ensuite les bibliothèques d'ensembles de données et de transformateurs avec pip, comme spécifié dans notre 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. Ce champ définit la configuration du pool de nœuds de calcul utilisée par le job personnalisé. 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 la machine. Cliquez ici pour connaître les types acceptés.
  • replica-count: nombre d'instances répliquées de nœuds de calcul à utiliser pour ce pool de nœuds de calcul. La valeur par défaut 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 pour chaque VM du pool de nœuds de calcul. La valeur par défaut 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. Au lieu d'afficher 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" de la console Cloud. Votre job devrait être en cours d'exécution sous JOBS PERSONNALISÉS.

training_job

Cette tâche prendra environ 20 minutes.

Une fois l'opération terminée, vous devriez voir les artefacts de modèle enregistrés suivants 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 autopackaging

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