Vertex AI Workbench: addestra un modello TensorFlow con i dati di BigQuery

1. Panoramica

In questo lab imparerai a utilizzare Vertex AI Workbench per l'esplorazione dei dati e l'addestramento di modelli ML.

Cosa imparerai

Al termine del corso sarai in grado di:

  • Crea e configura un'istanza di Vertex AI Workbench
  • Utilizzare il connettore BigQuery di Vertex AI Workbench
  • Addestrare un modello su un kernel Vertex AI Workbench

Il costo totale per eseguire questo lab su Google Cloud è di circa 1$.

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.

Vertex AI include molti prodotti diversi per supportare i flussi di lavoro ML end-to-end. Questo lab si concentrerà su Vertex AI Workbench.

Vertex AI Workbench aiuta gli utenti a creare rapidamente flussi di lavoro end-to-end basati su notebook tramite un'integrazione profonda con i servizi di dati (come Dataproc, Dataflow, BigQuery e Dataplex) e Vertex AI. Consente ai data scientist di connettersi ai servizi dati di Google Cloud, analizzare i set di dati, sperimentare diverse tecniche di modellazione, eseguire il deployment dei modelli addestrati in produzione e gestire MLOps durante il ciclo di vita del modello.

3. Panoramica del caso d'uso

In questo lab esplorerai il set di dati London Bicycles Hire. Questi dati contengono informazioni sui viaggi in bicicletta del programma pubblico di bike sharing di Londra dal 2011. Inizierai esplorando questo set di dati in BigQuery tramite il connettore BigQuery di Vertex AI Workbench. Quindi caricherai i dati in un blocco note Jupyter utilizzando Pandas e addestrerai un modello TensorFlow per prevedere la durata di una corsa in ciclo in base a quando si è verificato il viaggio e a quanto tempo ha percorso la persona.

Questo lab utilizza gli strati di pre-elaborazione di Keras per trasformare e preparare i dati di input per l'addestramento del modello. Questa API ti consente di creare la pre-elaborazione direttamente nel grafico del modello TensorFlow, riducendo il rischio di asimmetria di addestramento/pubblicazione garantendo che i dati di addestramento e di pubblicazione subiscano trasformazioni identiche. Tieni presente che, a partire da TensorFlow 2.6, questa API è stabile. Se utilizzi una versione precedente di TensorFlow, dovrai importare il simbolo sperimentale.

4. Configura l'ambiente

Per eseguire questo codelab, devi avere un progetto Google Cloud 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 Attiva se non è già abilitato.

Passaggio 2: attiva l'API Vertex AI

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

Dashboard di Vertex AI

Passaggio 3: crea un'istanza di Vertex AI Workbench

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

Menu Vertex AI

Se non l'hai ancora fatto, abilita l'API Notebooks.

Notebook_api

Dopo averla attivata, fai clic su NOTEBOOK GESTITI:

Notebooks_UI

Quindi seleziona NUOVO NOTEBOOK.

new_notebook

Assegna un nome al notebook e in Autorizzazione seleziona Account di servizio.

service_account

Seleziona Impostazioni avanzate.

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

enable_terminal

Puoi lasciare invariate tutte le altre impostazioni avanzate.

Poi, fai clic su Crea.

Una volta creata l'istanza, seleziona APRI JUPYTERLAB.

enable_terminal

5. Esplorare il set di dati in BigQuery

Nell'istanza di Vertex AI Workbench, vai a sinistra e fai clic sul connettore BigQuery in Notebooks.

Connettore BQ

Il connettore BigQuery ti consente di esplorare ed eseguire query sui set di dati BigQuery con facilità. Oltre ai set di dati nel tuo progetto, puoi esplorare quelli in altri progetti facendo clic sul pulsante Aggiungi progetto.

in primo piano

Per questo lab utilizzerai i dati dei set di dati pubblici di BigQuery. Scorri verso il basso fino a trovare il set di dati london_bicycles. Vedrai che questo set di dati contiene due tabelle, cycle_hire e cycle_stations. Vediamoli uno per uno.

london_bike_ds

Innanzitutto, fai doppio clic sulla tabella cycle_hire. La tabella si apre in una nuova scheda con lo schema della tabella e metadati come il numero di righe e le dimensioni.

cycle_hire_ds

Se fai clic sulla scheda Anteprima, puoi visualizzare un campione dei dati. Eseguiamo una semplice query per vedere quali sono i percorsi più frequenti. Innanzitutto, fai clic sul pulsante Query table (Esegui query sulla tabella).

cycle_hire_preview_ds

Poi, incolla quanto segue nell'editor SQL e fai clic su Invia query.

SELECT
  start_station_name,
  end_station_name,
  IF(start_station_name = end_station_name,
    TRUE,
    FALSE) same_station,
  AVG(duration) AS avg_duration,
  COUNT(*) AS total_rides
FROM
  `bigquery-public-data.london_bicycles.cycle_hire`
GROUP BY
  start_station_name,
  end_station_name,
  same_station
ORDER BY
  total_rides DESC

Dai risultati della query, vedrai che i viaggi in bicicletta da e verso la stazione Hyde Park Corner sono stati i più apprezzati.

journey_query_results

Quindi, fai doppio clic sulla tabella cycle_stations, che fornisce informazioni su ciascuna stazione.

Vogliamo unire le tabelle cycle_hire e cycle_stations. La tabella cycle_stations contiene lat/lon per ogni stazione. Potrai utilizzare queste informazioni per stimare la distanza percorsa in ogni viaggio in bici calcolando la distanza tra le stazioni di partenza e di arrivo.

Per eseguire questo calcolo, utilizzerai le funzioni geografiche di BigQuery. Nello specifico, convertirai ogni stringa lat/lon in un ST_GEOGPOINT e utilizzerai la funzione ST_DISTANCE per calcolare la distanza in linea retta in metri tra i due punti. Utilizzerai questo valore come sostituto della distanza percorsa in ogni viaggio in bicicletta.

Copia la seguente query nell'editor SQL e fai clic su Invia query. Tieni presente che nella condizione JOIN sono presenti tre tabelle perché dobbiamo unire la tabella stazioni due volte per ottenere lat/lon sia per la stazione di partenza che per quella di arrivo del ciclo.

WITH staging AS (
    SELECT
        STRUCT(
            start_stn.name,
            ST_GEOGPOINT(start_stn.longitude, start_stn.latitude) AS POINT,
            start_stn.docks_count,
            start_stn.install_date
        ) AS starting,
        STRUCT(
            end_stn.name,
            ST_GEOGPOINT(end_stn.longitude, end_stn.latitude) AS point,
            end_stn.docks_count,
            end_stn.install_date
        ) AS ending,
        STRUCT(
            rental_id,
            bike_id,
            duration, --seconds
            ST_DISTANCE(
                ST_GEOGPOINT(start_stn.longitude, start_stn.latitude),
                ST_GEOGPOINT(end_stn.longitude, end_stn.latitude)
            ) AS distance, --meters
            start_date,
            end_date
        ) AS bike
        FROM `bigquery-public-data.london_bicycles.cycle_stations` AS start_stn
        LEFT JOIN `bigquery-public-data.london_bicycles.cycle_hire` as b
        ON start_stn.id = b.start_station_id
        LEFT JOIN `bigquery-public-data.london_bicycles.cycle_stations` AS end_stn
        ON end_stn.id = b.end_station_id
        LIMIT 700000)

SELECT * from STAGING

6. Addestra un modello ML su un kernel TensorFlow

Vertex AI Workbench dispone di un livello di compatibilità di calcolo che ti consente di avviare kernel per TensorFlow, PySpark, R e così via, il tutto da una singola istanza di notebook. In questo lab creerai un notebook utilizzando il kernel TensorFlow.

Crea DataFrame

Dopo l'esecuzione della query, fai clic su Copia codice per DataFrame. In questo modo potrai incollare il codice Python in un blocco note che si connette al client BigQuery ed estrae questi dati come DataFrame pandas.

copy_for_df

Torna al programma di avvio e crea un blocco note TensorFlow 2.

tf_kernel

Nella prima cella del blocco note, incolla il codice copiato dall'Editor di query. Dovrebbe avere il seguente aspetto:

# The following two lines are only necessary to run once.
# Comment out otherwise for speed-up.
from google.cloud.bigquery import Client, QueryJobConfig
client = Client()

query = """WITH staging AS (
    SELECT
        STRUCT(
            start_stn.name,
            ST_GEOGPOINT(start_stn.longitude, start_stn.latitude) AS POINT,
            start_stn.docks_count,
            start_stn.install_date
        ) AS starting,
        STRUCT(
            end_stn.name,
            ST_GEOGPOINT(end_stn.longitude, end_stn.latitude) AS point,
            end_stn.docks_count,
            end_stn.install_date
        ) AS ending,
        STRUCT(
            rental_id,
            bike_id,
            duration, --seconds
            ST_DISTANCE(
                ST_GEOGPOINT(start_stn.longitude, start_stn.latitude),
                ST_GEOGPOINT(end_stn.longitude, end_stn.latitude)
            ) AS distance, --meters
            start_date,
            end_date
        ) AS bike
        FROM `bigquery-public-data.london_bicycles.cycle_stations` AS start_stn
        LEFT JOIN `bigquery-public-data.london_bicycles.cycle_hire` as b 
        ON start_stn.id = b.start_station_id
        LEFT JOIN `bigquery-public-data.london_bicycles.cycle_stations` AS end_stn
        ON end_stn.id = b.end_station_id
        LIMIT 700000)

SELECT * from STAGING"""
job = client.query(query)
df = job.to_dataframe()

Ai fini di questo lab, limitiamo il set di dati a 700.000 per ridurre il tempo di addestramento. Tuttavia, non esitare a modificare la query ed eseguire esperimenti sull'intero set di dati.

Importa poi le librerie necessarie.

from datetime import datetime
import pandas as pd
import tensorflow as tf

Esegui questo codice per creare un dataframe ridotto che contenga solo le colonne necessarie per la parte ML di questo esercizio.

values = df['bike'].values
duration = list(map(lambda a: a['duration'], values))
distance = list(map(lambda a: a['distance'], values))
dates = list(map(lambda a: a['start_date'], values))
data = pd.DataFrame(data={'duration': duration, 'distance': distance, 'start_date':dates})
data = data.dropna()

La colonna start_date è un datetime di Python. Anziché utilizzare direttamente questo datetime nel modello, creerai due nuove funzionalità che indicano il giorno della settimana e l'ora del giorno in cui si è verificato il viaggio in bicicletta.

data['weekday'] = data['start_date'].apply(lambda a: a.weekday())
data['hour'] = data['start_date'].apply(lambda a: a.time().hour)
data = data.drop(columns=['start_date'])

Infine, converti la colonna della durata da secondi a minuti per facilitarne la comprensione.

data['duration'] = data['duration'].apply(lambda x:float(x / 60))

Esamina le prime righe del DataFrame formattato. Per ogni viaggio in bici ora disponi dei dati sul giorno della settimana, sull'ora del giorno in cui si è verificato il viaggio e sulla distanza percorsa. Da queste informazioni, dovrai prevedere la durata del viaggio.

data.head()

data_head

Prima di poter creare e addestrare il modello, devi suddividere i dati in set di addestramento e convalida.

# Use 80/20 train/eval split
train_size = int(len(data) * .8)
print ("Train size: %d" % train_size)
print ("Evaluation size: %d" % (len(data) - train_size))

# Split data into train and test sets
train_data = data[:train_size]
val_data = data[train_size:]

Crea un modello TensorFlow

Creerai un modello TensorFlow utilizzando l'API Keras Functional. Per pre-elaborare i dati di input, utilizzerai l'API degli strati di pre-elaborazione di Keras.

La seguente funzione di utilità creerà un tf.data.Dataset dal DataFrame pandas.

def df_to_dataset(dataframe, label, shuffle=True, batch_size=32):
  dataframe = dataframe.copy()
  labels = dataframe.pop(label)
  ds = tf.data.Dataset.from_tensor_slices((dict(dataframe), labels))
  if shuffle:
    ds = ds.shuffle(buffer_size=len(dataframe))
  ds = ds.batch(batch_size)
  ds = ds.prefetch(batch_size)
  return ds

Utilizza la funzione precedente per creare due tf.data.Dataset, uno per l'addestramento e uno per la convalida. Potresti vedere alcuni avvisi, ma puoi tranquillamente ignorarli.

train_dataset = df_to_dataset(train_data, 'duration')
validation_dataset = df_to_dataset(val_data, 'duration')

Nel modello, utilizzerai i seguenti strati di pre-elaborazione:

  • Livello di normalizzazione: esegue la normalizzazione delle caratteristiche di input in base alle caratteristiche.
  • Strato IntegerLookup: trasforma i valori categorici interi in indici di numeri interi.
  • Livello CategoryEncoding: trasforma le caratteristiche categoriche intere in rappresentazioni dense con codifica one-hot, multi-hot o TF-IDF.

Tieni presente che questi livelli non sono addestrabili. Imposti invece lo stato del livello di preelaborazione esponendolo ai dati di addestramento tramite il metodo adapt().

La seguente funzione crea un livello di normalizzazione che puoi utilizzare per la funzionalità di distanza. Imposterai lo stato prima di adattare il modello utilizzando il metodo adapt() sui dati di addestramento. Verranno calcolate la media e la varianza da utilizzare per la normalizzazione. In seguito, quando passi il set di dati di convalida al modello, queste stesse medie e varianze calcolate sui dati di addestramento verranno utilizzate per scalare i dati di convalida.

def get_normalization_layer(name, dataset):
  # Create a Normalization layer for our feature.
  normalizer = tf.keras.layers.Normalization(axis=None)

  # Prepare a Dataset that only yields our feature.
  feature_ds = dataset.map(lambda x, y: x[name])

  # Learn the statistics of the data.
  normalizer.adapt(feature_ds)

  return normalizer

Analogamente, la seguente funzione crea una codifica delle categorie da utilizzare per le funzionalità relative all'ora e al giorno della settimana.

def get_category_encoding_layer(name, dataset, dtype, max_tokens=None):
  index = tf.keras.layers.IntegerLookup(max_tokens=max_tokens)

  # Prepare a Dataset that only yields our feature
  feature_ds = dataset.map(lambda x, y: x[name])

  # Learn the set of possible values and assign them a fixed integer index.
  index.adapt(feature_ds)

  # Create a Discretization for our integer indices.
  encoder = tf.keras.layers.CategoryEncoding(num_tokens=index.vocabulary_size())

  # Apply one-hot encoding to our indices. The lambda function captures the
  # layer so we can use them, or include them in the functional model later.
  return lambda feature: encoder(index(feature))

Quindi, crea la parte di pre-elaborazione del modello. Innanzitutto, crea un livello tf.keras.Input per ogni elemento.

# Create a Keras input layer for each feature
numeric_col = tf.keras.Input(shape=(1,), name='distance')
hour_col = tf.keras.Input(shape=(1,), name='hour', dtype='int64')
weekday_col = tf.keras.Input(shape=(1,), name='weekday', dtype='int64')

Poi crea i livelli di normalizzazione e codifica delle categorie, archiviandoli in un elenco.

all_inputs = []
encoded_features = []

# Pass 'distance' input to normalization layer
normalization_layer = get_normalization_layer('distance', train_dataset)
encoded_numeric_col = normalization_layer(numeric_col)
all_inputs.append(numeric_col)
encoded_features.append(encoded_numeric_col)

# Pass 'hour' input to category encoding layer
encoding_layer = get_category_encoding_layer('hour', train_dataset, dtype='int64')
encoded_hour_col = encoding_layer(hour_col)
all_inputs.append(hour_col)
encoded_features.append(encoded_hour_col)

# Pass 'weekday' input to category encoding layer
encoding_layer = get_category_encoding_layer('weekday', train_dataset, dtype='int64')
encoded_weekday_col = encoding_layer(weekday_col)
all_inputs.append(weekday_col)
encoded_features.append(encoded_weekday_col)

Dopo aver definito gli strati di preelaborazione, puoi definire il resto del modello. Concatena tutte le funzionalità di input e passale a un livello denso. Il livello di output è una singola unità poiché si tratta di un problema di regressione.

all_features = tf.keras.layers.concatenate(encoded_features)
x = tf.keras.layers.Dense(64, activation="relu")(all_features)
output = tf.keras.layers.Dense(1)(x)
model = tf.keras.Model(all_inputs, output)

Infine, compila il modello.

model.compile(optimizer = tf.keras.optimizers.Adam(0.001),
              loss='mean_squared_logarithmic_error')

Ora che hai definito il modello, puoi visualizzare l'architettura

tf.keras.utils.plot_model(model, show_shapes=True, rankdir="LR")

keras_model

Tieni presente che questo modello è piuttosto complicato per questo semplice set di dati. È destinato a scopi dimostrativi.

Eseguiamo l'addestramento per un'epoca per verificare che il codice venga eseguito.

model.fit(train_dataset, validation_data = validation_dataset, epochs = 1)

Addestra il modello con una GPU

Successivamente, addestrerai il modello per più tempo e utilizzerai il selettore hardware per velocizzare l'addestramento. Vertex AI Workbench ti consente di cambiare l'hardware senza arrestare l'istanza. Aggiungendo la GPU solo quando serve, puoi ridurre i costi.

Per modificare il profilo hardware, fai clic sul tipo di macchina nell'angolo in alto a destra e seleziona Modifica hardware.

modify_hardware

Seleziona Collega GPU e scegli una GPU NVIDIA T4 Tensor Core.

add_gpu

La configurazione dell'hardware richiede circa cinque minuti. Al termine della procedura, addestriamo il modello ancora per un po'. Noterai che ora ogni epoca richiede meno tempo.

model.fit(train_dataset, validation_data = validation_dataset, epochs = 5)

🎉 Complimenti! 🎉

Hai imparato a utilizzare Vertex AI Workbench per:

  • Esplorare i dati in BigQuery
  • Utilizzare il client BigQuery per caricare i dati in Python
  • Addestrare un modello TensorFlow con gli strati di pre-elaborazione di Keras e una GPU

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

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

elimina