Vertex AI Workbench: Entrena un modelo de TensorFlow con datos de BigQuery

1. Descripción general

En este lab, aprenderás a usar Vertex AI Workbench para explorar datos y entrenar modelos de AA.

Qué aprenderá

Aprenderás a hacer lo siguiente:

  • Crea y configura una instancia de Vertex AI Workbench
  • Usar el conector de BigQuery de Vertex AI Workbench
  • Entrena un modelo en un kernel de Vertex AI Workbench

El costo total de la ejecución de este lab en Google Cloud es de aproximadamente $1.

2. Introducción a Vertex AI

En este lab, se utiliza la oferta de productos de IA más reciente de Google Cloud. Vertex AI integra las ofertas de AA de Google Cloud en una experiencia de desarrollo fluida. Anteriormente, se podía acceder a los modelos personalizados y a los entrenados con AutoML mediante servicios independientes. La nueva oferta combina ambos en una sola API, junto con otros productos nuevos. También puedes migrar proyectos existentes a Vertex AI.

Vertex AI incluye muchos productos distintos para respaldar flujos de trabajo de AA de extremo a extremo. Este lab se enfocará en Vertex AI Workbench.

Vertex AI Workbench ayuda a los usuarios a compilar con rapidez flujos de trabajo basados en notebooks de extremo a extremo a través de la integración profunda a servicios de datos (como Dataproc, Dataflow, BigQuery y Dataplex) y Vertex AI. Permite a los científicos de datos conectarse a servicios de datos de GCP, analizar conjuntos de datos, experimentar con diferentes técnicas de modelado, implementar modelos entrenados en producción y administrar MLOps durante el ciclo de vida del modelo.

3. Descripción general del caso de uso

En este lab, explorarás el conjunto de datos London Bicycles Hire. Estos datos contienen información sobre viajes en bicicleta del programa público de bicicletas compartidas de Londres desde 2011. Comenzarás explorando este conjunto de datos en BigQuery a través del conector de BigQuery de Vertex AI Workbench. Luego, cargarás los datos en un notebook de Jupyter con Pandas y entrenarás un modelo de TensorFlow para predecir la duración de un viaje en bicicleta según el momento en el que se produjo el viaje y la distancia que recorrió la persona en bicicleta.

En este lab, se usan las capas de procesamiento previo de Keras para transformar y preparar los datos de entrada para el entrenamiento de modelos. Esta API te permite compilar el procesamiento previo directamente en el grafo del modelo de TensorFlow, lo que reduce el riesgo de desviación entre el entrenamiento y la entrega, ya que garantiza que los datos de entrenamiento y de entrega experimenten transformaciones idénticas. Ten en cuenta que, a partir de TensorFlow 2.6, esta API es estable. Si estás usando una versión anterior de TensorFlow, deberás importar el símbolo experimental.

4. Configura el entorno

Para ejecutar este codelab, necesitarás un proyecto de Google Cloud Platform que tenga habilitada la facturación. Para crear un proyecto, sigue estas instrucciones.

Paso 1: Habilita la API de Compute Engine

Ve a Compute Engine y selecciona Habilitar (si aún no está habilitada).

Paso 2: Habilita la API de Vertex AI

Navegue hasta la sección de Vertex AI en la consola de Cloud y haga clic en Habilitar API de Vertex AI.

Panel de Vertex AI

Paso 3: Crea una instancia de Vertex AI Workbench

En la sección Vertex AI de Cloud Console, haz clic en Workbench:

Menú Vertex AI

Habilita la API de Notebooks si aún no está habilitada.

Notebook_api

Una vez habilitada, haz clic en NOTEBOOKS ADMINISTRADOS (MANAGED NOTEBOOKS):

Notebooks_UI

Luego, selecciona NUEVO NOTEBOOK (NEW NOTEBOOK).

new_notebook

Asígnale un nombre al notebook y en Permiso (Permission), selecciona Cuenta de servicio (Service account).

service_account

Selecciona Configuración avanzada.

En Seguridad (Security), selecciona la opción “Habilitar terminal” (Enable terminal) si aún no está habilitada.

enable_terminal

Puedes dejar el resto de la configuración avanzada tal como está.

Luego, haz clic en Crear.

Una vez que se cree la instancia, selecciona ABRIR JUPYTERLAB (OPEN JUPYTERLAB).

enable_terminal

5. Explora un conjunto de datos en BigQuery

En la instancia de Vertex AI Workbench, navega al lado izquierdo y haz clic en el conector de BigQuery en Notebooks.

Conector de BigQuery

El conector de BigQuery te permite explorar y consultar fácilmente los conjuntos de datos de BigQuery. Además de cualquier conjunto de datos de tu proyecto, puedes hacer clic en el botón Add Project para explorar los conjuntos de datos de otros proyectos.

fijar

En este lab, usarás datos de los conjuntos de datos públicos de BigQuery. Desplázate hacia abajo hasta que encuentres el conjunto de datos london_bicycles. Verás que este conjunto de datos tiene dos tablas, cycle_hire y cycle_stations. Exploremos cada una de ellas.

london_bike_ds

Primero, haz doble clic en la tabla cycle_hire. Verás que la tabla se abre como una pestaña nueva con el esquema de la tabla y metadatos, como la cantidad de filas y el tamaño.

cycle_hire_ds

Si haces clic en la pestaña Vista previa, podrás ver una muestra de los datos. Vamos a ejecutar una consulta simple para ver cuáles son los recorridos populares. Primero, haz clic en el botón Tabla de consultas.

cycle_hire_preview_ds

Luego, pega lo siguiente en el editor de SQL y haz clic en Enviar consulta.

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

En los resultados de la consulta, verás que los viajes en bicicleta desde y hacia la estación de Hyde Park Corner fueron las más populares.

journey_query_results

A continuación, haz doble clic en la tabla cycle_stations, que proporciona información sobre cada estación.

Queremos unir las tablas cycle_hire y cycle_stations. La tabla cycle_stations contiene las coordenadas de latitud y longitud de cada estación. Usarás esta información para estimar la distancia recorrida en cada viaje en bicicleta calculando la distancia entre las estaciones de partida y llegada.

Para realizar este cálculo, usarás las funciones geográficas de BigQuery. Específicamente, convertirás cada cadena de latitud y longitud en ST_GEOGPOINT y usarás la función ST_DISTANCE para calcular la distancia en línea recta en metros entre los dos puntos. Utilizarás este valor como un proxy de la distancia recorrida en cada viaje en bicicleta.

Copia la siguiente consulta en tu editor de SQL y haz clic en Enviar consulta. Ten en cuenta que hay tres tablas en la condición JOIN porque debemos unir la tabla de estaciones dos veces para obtener la latitud y longitud de la estación de partida y de finalización 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. Entrena un modelo de AA en un kernel de TensorFlow

Vertex AI Workbench tiene una capa de compatibilidad de procesamiento que te permite iniciar kernels para TensorFlow, PySpark, R, etc., desde una sola instancia de notebook. En este lab, crearás un notebook con el kernel de TensorFlow.

Crear DataFrame

Una vez ejecutada la consulta, haz clic en Copiar código para DataFrame. Esto te permitirá pegar el código de Python en un notebook que se conecta con el cliente de BigQuery y extrae estos datos como un DataFrame de Pandas.

copy_for_df

Luego, vuelve al Selector y crea un notebook de TensorFlow 2.

tf_kernel

En la primera celda del notebook, pega el código que copiaste del Editor de consultas. Se verá de la siguiente manera:

# 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()

A los fines de este lab, limitamos el conjunto de datos a 700,000 para que el tiempo de entrenamiento sea más breve. Pero siéntete libre de modificar la consulta y experimentar con todo el conjunto de datos.

A continuación, importa las bibliotecas necesarias.

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

Ejecuta el siguiente código para crear un DataFrame reducido que solo contenga las columnas necesarias para la parte de AA de este ejercicio.

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 columna start_date es una datetime de Python. En lugar de usar este datetime directamente en el modelo, crearás dos atributos nuevos que indicarán el día de la semana y la hora del día en que ocurrió el viaje en bicicleta.

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'])

Por último, convierte la columna de duración de segundos a minutos para que sea más fácil de entender

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

Examina las primeras filas del DataFrame con formato. Para cada viaje en bicicleta, ahora tienes datos sobre el día de la semana y la hora del día en que ocurrió el viaje, así como la distancia recorrida. A partir de esta información, intentarás predecir cuánto duró el viaje.

data.head()

data_head

Antes de crear y entrenar el modelo, debes dividir los datos en conjuntos de entrenamiento y validación.

# 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:]

Crear un modelo de TensorFlow

Crearás un modelo de TensorFlow con la API funcional de Keras. Para procesar previamente los datos de entrada, usarás la API de capas de procesamiento previo de Keras.

La siguiente función de utilidad creará un tf.data.Dataset a partir del DataFrame de 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

Usa la función anterior para crear dos tf.data.Dataset, uno para el entrenamiento y otro para la validación. Es posible que veas algunas advertencias, pero puedes ignorarlas de manera segura.

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

Usarás las siguientes capas de procesamiento previo en el modelo:

  • Capa de normalización: realiza la normalización con respecto a los atributos de los atributos de entrada.
  • Capa de IntegerLookup: convierte los valores categóricos de números enteros en índices de números enteros.
  • Capa de CategoryEncoding: Convierte los atributos categóricos de números enteros en representaciones one-hot, multi-hot o densas de TF-IDF.

Ten en cuenta que estas capas no se pueden entrenar. En su lugar, debes establecer el estado de la capa de procesamiento previo exponiéndola a los datos de entrenamiento a través del método adapt().

La siguiente función creará una capa con normalización que puedes usar en el atributo de distancia. Establecerás el estado anterior a ajustar el modelo con el método adapt() en los datos de entrenamiento. Esto calculará la media y la varianza que se usarán para la normalización. Más adelante, cuando pases el conjunto de datos de validación al modelo, se usará esa misma media y varianza calculadas en los datos de entrenamiento para escalar los datos de validación.

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

De manera similar, la siguiente función crea una codificación de categoría que utilizarás en los atributos de horario y día de semana.

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

A continuación, crea la porción de procesamiento previo del modelo. Primero, crea una capa de tf.keras.Input para cada uno de los componentes.

# 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')

A continuación, crea las capas de normalización y codificación de categoría, almacenándolas en una lista.

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)

Después de definir las capas de procesamiento previo, puedes definir el resto del modelo. Concatenarás todas las funciones de entrada y las pasarás a una capa densa. La capa de salida es una sola unidad, ya que este es un problema de regresión.

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)

Por último, compila el modelo.

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

Ahora que definiste el modelo, puedes visualizar la arquitectura

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

keras_model

Ten en cuenta que este modelo es bastante complicado para este conjunto de datos simple. Está destinada a fines demostrativos.

Entrenémoslo durante 1 ciclo de entrenamiento solo para confirmar que se ejecute el código.

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

Entrena el modelo con una GPU

A continuación, entrenarás el modelo por más tiempo y usarás el conmutador de hardware para acelerar el entrenamiento. Vertex AI Workbench te permite cambiar el hardware sin cerrar tu instancia. Si agregas la GPU solo cuando la necesitas, puedes reducir los costos.

Para cambiar el perfil de hardware, haz clic en el tipo de máquina en la esquina superior derecha y selecciona Modify Hardware.

modify_hardware

Selecciona Conectar GPU y selecciona una GPU NVIDIA T4 Tensor Core.

add_gpu

El hardware tardará unos cinco minutos en configurarse. Una vez que se completa el proceso, hay que entrenar el modelo por un poco más de tiempo. Notarás que cada época lleva menos tiempo ahora.

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

🎉 ¡Felicitaciones! 🎉

Aprendiste a usar Vertex AI Workbench para hacer lo siguiente:

  • Explora datos en BigQuery
  • Usa el cliente de BigQuery para cargar datos en Python
  • Entrena un modelo de TensorFlow con capas de procesamiento previo de Keras y una GPU

Si quieres obtener más información sobre los diferentes componentes de Vertex AI, consulta la documentación.

7. Realiza una limpieza

Debido a que configuramos el notebook para que se agote el tiempo de espera después de 60 minutos de inactividad, no tenemos que preocuparnos por cerrar la instancia. Si quieres cerrar la instancia de forma manual, haz clic en el botón Detener (Stop) en la sección Vertex AI Workbench de la consola. Si quieres borrar el notebook por completo, haz clic en el botón Borrar (Delete).

delete