1. Panoramica
In questo lab imparerai a utilizzare Vertex AI per l'ottimizzazione degli iperparametri e l'addestramento distribuito. Sebbene questo lab utilizzi TensorFlow per il codice del modello, i concetti sono applicabili anche ad altri framework ML.
Cosa imparerai
Al termine del corso sarai in grado di:
- Addestrare un modello utilizzando l'addestramento distribuito su un container personalizzato
- Avviare più prove del codice di addestramento per l'ottimizzazione automatica degli iperparametri
Il costo totale per eseguire questo lab su Google Cloud è di circa 6$.
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 si concentrerà su Training e Workbench.

3. Panoramica del caso d'uso
In questo lab utilizzerai l'ottimizzazione degli iperparametri per scoprire i parametri ottimali per un modello di classificazione delle immagini addestrato sul set di dati di cavalli o esseri umani dai set di dati TensorFlow.
Ottimizzazione degli iperparametri
L'ottimizzazione degli iperparametri con Vertex AI Training funziona eseguendo più prove dell'applicazione di addestramento con i valori degli iperparametri scelti, impostati entro i limiti specificati. Vertex AI tiene traccia dei risultati di ogni prova ed effettua modifiche per le prove successive.
Per utilizzare l'ottimizzazione degli iperparametri con Vertex AI Training, devi apportare due modifiche al codice di addestramento:
- Definisci un argomento della riga di comando nel modulo di addestramento principale per ogni iperparametro da ottimizzare.
- Utilizza il valore passato in questi argomenti per impostare l'iperparametro corrispondente nel codice dell'applicazione.
Addestramento distribuito
Se hai una singola GPU, TensorFlow utilizzerà questo acceleratore per velocizzare l'addestramento del modello senza alcun lavoro aggiuntivo da parte tua. Tuttavia, se vuoi ottenere un ulteriore aumento delle prestazioni utilizzando più GPU, devi utilizzare tf.distribute, il modulo di TensorFlow per l'esecuzione di un calcolo su più dispositivi.
Questo lab utilizza tf.distribute.MirroredStrategy, che puoi aggiungere alle applicazioni di addestramento con poche modifiche al codice. Questa strategia crea una copia del modello su ogni GPU della macchina. I successivi aggiornamenti dei gradienti avverranno in modo sincrono. Ciò significa che ogni GPU calcola i passaggi in avanti e indietro attraverso il modello su una fetta diversa dei dati di input. I gradienti calcolati da ciascuna di queste fette vengono quindi aggregati su tutte le GPU e calcolati in media in un processo noto come all-reduce. I parametri del modello vengono aggiornati utilizzando questi gradienti medi.
Non devi conoscere i dettagli per completare questo lab, ma se vuoi saperne di più su come funziona l'addestramento distribuito in TensorFlow, guarda il video di seguito:
4. Configura l'ambiente
Per eseguire questo codelab, devi avere un progetto Google Cloud Platform con la fatturazione abilitata. Per creare un progetto, segui le istruzioni riportate qui.
Passaggio 1: abilita l'API Compute Engine
Vai a Compute Engine e seleziona Abilita se non è già abilitato.
Passaggio 2: abilita l'API Container Registry
Vai a Container Registry e seleziona Abilita se non è già abilitato. Lo utilizzerai per creare un container per il tuo job di addestramento personalizzato.
Passaggio 3: abilita l'API Vertex AI
Accedi alla sezione Vertex AI della tua console Cloud e fai clic su Abilita API Vertex AI.

Passaggio 4: crea un'istanza di Vertex AI Workbench
Nella sezione Vertex AI della console Cloud, fai clic su Workbench:

Abilita l'API Notebooks se non è già abilitata.

Una volta abilitata, fai clic su NOTEBOOK GESTITI:

Quindi seleziona NUOVO NOTEBOOK.

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

In Impostazioni avanzate, abilita l'arresto in caso di inattività e imposta il numero di minuti su 60. Ciò significa che il notebook si spegnerà automaticamente quando non è in uso, in modo da non sostenere costi non necessari.

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

Puoi lasciare invariate tutte le altre impostazioni avanzate.
Quindi, fai clic su Crea. Il provisioning dell'istanza richiederà alcuni minuti.
Una volta creata l'istanza, seleziona Apri JupyterLab.

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

5. Scrivi il codice di addestramento
Per iniziare, dal menu Avvio app, apri una finestra Terminale nell'istanza del notebook:

Crea una nuova directory denominata vertex-codelab e vai al suo interno.
mkdir vertex-codelab
cd vertex-codelab
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 vertex-codelab:
+ trainer/
+ task.py
Quindi, apri il file task.py appena creato e incolla tutto il codice riportato di seguito.
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()
Diamo un'occhiata più da vicino al codice ed esaminiamo i componenti specifici per l'addestramento distribuito e l'ottimizzazione degli iperparametri.
Addestramento distribuito
- Nella funzione
main(), viene creato l'oggettoMirroredStrategy. Quindi, racchiudi la creazione delle variabili del modello nell'ambito della strategia. Questo passaggio indica a TensorFlow quali variabili devono essere replicate nelle GPU. - La dimensione del batch viene aumentata di
num_replicas_in_sync. L'aumento della dimensione del batch è una best practice quando si utilizzano strategie di parallelismo dei dati sincrone in TensorFlow. Puoi saperne di più qui.
Ottimizzazione degli iperparametri
- Lo script importa la libreria
hypertune. In un secondo momento, quando creeremo l'immagine container, dovremo assicurarci di installare questa libreria. - La funzione
get_args()definisce un argomento della riga di comando per ogni iperparametro da ottimizzare. In questo esempio, gli iperparametri che verranno ottimizzati sono il tasso di apprendimento, il valore momentum nell'ottimizzatore e il numero di unità nell'ultimo strato nascosto del modello, ma sperimenta pure con altri iperparametri. Il valore passato in questi argomenti viene quindi utilizzato per impostare l'iperparametro corrispondente nel codice (ad es. impostalearning_rate = args.learning_rate) - Alla fine della funzione
main(), la libreriahypertuneviene utilizzata per definire la metrica che desideri ottimizzare. In TensorFlow, il metodo Kerasmodel.fitrestituisce un oggettoHistory. L'attributoHistory.historyè un record dei valori di perdita dell'addestramento e dei valori delle metriche in epoche successive. Se passi i dati di convalida amodel.fit, l'attributoHistory.historyincluderà anche la perdita di convalida e i valori delle metriche. Ad esempio, se addestrassi un modello per tre epoche con dati di convalida e fornissiaccuracycome metrica, l'attributoHistory.historysarebbe simile al seguente dizionario.
{
"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
]
Se desideri che il servizio di ottimizzazione degli iperparametri scopra i valori che massimizzano l'accuratezza di convalida del modello, definisci la metrica come l'ultima voce (o NUM_EPOCS - 1) dell'elenco val_accuracy. Quindi, passa questa metrica a un'istanza di HyperTune. Puoi scegliere la stringa che preferisci per hyperparameter_metric_tag, ma dovrai utilizzare nuovamente la stringa in seguito quando avvierai il job di ottimizzazione dell'iperparametro.
6. Containerizza il codice
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.
Passaggio 1: scrivi il Dockerfile
Dal terminale, assicurati di trovarti nella directory vertex-codelab e crea un Dockerfile vuoto:
touch Dockerfile
Ora dovresti avere quanto segue nella directory vertex-codelab:
+ Dockerfile
+ trainer/
+ task.py
Apri il Dockerfile e copia al suo interno quanto segue:
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"]
Questo Dockerfile utilizza l'immagine Docker GPU TensorFlow Enterprise 2.7 del container di 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.
Passaggio 2: 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/horse-human-codelab:latest"
Configura Docker
gcloud auth configure-docker
Quindi, crea il container eseguendo quanto segue dalla radice della directory vertex-codelab:
docker build ./ -t $IMAGE_URI
Infine, esegui il push in Google Container Registry:
docker push $IMAGE_URI
Passaggio 3: crea un bucket Cloud Storage
Nel job di addestramento, passeremo il percorso a un bucket di gestione temporanea.
Esegui quanto segue nel terminale per creare un nuovo bucket nel tuo progetto.
BUCKET_NAME="gs://${PROJECT_ID}-hptune-bucket"
gsutil mb -l us-central1 $BUCKET_NAME
7. Avvia il job di ottimizzazione degli iperparametri
Passaggio 1: crea un job di addestramento personalizzato con l'ottimizzazione degli iperparametri
Dal launcher, apri un nuovo notebook TensorFlow 2.

Importa l'SDK Vertex AI Python.
from google.cloud import aiplatform
from google.cloud.aiplatform import hyperparameter_tuning as hpt
Per avviare il job di ottimizzazione degli iperparametri, devi prima definire worker_pool_specs, che specifica il tipo di macchina e l'immagine Docker. La seguente specifica definisce una macchina con due GPU NVIDIA Tesla V100.
Dovrai sostituire {PROJECT_ID} in image_uri con il tuo progetto.
# 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"
}
}]
Quindi, definisci parameter_spec, un dizionario che specifica i parametri da ottimizzare. La chiave del dizionario è la stringa assegnata all'argomento della riga di comando per ogni iperparametro, mentre il valore del dizionario è la specifica del parametro.
Per ogni iperparametro, devi definire il tipo e i limiti per i valori che il servizio di ottimizzazione proverà. Gli iperparametri possono essere di tipo Double, Integer, Categorical o Discrete. Se selezioni il tipo Double o Integer, devi fornire un valore minimo e massimo. Se selezioni Categorical o Discrete, devi fornire i valori. Per i tipi Double e Integer, devi anche fornire il valore di Scaling. Puoi scoprire di più su come scegliere la scala migliore in questo video.
# 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)
}
L'ultima specifica da definire è metric_spec, un dizionario che rappresenta la metrica da ottimizzare. La chiave del dizionario è hyperparameter_metric_tag che hai impostato nel codice dell'applicazione di addestramento, mentre il valore è l'obiettivo di ottimizzazione.
# 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'}
Una volta definite le specifiche, creerai un CustomJob, la specifica comune che verrà utilizzata per eseguire il job in ogni prova di ottimizzazione degli iperparametri.
Dovrai sostituire {YOUR_BUCKET} con il bucket creato in precedenza.
# Replace YOUR_BUCKET
my_custom_job = aiplatform.CustomJob(display_name='horses-humans',
worker_pool_specs=worker_pool_specs,
staging_bucket='gs://{YOUR_BUCKET}')
Quindi, crea ed esegui 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()
Ci sono alcuni argomenti da notare:
- max_trial_count: dovrai porre un limite superiore al numero di prove che il servizio eseguirà. Un numero maggiore di prove generalmente porta a risultati migliori, ma ci sarà un punto in cui i risultati diminuiranno dopo il quale ulteriori prove avranno poco o nessun effetto sulla metrica che stai cercando di ottimizzare. Una best practice è iniziare con un numero inferiore di prove e farsi un'idea dell'impatto degli iperparametri scelti prima dello scale up.
- parallel_trial_count: se utilizzi prove parallele, il servizio esegue il provisioning di più cluster di elaborazione dell'addestramento. L'aumento del numero di prove parallele riduce il tempo necessario per eseguire il job di ottimizzazione degli iperparametri; tuttavia, può ridurre l'efficacia del job nel complesso. Questo perché la strategia di ottimizzazione predefinita utilizza i risultati delle prove precedenti per informare l'assegnazione dei valori nelle prove successive.
- search_algorithm: puoi impostare l'algoritmo di ricerca su griglia, casuale o predefinito (Nessuno). L'opzione predefinita applica l'ottimizzazione bayesiana per cercare lo spazio dei possibili valori degli iperparametri ed è l'algoritmo consigliato. Puoi saperne di più su questo algoritmo qui.
Una volta avviato il job, potrai monitorarne lo stato nell'interfaccia utente nella scheda JOB DI OTTIMIZZAZIONE DEGLI IPERPARAMETRI.

Al termine del job, puoi visualizzare e ordinare i risultati delle prove per scoprire la migliore combinazione di valori degli iperparametri.

🎉 Congratulazioni! 🎉
Hai imparato come utilizzare Vertex AI per:
- Eseguire un job di ottimizzazione degli iperparametri con l'addestramento distribuito
Per saperne di più sulle diverse parti di Vertex AI, consulta la documentazione.
8. Esegui la pulizia
Poiché abbiamo configurato il notebook in modo che scada dopo 60 minuti di inattività, non dobbiamo preoccuparci di spegnere l'istanza. Se vuoi spegnere manualmente l'istanza, fai clic sul pulsante Arresta nella sezione Vertex AI Workbench della console. Se vuoi eliminare completamente il notebook, fai clic sul pulsante Elimina.

Per eliminare il bucket di archiviazione, utilizza il menu di navigazione nella console Cloud, vai ad Archiviazione, seleziona il bucket e fai clic su Elimina:
