1. Panoramica
In questo lab, esaminerai un flusso di lavoro di addestramento ML completo su Google Cloud, utilizzando PyTorch per creare il modello. Da un ambiente Cloud AI Platform Notebooks, imparerai a pacchettizzare il job di addestramento per eseguirlo su AI Platform Training con l'ottimizzazione degli iperparametri.
Cosa imparerai
Al termine del corso sarai in grado di:
- Crea un'istanza di AI Platform Notebooks
- Crea un modello PyTorch
- Addestra il modello con l'ottimizzazione degli iperparametri su AI Platform Training
Il costo totale per eseguire questo lab su Google Cloud è di circa 1$.
2. 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: attiva l'API Cloud AI Platform Models
Vai alla sezione Modelli AI Platform della console Cloud e fai clic su Abilita se non è già abilitata.

Passaggio 2: abilita l'API Compute Engine
Vai a Compute Engine e seleziona Abilita se non è già abilitato. Ne avrai bisogno per creare la tua istanza di blocco note.
Passaggio 3: crea un'istanza di AI Platform Notebooks
Vai alla sezione AI Platform Notebooks della tua console Cloud e fai clic su Nuova istanza. Quindi, seleziona il tipo di istanza PyTorch più recente (senza GPU):

Utilizza le opzioni predefinite o assegna un nome personalizzato, se vuoi, poi fai clic su Crea. Una volta creata l'istanza, seleziona Apri JupyterLab:

Dopodiché, apri un'istanza di Python 3 Notebook dall'Avvio app:

Ora puoi iniziare.
Passaggio 5: importa i pacchetti Python
Nella prima cella del notebook, aggiungi le seguenti importazioni ed esegui la cella. Puoi eseguirlo premendo il pulsante Freccia destra nel menu in alto o premendo Comando-Invio:
import datetime
import numpy as np
import os
import pandas as pd
import time
Noterai che qui non importiamo PyTorch. Questo perché eseguiamo il job di addestramento su AI Platform Training, non dalla nostra istanza del notebook.
3. Crea un pacchetto per il job di addestramento
Per eseguire il job di addestramento su AI Platform Training, avremo bisogno del codice di addestramento pacchettizzato localmente nell'istanza Notebooks e di un bucket Cloud Storage per archiviare gli asset del job. Per prima cosa, creiamo un bucket di archiviazione. Puoi saltare questo passaggio se ne hai già uno.
Passaggio 1: crea un bucket Cloud Storage per il modello
Definiamo innanzitutto alcune variabili di ambiente che utilizzeremo per il resto del codelab. Compila i valori riportati di seguito con il nome del tuo progetto Google Cloud e il nome del bucket Cloud Storage che vuoi creare (deve essere univoco a livello globale):
# Update these to your own GCP project, model, and version names
GCP_PROJECT = 'your-gcp-project'
BOCKET_URL = 'gs://storage_bucket_name'
Ora siamo pronti per creare un bucket di archiviazione, a cui faremo riferimento quando avvieremo il job di addestramento.
Esegui questo comando gsutil dal notebook per creare un bucket:
!gsutil mb $BUCKET_URL
Passaggio 2: crea i file iniziali per il nostro pacchetto Python
Per eseguire un job di addestramento su AI Platform, dobbiamo configurare il nostro codice come pacchetto Python. È costituito da un file setup.py nella nostra directory principale che specifica eventuali dipendenze da pacchetti esterni, una sottodirectory con il nome del nostro pacchetto (qui lo chiameremo trainer/) e un file __init__.py vuoto all'interno di questa sottodirectory.
Innanzitutto, scriviamo il file setup.py. Utilizziamo i comandi magici %%writefile di iPython per salvare il file nella nostra istanza. Qui abbiamo specificato tre librerie esterne che utilizzeremo nel nostro codice di addestramento: PyTorch, Scikit-learn e Pandas:
%%writefile setup.py
from setuptools import find_packages
from setuptools import setup
REQUIRED_PACKAGES = ['torch>=1.5', 'scikit-learn>=0.20', 'pandas>=1.0']
setup(
name='trainer',
version='0.1',
install_requires=REQUIRED_PACKAGES,
packages=find_packages(),
include_package_data=True,
description='My training application package.'
)
Successivamente, creiamo la directory trainer/ e il file init.py vuoto al suo interno. Python utilizza questo file per riconoscere che si tratta di un pacchetto:
!mkdir trainer
!touch trainer/__init__.py
Ora siamo pronti per iniziare a creare il job di addestramento.
4. Visualizzare l'anteprima del set di dati
Questo lab si concentra sugli strumenti per l'addestramento dei modelli, ma diamo una rapida occhiata al set di dati che utilizzeremo per addestrare il modello. Utilizzeremo il set di dati sulla natalità disponibile in BigQuery. Contiene dati sulle nascite negli Stati Uniti per diversi decenni. Utilizzeremo alcune colonne del set di dati per prevedere il peso di un bambino alla nascita. Il set di dati originale è piuttosto grande e utilizzeremo un sottoinsieme che abbiamo reso disponibile in un bucket Cloud Storage.
Passaggio 1: scarica il set di dati BigQuery sulla natalità
Scarichiamo la versione del set di dati che abbiamo reso disponibile in Cloud Storage in un DataFrame Pandas e visualizziamone l'anteprima.
natality = pd.read_csv('https://storage.googleapis.com/ml-design-patterns/natality.csv')
natality.head()
Questo set di dati ha poco meno di 100.000 righe. Utilizzeremo 5 caratteristiche per prevedere il peso alla nascita di un bambino: l'età della madre e del padre, le settimane di gestazione, l'aumento di peso della madre in libbre e il genere del bambino rappresentato come valore booleano.
5. Definisci il job di addestramento con l'ottimizzazione degli iperparametri
Scriveremo lo script di addestramento in un file chiamato model.py all'interno della sottodirectory trainer/ creata in precedenza. Il nostro job di addestramento verrà eseguito su AI Platform Training e utilizzerà anche il servizio di ottimizzazione degli iperparametri di AI Platform per trovare gli iperparametri ottimali per il nostro modello utilizzando l'ottimizzazione bayesiana.
Passaggio 1: crea lo script di addestramento
Innanzitutto, creiamo il file Python con lo script di addestramento. Poi analizzeremo cosa succede al suo interno. L'esecuzione di questo comando %%writefile scriverà il codice del modello in un file Python locale:
%%writefile trainer/model.py
import argparse
import hypertune
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.utils import shuffle
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import normalize
def get_args():
"""Argument parser.
Returns:
Dictionary of arguments.
"""
parser = argparse.ArgumentParser(description='PyTorch MNIST')
parser.add_argument('--job-dir', # handled automatically by AI Platform
help='GCS location to write checkpoints and export ' \
'models')
parser.add_argument('--lr', # Specified in the config file
type=float,
default=0.01,
help='learning rate (default: 0.01)')
parser.add_argument('--momentum', # Specified in the config file
type=float,
default=0.5,
help='SGD momentum (default: 0.5)')
parser.add_argument('--hidden-layer-size', # Specified in the config file
type=int,
default=8,
help='hidden layer size')
args = parser.parse_args()
return args
def train_model(args):
# Get the data
natality = pd.read_csv('https://storage.googleapis.com/ml-design-patterns/natality.csv')
natality = natality.dropna()
natality = shuffle(natality, random_state = 2)
natality.head()
natality_labels = natality['weight_pounds']
natality = natality.drop(columns=['weight_pounds'])
train_size = int(len(natality) * 0.8)
traindata_natality = natality[:train_size]
trainlabels_natality = natality_labels[:train_size]
testdata_natality = natality[train_size:]
testlabels_natality = natality_labels[train_size:]
# Normalize and convert to PT tensors
normalized_train = normalize(np.array(traindata_natality.values), axis=0)
normalized_test = normalize(np.array(testdata_natality.values), axis=0)
train_x = torch.Tensor(normalized_train)
train_y = torch.Tensor(np.array(trainlabels_natality))
test_x = torch.Tensor(normalized_test)
test_y = torch.Tensor(np.array(testlabels_natality))
# Define our data loaders
train_dataset = torch.utils.data.TensorDataset(train_x, train_y)
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=128, shuffle=True)
test_dataset = torch.utils.data.TensorDataset(test_x, test_y)
test_dataloader = torch.utils.data.DataLoader(test_dataset, batch_size=128, shuffle=False)
# Define the model, while tuning the size of our hidden layer
model = nn.Sequential(nn.Linear(len(train_x[0]), args.hidden_layer_size),
nn.ReLU(),
nn.Linear(args.hidden_layer_size, 1))
criterion = nn.MSELoss()
# Tune hyperparameters in our optimizer
optimizer = optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum)
epochs = 20
for e in range(epochs):
for batch_id, (data, label) in enumerate(train_dataloader):
optimizer.zero_grad()
y_pred = model(data)
label = label.view(-1,1)
loss = criterion(y_pred, label)
loss.backward()
optimizer.step()
val_mse = 0
num_batches = 0
# Evaluate accuracy on our test set
with torch.no_grad():
for i, (data, label) in enumerate(test_dataloader):
num_batches += 1
y_pred = model(data)
mse = criterion(y_pred, label.view(-1,1))
val_mse += mse.item()
avg_val_mse = (val_mse / num_batches)
# Report the metric we're optimizing for to AI Platform's HyperTune service
# In this example, we're mimizing error on our test set
hpt = hypertune.HyperTune()
hpt.report_hyperparameter_tuning_metric(
hyperparameter_metric_tag='val_mse',
metric_value=avg_val_mse,
global_step=epochs
)
def main():
args = get_args()
print('in main', args)
train_model(args)
if __name__ == '__main__':
main()
Il job di addestramento è composto da due funzioni in cui si svolge la maggior parte del lavoro.
get_args(): analizza gli argomenti della riga di comando che trasmetteremo quando creiamo il job di addestramento, insieme agli iperparametri che vogliamo che AI Platform ottimizzi. In questo esempio, l'elenco degli argomenti include solo gli iperparametri che ottimizzeremo: il tasso di apprendimento, il momentum e il numero di neuroni del nostro modello nello strato nascosto.train_model(): qui scarichiamo i dati in un DataFrame Pandas, li normalizziamo, li convertiamo in tensori PyTorch e poi definiamo il modello. Per creare il nostro modello, utilizziamo l'API PyTorchnn.Sequential, che ci consente di definire il modello come uno stack di livelli:
model = nn.Sequential(nn.Linear(len(train_x[0]), args.hidden_layer_size),
nn.ReLU(),
nn.Linear(args.hidden_layer_size, 1))
Tieni presente che, anziché codificare in modo rigido le dimensioni del livello nascosto del modello, lo rendiamo un iperparametro che AI Platform ottimizzerà per noi. Scopri di più nella sezione successiva.
Passaggio 2: utilizza il servizio di ottimizzazione degli iperparametri di AI Platform
Anziché provare manualmente diversi valori di iperparametri e riaddestrare il modello ogni volta, utilizzeremo il servizio di ottimizzazione degli iperparametri di Cloud AI Platform. Se configuriamo il job di addestramento con argomenti di iperparametri, AI Platform utilizzerà l'ottimizzazione bayesiana per trovare i valori ideali per gli iperparametri specificati.
Nell'ottimizzazione degli iperparametri, una singola prova consiste in un'esecuzione di addestramento del modello con una specifica combinazione di valori degli iperparametri. A seconda del numero di prove eseguite, AI Platform utilizzerà i risultati delle prove completate per ottimizzare gli iperparametri selezionati per le prove future. Per configurare l'ottimizzazione degli iperparametri, dobbiamo passare un file di configurazione quando avviamo il job di addestramento con alcuni dati su ciascuno degli iperparametri che stiamo ottimizzando.
Dopodiché, crea il file di configurazione localmente:
%%writefile config.yaml
trainingInput:
hyperparameters:
goal: MINIMIZE
maxTrials: 10
maxParallelTrials: 5
hyperparameterMetricTag: val_mse
enableTrialEarlyStopping: TRUE
params:
- parameterName: lr
type: DOUBLE
minValue: 0.0001
maxValue: 0.1
scaleType: UNIT_LINEAR_SCALE
- parameterName: momentum
type: DOUBLE
minValue: 0.0
maxValue: 1.0
scaleType: UNIT_LINEAR_SCALE
- parameterName: hidden-layer-size
type: INTEGER
minValue: 8
maxValue: 32
scaleType: UNIT_LINEAR_SCALE
Per ogni iperparametro, specifichiamo il tipo, l'intervallo di valori che vogliamo cercare e la scala su cui aumentare il valore nelle diverse prove.
All'inizio del job specifichiamo anche la metrica per cui stiamo eseguendo l'ottimizzazione. Tieni presente che alla fine della funzione train_model() riportata sopra, questa metrica viene segnalata ad AI Platform ogni volta che viene completata una prova. In questo caso, stiamo minimizzando lo scarto quadratico medio del nostro modello, quindi vogliamo utilizzare gli iperparametri che comportano lo scarto quadratico medio più basso per il nostro modello. Il nome di questa metrica (val_mse) corrisponde al nome che utilizziamo per generare report quando chiamiamo report_hyperparameter_tuning_metric() al termine di una prova.
6. Esegui un job di addestramento su AI Platform
In questa sezione avvieremo il job di addestramento del modello con l'ottimizzazione degli iperparametri su AI Platform.
Passaggio 1: definisci alcune variabili di ambiente
Definiamo innanzitutto alcune variabili di ambiente che utilizzeremo per avviare il job di addestramento. Se vuoi eseguire il job in un'altra regione, aggiorna la variabile REGION di seguito:
MAIN_TRAINER_MODULE = "trainer.model"
TRAIN_DIR = os.getcwd() + '/trainer'
JOB_DIR = BUCKET_URL + '/output'
REGION = "us-central1"
Ogni job di addestramento su AI Platform deve avere un nome univoco. Esegui il comando seguente per definire una variabile per il nome del job utilizzando un timestamp:
timestamp = str(datetime.datetime.now().time())
JOB_NAME = 'caip_training_' + str(int(time.time()))
Passaggio 2: avvia il job di addestramento
Creeremo il job di addestramento utilizzando gcloud, Google Cloud CLI. Possiamo eseguire questo comando direttamente nel notebook, facendo riferimento alle variabili definite sopra:
!gcloud ai-platform jobs submit training $JOB_NAME \
--scale-tier basic \
--package-path $TRAIN_DIR \
--module-name $MAIN_TRAINER_MODULE \
--job-dir $JOB_DIR \
--region $REGION \
--runtime-version 2.1 \
--python-version 3.7 \
--config config.yaml
Se il job è stato creato correttamente, vai alla sezione Job della console AI Platform per monitorare i log.
Passaggio 3: monitora il job
Una volta nella sezione Job della console, fai clic sul job appena avviato per visualizzare i dettagli:

Quando inizia il primo round di prove, puoi visualizzare i valori degli iperparametri selezionati per ogni prova:

Man mano che le prove vengono completate, il valore risultante della metrica di ottimizzazione (in questo caso val_mse) verrà registrato qui. L'esecuzione del job dovrebbe richiedere 15-20 minuti e, al termine, la dashboard avrà un aspetto simile al seguente (i valori esatti variano):

Per eseguire il debug di potenziali problemi e monitorare il job in modo più dettagliato, fai clic su Visualizza log nella pagina dei dettagli dei job:

Ogni istruzione print() nel codice di addestramento del modello verrà visualizzata qui. Se riscontri problemi, prova ad aggiungere altre istruzioni di stampa e ad avviare un nuovo job di addestramento.
Una volta completato il job di addestramento, trova gli iperparametri che hanno prodotto il valore val_mse più basso. Puoi utilizzarli per addestrare ed esportare una versione finale del modello oppure come guida per avviare un altro job di addestramento con ulteriori prove di ottimizzazione degli iperparametri.
7. Esegui la pulizia
Se vuoi continuare a utilizzare questo notebook, ti consigliamo di disattivarlo quando non lo usi. Dall'interfaccia utente di Notebooks nella console Cloud, seleziona il notebook, quindi seleziona Interrompi:

Se vuoi eliminare tutte le risorse che hai creato in questo lab, elimina semplicemente l'istanza del notebook anziché arrestarla.
Utilizzando il menu di navigazione della console Cloud, vai a Storage ed elimina entrambi i bucket creati per archiviare gli asset del modello.