Vertex AI Workbench: treine um modelo do TensorFlow com dados do BigQuery

1. Visão geral

Neste laboratório, você vai aprender a usar o Vertex AI Workbench para explorar dados e treinar modelos de ML.

Conteúdo do laboratório

Você vai aprender a:

  • Criar e configurar uma instância do Vertex AI Workbench
  • Usar o conector do BigQuery do Vertex AI Workbench
  • Treinar um modelo em um kernel do Vertex AI Workbench

O custo total da execução deste laboratório no Google Cloud é de aproximadamente US$ 1.

2. Introdução à Vertex AI

Este laboratório usa a mais nova oferta de produtos de IA disponível no Google Cloud. A Vertex AI integra as ofertas de ML do Google Cloud em uma experiência de desenvolvimento intuitiva. Anteriormente, modelos treinados com o AutoML e modelos personalizados eram acessíveis por serviços separados. A nova oferta combina ambos em uma única API, com outros novos produtos. Você também pode migrar projetos para a Vertex AI.

A Vertex AI inclui vários produtos diferentes para dar suporte a fluxos de trabalho integrais de ML. O foco deste laboratório é a Vertex AI Workbench.

Com o Vertex AI Workbench, os usuários criam de modo rápido fluxos de trabalho completos com notebooks, por meio da integração entre serviços de dados (como Dataproc, Dataflow, BigQuery e Dataplex) e a Vertex AI. Com ele, cientistas de dados podem se conectar a serviços de dados do GCP, analisar conjuntos de dados, testar diferentes técnicas de modelagem, implantar modelos treinados na produção e gerenciar MLOps durante o ciclo de vida do modelo.

3. Visão geral do caso de uso

Neste laboratório, você vai analisar o conjunto de dados London Bicycles Hire. Esses dados contêm informações sobre viagens de bicicleta do programa público de compartilhamento de bicicletas de Londres desde 2011. Comece a explorar esse conjunto de dados no BigQuery usando o conector do BigQuery do Vertex AI Workbench. Em seguida, você carregará os dados em um notebook do Jupyter usando pandas e treinará um modelo do TensorFlow para prever a duração de um passeio de bicicleta com base no momento da viagem e na distância que a pessoa percorreu de bicicleta.

Este laboratório usa as camadas de pré-processamento do Keras para transformar e preparar os dados de entrada para o treinamento do modelo. Essa API permite criar o pré-processamento diretamente no grafo do modelo do TensorFlow, reduzindo o risco de distorção de treinamento/disponibilização, garantindo que os dados de treinamento e de disponibilização passem por transformações idênticas. A partir do TensorFlow 2.6, essa API é estável. Se você estiver usando uma versão mais antiga do TensorFlow, será necessário importar o símbolo experimental.

4. Configurar o ambiente

Para executar este codelab, você vai precisar de um projeto do Google Cloud Platform com o faturamento ativado. Para criar um projeto, siga estas instruções.

Etapa 1: ativar a API Compute Engine

Acesse o Compute Engine e selecione Ativar, caso essa opção ainda não esteja ativada.

Etapa 2: ativar a API Vertex AI

Navegue até a seção "Vertex AI" do Console do Cloud e clique em Ativar API Vertex AI.

Painel da Vertex AI

Etapa 3: criar uma instância do Vertex AI Workbench

Na seção Vertex AI do Console do Cloud, clique em "Workbench":

Menu da Vertex AI

Ative a API Notebooks, se ela ainda não tiver sido ativada.

Notebook_api

Após a ativação, clique em NOTEBOOK GERENCIADO:

Notebooks_UI

Em seguida, selecione NOVO NOTEBOOK.

new_notebook

Dê um nome ao notebook. Em Permissão selecione Conta de serviço.

service_account

Selecione Configurações avançadas.

Em Segurança, selecione "Ativar terminal", se essa opção ainda não estiver ativada.

enable_terminal

Você pode manter as outras configurações avançadas como estão.

Em seguida, clique em Criar.

Quando a instância tiver sido criada, selecione ABRIR O JUPYTERLAB.

enable_terminal

5. Analisar o conjunto de dados no BigQuery

Na instância do Vertex AI Workbench, navegue até o lado esquerdo e clique no conector BigQuery in Notebooks.

Conector do BQ

Com o conector do BigQuery, você pode analisar e consultar conjuntos de dados do BigQuery com facilidade. Além dos conjuntos de dados no seu projeto, você pode conferir os de outros projetos clicando no botão Adicionar projeto.

fixar

Neste laboratório, você vai usar dados dos conjuntos de dados públicos do BigQuery. Role a tela para baixo até encontrar o conjunto de dados london_bicycles. Esse conjunto de dados tem duas tabelas, cycle_hire e cycle_stations. Vamos conhecer cada um deles.

london_bike_ds

Primeiro, clique duas vezes na tabela cycle_hire. Você vai notar que a tabela é aberta como uma nova guia com o esquema, além de metadados, como o número de linhas e o tamanho.

cycle_hire_ds

Se você clicar na guia Visualização, será possível ver uma amostra dos dados. Vamos executar uma consulta simples para ver quais são as jornadas mais procuradas. Primeiro, clique no botão Consultar tabela.

cycle_hire_preview_ds

Em seguida, cole o seguinte no editor SQL e clique em 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

Nos resultados da consulta, você verá que as viagens de bicicleta de e para a estação Hyde Park Corner foram as mais procuradas.

journey_query_results

Em seguida, clique duas vezes na tabela cycle_stations, que fornece informações sobre cada estação.

Queremos mesclar as tabelas cycle_hire e cycle_stations. A tabela cycle_stations contém a lat/lon de cada estação. Você vai usar essas informações para estimar a distância percorrida em cada viagem de bicicleta calculando a distância entre as estações de início e término.

Para fazer esse cálculo, use as funções geográficas do BigQuery. Especificamente, você converterá cada string de latitude/longitude em ST_GEOGPOINT e usará a função ST_DISTANCE para calcular a distância em linha reta em metros entre os dois pontos. Você usará esse valor como um indicador da distância percorrida em cada viagem de bicicleta.

Copie a consulta a seguir no editor SQL e clique em "Enviar consulta". Há três tabelas na condição JOIN porque precisamos mesclar a tabela "stations" duas vezes para receber a latitude/longitude da estação inicial e da estação final do 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. treinar um modelo de ML em um kernel do TensorFlow

O Vertex AI Workbench tem uma camada de compatibilidade de computação que permite iniciar kernels para TensorFlow, PySpark, R etc., tudo em uma única instância de notebook. Neste laboratório, você vai criar um notebook usando o kernel do TensorFlow.

Criar DataFrame

Após a execução da consulta, clique em Copiar código para o DataFrame. Isso permite colar código Python em um notebook que se conecta ao cliente do BigQuery e extrai esses dados como um DataFrame pandas.

copy_for_df

Em seguida, volte para a tela de início e crie um notebook do TensorFlow 2.

tf_kernel

Na primeira célula do notebook, cole o código copiado do editor de consultas. A aparência será semelhante a esta:

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

Para este laboratório, limitamos o conjunto de dados a 700000 para manter o tempo de treinamento mais curto. Mas fique à vontade para modificar a consulta e testar o conjunto de dados inteiro.

Em seguida, importe as bibliotecas necessárias.

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

Execute o código abaixo para criar um dataframe reduzido que contém apenas as colunas necessárias para a parte de ML deste exercício.

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

A coluna "start_date" é um datetime do Python. Em vez de usar esse datetime diretamente no modelo, crie dois novos recursos que indiquem o dia da semana e a hora do dia em que a viagem de bicicleta ocorreu.

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 fim, converta a coluna de duração de segundos para minutos para facilitar o entendimento

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

Examine as primeiras linhas do DataFrame formatado. Para cada viagem de bicicleta, agora você tem dados do dia da semana e da hora do dia em que a viagem ocorreu, bem como a distância percorrida. Com essas informações, você vai tentar prever quanto tempo a viagem levou.

data.head()

data_head

Antes de criar e treinar o modelo, você precisa dividir os dados em conjuntos de treinamento e validação.

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

Criar um modelo do TensorFlow

Você vai criar um modelo do TensorFlow usando a API funcional do Keras. Para pré-processar os dados de entrada, você vai usar a API de camadas de pré-processamento do Keras.

A função de utilitário a seguir vai criar um tf.data.Dataset no DataFrame do 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

Use a função acima para criar duas tf.data.Datasets, uma para treinamento e outra para validação. Talvez você veja alguns avisos, mas eles podem ser ignorados com segurança.

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

Você vai usar as seguintes camadas de pré-processamento no modelo:

  • Camada de normalização: realiza uma normalização por atributo de entrada.
  • Camada IntegerLookup: transforma valores categóricos de números inteiros em índices de números inteiros.
  • Camada CategoryEncoding: transforma atributos categóricos de números inteiros em representações densas one-hot, multi-hot ou TF-IDF.

Essas camadas não podem ser treinadas. Em vez disso, defina o estado da camada de pré-processamento expondo-a aos dados de treinamento com o método adapt().

A função a seguir vai criar uma camada de normalização que pode ser usada no elemento de distância. Você vai definir o estado antes de ajustar o modelo usando o método adapt() nos dados de treinamento. Isso calculará a média e a variância a serem usadas para normalização. Mais tarde, quando você transmitir o conjunto de dados de validação para o modelo, essa mesma média e variância calculada nos dados de treinamento serão usadas para dimensionar os dados de validação.

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

Da mesma forma, a função a seguir cria uma codificação de categoria que você vai usar nos recursos de hora e dia da 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))

Em seguida, crie a parte de pré-processamento do modelo. Primeiro, crie uma camada tf.keras.Input para cada um dos recursos.

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

Em seguida, crie as camadas de normalização e codificação de categoria, armazenando-as em uma 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)

Depois de definir as camadas de pré-processamento, você pode definir o restante do modelo. Você vai concatenar todos os recursos de entrada e transmiti-los a uma camada densa. A camada de saída é uma única unidade, já que este é um problema de regressão.

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 fim, compile o modelo.

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

Agora que você definiu o modelo, é possível visualizar a arquitetura

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

keras_model

Esse modelo é bastante complicado para esse conjunto de dados simples. Ele é destinado a fins de demonstração.

Vamos treinar por uma época para confirmar que o código está funcionando.

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

Treinar o modelo com uma GPU

Em seguida, você vai treinar o modelo por mais tempo e usar o comutador de hardware para acelerar o treinamento. O Vertex AI Workbench permite mudar o hardware sem encerrar a instância. Ao adicionar a GPU apenas quando você precisar, é possível manter os custos mais baixos.

Para mudar o perfil de hardware, clique no tipo de máquina no canto superior direito e selecione Modificar hardware.

modify_hardware

Selecione "Anexar GPUs" e escolha uma GPU NVIDIA T4 Tensor Core.

add_gpu

A configuração do hardware leva cerca de cinco minutos. Quando o processo for concluído, vamos treinar o modelo por mais um pouco. Você notará que cada época leva menos tempo agora.

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

Parabéns! 🎉

Você aprendeu a usar o Vertex AI Workbench para:

  • Analisar dados no BigQuery
  • Usar o cliente do BigQuery para carregar dados no Python
  • Treinar um modelo do TensorFlow com camadas de pré-processamento do Keras e uma GPU

Para saber mais sobre partes diferentes da Vertex AI, acesse a documentação.

7. Limpeza

Como configuramos o notebook para expirar após 60 minutos de inatividade, não precisamos nos preocupar em desligar a instância. Para encerrar a instância manualmente, clique no botão "Parar" na seção "Vertex AI Workbench" do console. Se quiser excluir o notebook completamente, clique no botão "Excluir".

excluir