Vertex AI Workbench: entraîner un modèle TensorFlow avec des données de BigQuery

1. Présentation

Dans cet atelier, vous allez apprendre à utiliser Vertex AI Workbench pour l'exploration des données et l'entraînement de modèles de ML.

Objectifs

Vous allez apprendre à effectuer les opérations suivantes :

  • Créer et configurer une instance Vertex AI Workbench
  • Utiliser le connecteur BigQuery de Vertex AI Workbench
  • Entraîner un modèle sur un kernel Vertex AI Workbench

Le coût total d'exécution de cet atelier sur Google Cloud est d'environ 1 $.

2. Présentation de Vertex AI

Cet atelier utilise la toute dernière offre de produits d'IA de Google Cloud. Vertex AI simplifie l'expérience de développement en intégrant toutes les offres de ML de Google Cloud. Auparavant, les modèles entraînés avec AutoML et les modèles personnalisés étaient accessibles depuis des services distincts. La nouvelle offre regroupe ces deux types de modèles mais aussi d'autres nouveaux produits en une seule API. Vous pouvez également migrer des projets existants vers Vertex AI.

Vertex AI comprend de nombreux produits différents qui permettent de gérer les workflows de ML de bout en bout. Cet atelier se concentre sur Vertex AI Workbench.

Vertex AI Workbench permet aux utilisateurs de créer rapidement des workflows de bout en bout basés sur des notebooks, grâce à une intégration approfondie avec des services de données (Dataproc, Dataflow, BigQuery, Dataplex, etc.) et Vertex AI. Il permet aux data scientists de se connecter aux services de données GCP, d'analyser des ensembles de données, de tester différentes techniques de modélisation, de déployer des modèles entraînés en production et de gérer le MLOps tout au long du cycle de vie du modèle.

3. Présentation du cas d'utilisation

Dans cet atelier, vous allez explorer l'ensemble de données London Bicycles Hire (Location de vélos à Londres). Ces données contiennent des informations sur les trajets à vélo effectués depuis le programme de vélos en libre-service public de Londres depuis 2011. Vous allez commencer par explorer cet ensemble de données dans BigQuery à l'aide du connecteur BigQuery de Vertex AI Workbench. Vous allez ensuite charger les données dans un notebook Jupyter à l'aide de pandas et entraîner un modèle TensorFlow pour prédire la durée d'un trajet à vélo en fonction de la date et de la distance parcourue.

Cet atelier utilise des couches de prétraitement Keras pour transformer et préparer les données d'entrée à l'entraînement du modèle. Cette API vous permet de créer un prétraitement directement dans le graphe de votre modèle TensorFlow, ce qui réduit le risque de décalage entraînement/diffusion en veillant à ce que les données d'entraînement et les données de diffusion subissent des transformations identiques. Notez qu'à partir de TensorFlow 2.6, cette API est stable. Si vous utilisez une ancienne version de TensorFlow, vous devez importer le symbole expérimental.

4. Configurer votre environnement

Pour suivre cet atelier de programmation, vous aurez besoin d'un projet Google Cloud Platform dans lequel la facturation est activée. Pour créer un projet, suivez ces instructions.

Étape 1 : Activez l'API Compute Engine

Accédez à Compute Engine et cliquez sur Activer si ce n'est pas déjà fait.

Étape 2: Activez l'API Vertex AI

Accédez à la section Vertex AI de Cloud Console, puis cliquez sur Activer l'API Vertex AI.

Tableau de bord Vertex AI

Étape 3: Créez une instance Vertex AI Workbench

Dans la section Vertex AI de Cloud Console, cliquez sur Workbench :

Menu Vertex AI

Activez l'API Notebooks si ce n'est pas déjà fait.

Notebook_api

Une fois l'API activée, cliquez sur NOTEBOOKS GÉRÉS :

Notebooks_UI

Sélectionnez ensuite NOUVEAU NOTEBOOK.

new_notebook

Attribuez un nom à votre notebook, puis sous Autorisation, sélectionnez Compte de service.

service_account

Sélectionnez Paramètres avancés.

Dans la section Sécurité, sélectionnez "Activer le terminal" si ce n'est pas déjà fait.

enable_terminal

Vous pouvez conserver tous les autres paramètres avancés tels quels.

Cliquez ensuite sur Créer.

Une fois l'instance créée, sélectionnez OUVRIR JUPYTERLAB :

enable_terminal

5. Explorer un ensemble de données dans BigQuery

Dans l'instance Vertex AI Workbench, accédez à gauche et cliquez sur le connecteur BigQuery dans Notebooks.

Connecteur BQ

Le connecteur BigQuery vous permet d'explorer et d'interroger facilement des ensembles de données BigQuery. Vous pouvez explorer les ensembles de données d'autres projets, en plus des ensembles de données de votre projet. Pour ce faire, cliquez sur le bouton Ajouter un projet.

épingler

Pour cet atelier, vous allez utiliser les données des ensembles de données publics BigQuery. Faites défiler la page jusqu'à l'ensemble de données london_bicycles. Vous constaterez que cet ensemble de données comporte deux tables, cycle_hire et cycle_stations. Examinons chacun d'entre eux.

london_bike_ds

Commencez par double-cliquer sur la table cycle_hire. La table s'ouvre dans un nouvel onglet contenant son schéma, ainsi que des métadonnées comme le nombre de lignes et la taille.

cycle_hire_ds

Si vous cliquez sur l'onglet Preview (Aperçu), vous pourrez consulter un échantillon des données. Exécutons une requête simple pour identifier les trajets populaires. Commencez par cliquer sur le bouton Query table (Interroger la table).

cycle_hire_preview_ds

Collez ensuite le code suivant dans l'éditeur SQL, puis cliquez sur Envoyer la requête.

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

Les résultats de la requête révèlent que les trajets à vélo à destination et en provenance de la station Hyde Park Corner ont été les plus populaires.

journey_query_results

Ensuite, double-cliquez sur la table cycle_stations, qui fournit des informations sur chaque station.

Nous voulons joindre les tables cycle_hire et cycle_stations. La table cycle_stations contient les coordonnées de latitude/longitude de chaque station. Vous utiliserez ces informations pour estimer la distance parcourue sur chaque trajet à vélo en calculant la distance entre les stations de départ et d'arrivée.

Pour effectuer ce calcul, vous utiliserez les fonctions géographiques de BigQuery. Plus précisément, vous convertirez chaque chaîne de latitude/longitude en ST_GEOGPOINT et utiliserez la fonction ST_DISTANCE pour calculer la distance en ligne droite en mètres entre les deux points. Vous utiliserez cette valeur comme indicateur de la distance parcourue à vélo pour chaque trajet.

Copiez la requête suivante dans votre éditeur SQL, puis cliquez sur "Envoyer la requête". Notez qu'il y a trois tables dans la condition JOIN, car nous devons joindre la table "stations" deux fois pour obtenir la latitude/longitude de la station de départ et de l'arrivée du cycle.

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. Entraîner un modèle de ML sur un kernel TensorFlow

Vertex AI Workbench dispose d'une couche de compatibilité de calcul qui vous permet de lancer des noyaux pour TensorFlow, PySpark, R, etc., le tout à partir d'une seule instance de notebook. Dans cet atelier, vous allez créer un notebook à l'aide du kernel TensorFlow.

Créer un DataFrame

Une fois la requête exécutée, cliquez sur "Copier le code pour DataFrame". Vous pourrez ainsi coller du code Python dans un notebook qui se connecte au client BigQuery et extrait ces données en tant que DataFrame pandas.

copy_for_df

Ensuite, revenez au lanceur et créez un notebook TensorFlow 2.

tf_kernel

Dans la première cellule du notebook, collez le code copié depuis l'éditeur de requêtes. Le résultat doit se présenter comme suit:

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

Pour les besoins de cet atelier, nous limitons l'ensemble de données à 700 000 afin de réduire la durée d'entraînement. Mais n'hésitez pas à modifier la requête et à expérimenter l'ensemble de données complet.

Importez ensuite les bibliothèques nécessaires.

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

Exécutez le code suivant pour créer une trame de données réduite contenant uniquement les colonnes nécessaires à la partie ML de cet exercice.

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 colonne start_date est de type datetime Python. Au lieu d'utiliser directement cette datetime dans le modèle, vous allez créer deux nouvelles caractéristiques qui indiquent le jour de la semaine et l'heure à laquelle le trajet à vélo a eu lieu.

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

Enfin, convertissez la colonne "Durée" de secondes en minutes pour qu'elle soit plus facile à comprendre.

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

Examinez les premières lignes du DataFrame formaté. Pour chaque trajet à vélo, vous disposez désormais de données sur le jour de la semaine et l'heure à laquelle il a eu lieu, ainsi que sur la distance parcourue. À partir de ces informations, vous allez essayer de prédire la durée du trajet.

data.head()

data_head

Avant de pouvoir créer et entraîner le modèle, vous devez diviser les données en ensembles d'entraînement et de validation.

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

Créer un modèle TensorFlow

Vous allez créer un modèle TensorFlow à l'aide de l'API Keras Functional. Pour prétraiter les données d'entrée, vous allez utiliser l'API des couches de prétraitement Keras.

La fonction utilitaire suivante crée un tf.data.Dataset à partir du 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

Utilisez la fonction ci-dessus pour créer deux tf.data.Dataset, l'un pour l'entraînement et l'autre pour la validation. Des avertissements peuvent s'afficher, mais vous pouvez les ignorer.

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

Vous utiliserez les couches de prétraitement suivantes dans le modèle:

  • Couche de normalisation: effectue une normalisation des caractéristiques d'entrée.
  • Couche IntegerLookup: convertit les valeurs catégorielles entières en index d'entiers.
  • Couche "CategoryEncoding": convertit des caractéristiques catégorielles entières en représentations one-hot, multi-hot ou TF-IDF.

Notez que ces couches ne peuvent pas être entraînées. À la place, vous définissez l'état de la couche de prétraitement en l'exposant aux données d'entraînement, via la méthode adapt().

La fonction suivante crée une couche de normalisation que vous pouvez utiliser sur l'élément géographique de distance. Vous définirez l'état avant d'ajuster le modèle à l'aide de la méthode adapt() sur les données d'entraînement. La moyenne et la variance à utiliser pour la normalisation sont calculées. Plus tard, lorsque vous transmettrez l'ensemble de données de validation au modèle, cette même moyenne et cette même variance calculées sur les données d'entraînement seront utilisées pour mettre à l'échelle les données de validation.

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 même, la fonction suivante crée un codage de catégorie que vous utiliserez pour les caractéristiques d'heure et de jour de la semaine.

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

Créez ensuite la partie de prétraitement du modèle. Commencez par créer un calque tf.keras.Input pour chacune des entités.

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

Créez ensuite les couches de normalisation et d'encodage de catégorie, puis stockez-les dans une liste.

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)

Une fois les couches de prétraitement définies, vous pouvez définir le reste du modèle. Vous allez concaténer toutes les caractéristiques d'entrée et les transmettre à une couche dense. La couche de sortie est une unité unique, car il s'agit d'un problème de régression.

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)

Enfin, compilez le modèle.

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

Maintenant que vous avez défini le modèle, vous pouvez visualiser l'architecture

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

keras_model

Notez que ce modèle est assez compliqué pour cet ensemble de données simple. Elle n'est fournie qu'à titre de démonstration.

Entrainons-nous pendant une époque pour vérifier que le code s'exécute.

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

Entraîner un modèle avec un GPU

Ensuite, vous allez entraîner le modèle plus longtemps et utiliser le commutateur matériel pour accélérer l'entraînement. Vertex AI Workbench vous permet de modifier le matériel sans arrêter votre instance. En n'ajoutant le GPU que lorsque vous en avez besoin, vous pouvez réduire vos coûts.

Pour modifier le profil matériel, cliquez sur le type de machine en haut à droite, puis sélectionnez Modifier le matériel.

modify_hardware

Sélectionnez "Associer des GPU", puis un GPU NVIDIA T4 Tensor Core.

add_gpu

La configuration du matériel prend environ cinq minutes. Une fois le processus terminé, entraînons le modèle un peu plus longtemps. Vous remarquerez que chaque époque prend désormais moins de temps.

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

🎉 Félicitations ! 🎉

Vous savez désormais utiliser Vertex AI Workbench pour:

  • Explorer les données dans BigQuery
  • Utiliser le client BigQuery pour charger des données dans Python
  • Entraîner un modèle TensorFlow avec des couches de prétraitement Keras et un GPU

Pour en savoir plus sur les différentes parties de Vertex AI, consultez la documentation.

7. Nettoyage

Comme le notebook est configuré pour expirer au bout de 60 minutes d'inactivité, il n'est pas nécessaire d'arrêter l'instance. Si vous souhaitez arrêter l'instance manuellement, cliquez sur le bouton "Arrêter" dans la section "Vertex AI Workbench" de la console. Si vous souhaitez supprimer le notebook définitivement, cliquez sur le bouton "Supprimer".

supprimer