Vertex AI: addestramento multi-lavoro e Transfer Learning con TensorFlow

1. Panoramica

In questo lab utilizzerai Vertex AI per eseguire un job di addestramento con più worker per un modello TensorFlow.

Cosa imparerai

Imparerai a:

  • Modificare il codice dell'applicazione di addestramento per l'addestramento con più worker
  • Configura e avvia un job di addestramento per più worker dalla UI di Vertex AI
  • Configura e avvia un job di addestramento per più worker con l'SDK Vertex

Il costo totale per l'esecuzione di questo lab su Google Cloud è di circa 5$.

2. Introduzione a Vertex AI

Questo lab utilizza la più recente offerta di prodotti AI disponibile su Google Cloud. Vertex AI integra le offerte ML di Google Cloud in un'esperienza di sviluppo fluida. In precedenza, i modelli addestrati con AutoML e i modelli personalizzati erano accessibili tramite servizi separati. La nuova offerta combina entrambi in un'unica API, insieme ad altri nuovi prodotti. Puoi anche migrare progetti esistenti su Vertex AI. In caso di feedback, consulta la pagina di supporto.

Vertex AI include molti prodotti diversi per supportare i flussi di lavoro ML end-to-end. Questo lab è incentrato sui prodotti evidenziati di seguito: Formazione e Workbench

Panoramica del prodotto Vertex

3. Panoramica del caso d'uso

In questo lab utilizzerai il transfer learning per addestrare un modello di classificazione delle immagini sul set di dati della manioca dai set di dati TensorFlow. L'architettura che utilizzerai è un modello ResNet50 della libreria tf.keras.applications preaddestrato sul set di dati Imagenet.

Perché addestramento distribuito?

Se disponi di una singola GPU, TensorFlow utilizzerà questo acceleratore per accelerare l'addestramento del modello senza alcun intervento aggiuntivo da parte tua. Tuttavia, se vuoi ottimizzare l'uso di più GPU su una singola macchina o su più macchine (ognuna con potenzialmente più GPU), dovrai utilizzare tf.distribute, la libreria di TensorFlow per eseguire un calcolo su più dispositivi. Un dispositivo fa riferimento a una CPU o a un acceleratore, come GPU o TPU, su una macchina su cui TensorFlow può eseguire operazioni.

Il modo più semplice per iniziare l'addestramento distribuito è usare una singola macchina con più dispositivi GPU. Una strategia di distribuzione TensorFlow del modulo tf.distribute gestirà il coordinamento della distribuzione dei dati e degli aggiornamenti dei gradienti in tutte le GPU. Se hai padroneggiato l'addestramento su un singolo host e vuoi scalare ancora di più, l'aggiunta di più macchine al tuo cluster può aiutarti a ottenere un miglioramento delle prestazioni ancora maggiore. Puoi utilizzare un cluster di macchine che sono solo CPU o che hanno ciascuna una o più GPU. Questo lab tratta quest'ultimo caso e mostra come utilizzare MultiWorkerMirroredStrategy per distribuire l'addestramento di un modello TensorFlow su più macchine su Vertex AI.

MultiWorkerMirroredStrategy è una strategia di parallelismo dei dati sincrona che puoi utilizzare con poche modifiche al codice. Viene creata una copia del modello su ogni dispositivo nel cluster. I successivi aggiornamenti del gradiente avverranno in modo sincrono. Ciò significa che ciascun dispositivo worker calcola i passaggi avanti e indietro attraverso il modello su una sezione diversa dei dati di input. I gradienti calcolati da ciascuna di queste sezioni vengono quindi aggregati tra tutti i dispositivi di una macchina e tutte le macchine nel cluster e ridotti (solitamente una media) attraverso un processo noto come "all-reduce". L'ottimizzatore esegue quindi gli aggiornamenti dei parametri con questi gradienti ridotti, mantenendo quindi sincronizzati i dispositivi. Per saperne di più sull'addestramento distribuito con TensorFlow, guarda il video seguente:

4. Configura l'ambiente

Per eseguire questo codelab, è necessario un progetto Google Cloud con fatturazione abilitata. Per creare un progetto, segui le istruzioni riportate qui.

Passaggio 1: abilita l'API Compute Engine

Passa a Compute Engine e seleziona Abilita se non è già abilitato. Ne avrai bisogno per creare la tua istanza di blocco note.

Passaggio 2: attiva l'API Container Registry

Vai a Container Registry e seleziona Abilita, se non è già selezionato. Lo utilizzerai per creare un container per il tuo job di addestramento personalizzato.

Passaggio 3: abilita l'API Vertex AI

Vai alla sezione Vertex AI della tua console Cloud e fai clic su Abilita API Vertex AI.

Dashboard di Vertex AI

Passaggio 4: crea un'istanza di Vertex AI Workbench

Dalla sezione Vertex AI della console Cloud, fai clic su Workbench:

Menu Vertex AI

Abilita l'API Notebooks, se non lo è già.

Notebook_api

Dopo averla attivata, fai clic su NOTEBOOK GESTITI:

Notebooks_UI

Quindi seleziona NUOVO Blocco note.

new_notebook

Assegna un nome al blocco note, quindi fai clic su Impostazioni avanzate.

create_notebook

In Impostazioni avanzate, abilita l'arresto per inattività e imposta il numero di minuti su 60. Ciò significa che il blocco note si arresterà automaticamente quando non è in uso, per evitare costi inutili.

idle_timeout

In Sicurezza, seleziona "Attiva terminale". se non è già abilitato.

enable_terminal

Puoi lasciare invariate tutte le altre impostazioni avanzate.

Quindi, fai clic su Crea. Il provisioning dell'istanza richiederà un paio di minuti.

Una volta creata l'istanza, seleziona Apri JupyterLab.

open_jupyterlab

La prima volta che utilizzi una nuova istanza, ti verrà chiesto di autenticarti. Per farlo, segui i passaggi nell'interfaccia utente.

autenticare

5. containerizza il codice dell'applicazione di addestramento

Invierai questo job di addestramento a Vertex inserendo il codice dell'applicazione di addestramento in un container Docker ed eseguendo il push di questo container a Google Container Registry. Con questo approccio, puoi addestrare un modello creato con qualsiasi framework.

Per iniziare, dal menu Avvio app, apri una finestra Terminale nell'istanza del blocco note:

Apri terminale nel blocco note

Crea una nuova directory chiamata cassava e accedi tramite cd:

mkdir cassava
cd cassava

Passaggio 1: crea un Dockerfile

Il primo passaggio per containerizzare il codice è creare un Dockerfile. Nel Dockerfile includerai tutti i comandi necessari per eseguire l'immagine. Installerà tutte le librerie necessarie e configurerà il punto di accesso per il codice di addestramento.

Dal terminale, crea un Dockerfile vuoto:

touch Dockerfile

Apri il Dockerfile e copia al suo interno quanto segue:

FROM gcr.io/deeplearning-platform-release/tf2-gpu.2-7

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

Questo Dockerfile utilizza l'immagine Docker GPU TensorFlow Enterprise 2.7 del container deep learning. Deep Learning Containers su Google Cloud è dotato di molti framework comuni di ML e data science preinstallati. Dopo aver scaricato l'immagine, questo Dockerfile configura il punto di accesso per il codice di addestramento. Non hai ancora creato questi file: nel passaggio successivo aggiungerai il codice per l'addestramento e la messa a punto del modello.

Passaggio 2: crea un bucket Cloud Storage

In questo job di addestramento, esporterai il modello TensorFlow addestrato in un bucket Cloud Storage. Dal tuo terminale, esegui quanto segue per definire una variabile env per il tuo progetto, assicurandoti di sostituire your-cloud-project con l'ID del tuo progetto:

PROJECT_ID='your-cloud-project'

Quindi, esegui questo comando nel terminale per creare un nuovo bucket nel tuo progetto.

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

Passaggio 3: aggiungi il codice di addestramento del modello

Dal tuo terminale, esegui quanto segue per creare una directory per il codice di addestramento e un file Python in cui aggiungerai il codice:

mkdir trainer
touch trainer/task.py

Ora dovresti avere quanto segue nella directory cassava/:

+ Dockerfile
+ trainer/
    + task.py

Successivamente, apri il file task.py che hai appena creato e copia il codice seguente. Dovrai sostituire {your-gcs-bucket} con il nome del bucket Cloud Storage che hai appena creato.

import tensorflow as tf
import tensorflow_datasets as tfds
import os


PER_REPLICA_BATCH_SIZE = 64
EPOCHS = 2

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

def preprocess_data(image, label):
  '''Resizes and scales images.'''

  image = tf.image.resize(image, (300,300))
  return tf.cast(image, tf.float32) / 255., label


def create_dataset(batch_size):
  '''Loads Cassava dataset and preprocesses data.'''

  data, info = tfds.load(name='cassava', as_supervised=True, with_info=True)
  number_of_classes = info.features['label'].num_classes
  train_data = data['train'].map(preprocess_data,
                                 num_parallel_calls=tf.data.experimental.AUTOTUNE)
  train_data  = train_data.shuffle(1000)
  train_data  = train_data.batch(batch_size)
  train_data  = train_data.prefetch(tf.data.experimental.AUTOTUNE)

  # Set AutoShardPolicy
  options = tf.data.Options()
  options.experimental_distribute.auto_shard_policy = tf.data.experimental.AutoShardPolicy.DATA
  train_data = train_data.with_options(options)

  return train_data, number_of_classes


def create_model(number_of_classes):
  '''Creates and compiles pretrained ResNet50 model.'''

  base_model = tf.keras.applications.ResNet50(weights='imagenet', include_top=False)
  x = base_model.output
  x = tf.keras.layers.GlobalAveragePooling2D()(x)
  x = tf.keras.layers.Dense(1016, activation='relu')(x)
  predictions = tf.keras.layers.Dense(number_of_classes, activation='softmax')(x)
  model = tf.keras.Model(inputs=base_model.input, outputs=predictions)

  model.compile(
      loss='sparse_categorical_crossentropy',
      optimizer=tf.keras.optimizers.Adam(0.0001),
      metrics=['accuracy'])

  return model


def _is_chief(task_type, task_id):
  '''Helper function. Determines if machine is chief.'''

  return task_type == 'chief'


def _get_temp_dir(dirpath, task_id):
  '''Helper function. Gets temporary directory for saving model.'''

  base_dirpath = 'workertemp_' + str(task_id)
  temp_dir = os.path.join(dirpath, base_dirpath)
  tf.io.gfile.makedirs(temp_dir)
  return temp_dir


def write_filepath(filepath, task_type, task_id):
  '''Helper function. Gets filepath to save model.'''

  dirpath = os.path.dirname(filepath)
  base = os.path.basename(filepath)
  if not _is_chief(task_type, task_id):
    dirpath = _get_temp_dir(dirpath, task_id)
  return os.path.join(dirpath, base)


def main():
  # Create strategy
  strategy = tf.distribute.MultiWorkerMirroredStrategy()

  # Get data
  global_batch_size = PER_REPLICA_BATCH_SIZE * strategy.num_replicas_in_sync
  train_data, number_of_classes = create_dataset(global_batch_size)

  # Wrap variable creation within strategy scope
  with strategy.scope():
    model = create_model(number_of_classes)

  model.fit(train_data, epochs=EPOCHS)

  # Determine type and task of the machine from
  # the strategy cluster resolver
  task_type, task_id = (strategy.cluster_resolver.task_type,
                        strategy.cluster_resolver.task_id)

  # Based on the type and task, write to the desired model path
  write_model_path = write_filepath(BUCKET, task_type, task_id)
  model.save(write_model_path)

if __name__ == "__main__":
    main()

Prima di creare il container, diamo uno sguardo più approfondito al codice, che utilizza MultiWorkerMirroredStrategy dell'API tf.distribute.Strategy.

Il codice contiene alcuni componenti necessari per far funzionare il tuo codice con MultiWorkerMirroredStrategy.

  1. I dati devono essere sottoposti a sharding, ovvero a ogni worker viene assegnato un sottoinsieme dell'intero set di dati. Pertanto, ad ogni passaggio, ogni worker elabora una dimensione batch globale di elementi del set di dati non sovrapposti. Questo partizionamento orizzontale avviene automaticamente con tf.data.experimental.AutoShardPolicy, che può essere impostato su FILE o DATA. In questo esempio, la funzione create_dataset() imposta AutoShardPolicy su DATA perché il set di dati della manioca non viene scaricato come file multipli. Tuttavia, se non imposti il criterio su DATA, verrà attivato il criterio AUTO predefinito e il risultato finale sarà lo stesso. Scopri di più sullo partizionamento orizzontale dei set di dati con MultiWorkerMirroredStrategy qui.
  2. Nella funzione main() viene creato l'oggetto MultiWorkerMirroredStrategy. A questo punto, completerai la creazione delle variabili del modello nell'ambito della strategia. Questo passaggio fondamentale indica a TensorFlow quali variabili devono essere sottoposte a mirroring tra le repliche.
  3. La dimensione del batch viene scalata dall'num_replicas_in_sync. Ciò garantisce che ogni replica elabori lo stesso numero di esempi in ogni passaggio. La scalabilità della dimensione del batch è una best practice quando si utilizzano strategie di parallelismo dei dati sincroni in TensorFlow.
  4. Salvare il modello è leggermente più complicato nel caso con più worker perché la destinazione deve essere diversa per ogni worker. Il chief worker salverà il modello nella directory del modello desiderata, mentre gli altri worker salvano il modello in directory temporanee. È importante che queste directory temporanee siano univoche per evitare che più worker scrivano nella stessa posizione. Il risparmio può contenere operazioni collettive, cioè tutti i lavoratori devono salvare, non solo il capo. Le funzioni _is_chief(), _get_temp_dir(), write_filepath() e la funzione main() includono tutte il codice boilerplate che consente di salvare il modello.

Tieni presente che se hai utilizzato MultiWorkerMirroredStrategy in un ambiente diverso, potresti aver configurato la variabile di ambiente TF_CONFIG. Vertex AI imposta TF_CONFIG automaticamente per te, quindi non devi definire questa variabile su ogni macchina nel tuo cluster.

Passaggio 4: crea il container

Dal tuo terminale, esegui quanto segue per definire una variabile env per il tuo progetto, assicurandoti di sostituire your-cloud-project con l'ID del tuo progetto:

PROJECT_ID='your-cloud-project'

Definisci una variabile con l'URI dell'immagine container in Google Container Registry:

IMAGE_URI="gcr.io/$PROJECT_ID/multiworker:cassava"

Configura Docker

gcloud auth configure-docker

Quindi, crea il container eseguendo quanto segue dalla radice della directory cassava:

docker build ./ -t $IMAGE_URI

Infine, invialo a Google Container Registry:

docker push $IMAGE_URI

Dopo il push del container in Container Registry, ora puoi avviare un job di addestramento.

6. Esegui un job di addestramento multi-worker su Vertex AI

Questo lab utilizza l'addestramento personalizzato tramite un container personalizzato su Google Container Registry, ma puoi anche eseguire un job di addestramento con i container predefiniti.

Per iniziare, vai alla sezione Addestramento nella sezione Vertex della console Cloud:

Menu uCAIP

Passaggio 1: configura il job di addestramento

Fai clic su Crea per inserire i parametri per il job di addestramento.

  • In Set di dati, seleziona Nessun set di dati gestito
  • Quindi seleziona Addestramento personalizzato (avanzato) come metodo di addestramento e fai clic su Continua.
  • Inserisci multiworker-cassava (o un nome che preferisci) in Nome modello
  • Fai clic su Continua.

Nel passaggio Impostazioni contenitore, seleziona Container personalizzato:

Opzione container personalizzato

Nella prima casella (Immagine container), inserisci il valore della variabile IMAGE_URI della sezione precedente. Dovrebbe essere: gcr.io/your-cloud-project/multiworker:cassava, con il tuo ID progetto. Lascia vuoti gli altri campi e fai clic su Continua.

Ignora il passaggio sugli iperparametri facendo di nuovo clic su Continua.

Passaggio 2: configura il cluster di computing

Vertex AI fornisce 4 pool di worker per coprire i diversi tipi di attività delle macchine.

Pool di worker 0 configura il principale, principale, di pianificazione o "master". In MultiWorkerMirroredStrategy, tutte le macchine sono designate come worker, ovvero le macchine fisiche su cui viene eseguito il calcolo replicato. Oltre che ogni macchina sia un worker, deve esserci un worker che svolge alcune attività extra come il salvataggio dei checkpoint e la scrittura dei file di riepilogo su TensorBoard. Questa macchina è nota come "Chief". Esiste sempre un solo Chief worker, quindi il conteggio dei worker per il pool di worker 0 sarà sempre 1.

In Compute e prezzi, lascia la regione selezionata così com'è e configura Pool di worker 0 come segue:

Worker_pool_0

Il pool di worker 1 è il luogo in cui configuri i worker per il cluster.

Configura Pool di worker 1 come segue:

Worker_pool_1

Il cluster è ora configurato in modo da avere due macchine solo CPU. Quando viene eseguito il codice dell'applicazione di addestramento, MultiWorkerMirroredStrategy distribuisce l'addestramento su entrambe le macchine.

MultiWorkerMirroredStrategy include solo i tipi di attività principale e worker, quindi non è necessario configurare i pool di worker aggiuntivi. Tuttavia, se utilizzi ParameterServerStrategy di TensorFlow, devi configurare i server dei parametri nel pool di worker 2. Se volessi aggiungere un valutatore al cluster, devi configurare la macchina nel pool di worker 3.

Fai clic su Inizia addestramento per dare il via al job di ottimizzazione degli iperparametri. Nella sezione Addestramento della console, nella scheda PIPELINE DI FORMAZIONE, vedrai il job che hai appena avviato:

Job di addestramento

🎉 Complimenti! 🎉

Hai imparato come utilizzare Vertex AI per:

  • Avvia un job di addestramento per più worker per il codice di addestramento fornito in un container personalizzato. In questo esempio hai utilizzato un modello TensorFlow, ma puoi addestrare un modello creato con qualsiasi framework utilizzando container personalizzati o integrati.

Per scoprire di più sulle diverse parti di Vertex, consulta la documentazione.

7. [Facoltativo] Utilizza l'SDK Vertex

La sezione precedente ha mostrato come avviare il job di addestramento tramite l'interfaccia utente. In questa sezione viene illustrato un modo alternativo per inviare il job di addestramento mediante l'API Vertex Python.

Torna all'istanza del blocco note e crea un blocco note TensorFlow 2 dall'Avvio app:

new_notebook

Importa l'SDK Vertex AI.

from google.cloud import aiplatform

Per avviare il job di addestramento per più worker, devi prima definire la specifica del pool di worker. Tieni presente che l'utilizzo delle GPU nella specifica è completamente facoltativo e puoi rimuovere accelerator_type e accelerator_count se preferisci un cluster con solo CPU, come mostrato nella sezione precedente.

# The spec of the worker pools including machine type and Docker image
# Be sure to replace {YOUR-PROJECT-ID} with your project ID.
worker_pool_specs=[
     {
        "replica_count": 1,
        "machine_spec": {
          "machine_type": "n1-standard-8", "accelerator_type": "NVIDIA_TESLA_V100", "accelerator_count": 1
        },
        "container_spec": {"image_uri": "gcr.io/{YOUR-PROJECT-ID}/multiworker:cassava"}
      },
      {
        "replica_count": 1,
        "machine_spec": {
          "machine_type": "n1-standard-8", "accelerator_type": "NVIDIA_TESLA_V100", "accelerator_count": 1
        },
        "container_spec": {"image_uri": "gcr.io/{YOUR-PROJECT-ID}/multiworker:cassava"}
      }
]

Ora crea ed esegui un CustomJob. Per la gestione temporanea, devi sostituire {YOUR_BUCKET} con un bucket nel tuo progetto. Puoi utilizzare lo stesso bucket che hai creato in precedenza.

# Replace YOUR_BUCKET
my_multiworker_job = aiplatform.CustomJob(display_name='multiworker-cassava-sdk',
                              worker_pool_specs=worker_pool_specs,
                              staging_bucket='gs://{YOUR_BUCKET}')

my_multiworker_job.run()

Nella sezione Addestramento della console, nella scheda JOB PERSONALIZZATI vedrai il tuo job di addestramento:

Job personalizzati

8. Esegui la pulizia

Poiché abbiamo configurato il timeout del blocco note dopo 60 minuti di inattività, non dobbiamo preoccuparci di arrestare l'istanza. Se vuoi arrestare manualmente l'istanza, fai clic sul pulsante Arresta nella sezione Vertex AI Workbench della console. Per eliminare completamente il blocco note, fai clic sul pulsante Elimina.

Arresta istanza

Per eliminare il bucket di archiviazione, utilizzando il menu di navigazione nella console Cloud, vai a Storage, seleziona il bucket e fai clic su Elimina:

Elimina spazio di archiviazione