Effectuer des prédictions avec des modèles PyTorch au format ONNX

Présentation

Open Neural Network Exchange (ONNX) fournit un format uniforme conçu pour représenter tous les frameworks de machine learning. La compatibilité de BigQuery ML avec ONNX vous permet de :

  • Entraîner un modèle à l'aide du framework de votre choix
  • Convertir le modèle au format ONNX (pour en savoir plus, consultez la section Convertir au format ONNX)
  • Importer le modèle ONNX dans BigQuery et effectuer des prédictions à l'aide de BigQuery ML

Ce tutoriel explique comment importer des modèles ONNX entraînés avec PyTorch dans un ensemble de données BigQuery et les utiliser pour effectuer des prédictions à partir d'une requête SQL. Vous pouvez importer des modèles ONNX à l'aide des interfaces suivantes :

Pour en savoir plus sur l'importation de modèles ONNX dans BigQuery, y compris sur les exigences en matière de format et de stockage, consultez la page Instruction CREATE MODEL pour l'importation de modèles ONNX.

Objectifs

Au cours de ce tutoriel, vous allez :

  • créer et entraîner des modèles avec PyTorch ;
  • convertir les modèles au format ONNX à l'aide de torch.onnx ;
  • importer les modèles ONNX dans BigQuery et effectuer des prédictions.

Créer un modèle de vision PyTorch pour la classification d'images

Importez une clé resnet18 pré-entraînée PyTorch qui accepte les données d'image décodées renvoyées par BigQuery ML ML.DECODE_IMAGE et ML.RESIZE_IMAGE.

import torch
import torch.nn as nn

# Define model input format to match the output format of
# ML.DECODE_IMAGE function: [height, width, channels]
dummy_input = torch.randn(1, 224, 224, 3, device="cpu")

# Load a pretrained pytorch model for image classification
model = torch.hub.load('pytorch/vision:v0.10.0', 'resnet18', pretrained=True)

# Reshape input format from [batch_size, height, width, channels]
# to [batch_size, channels, height, width]
class ReshapeLayer(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, x):
        x = x.permute(0, 3, 1, 2)  # reorder dimensions
        return x

class ArgMaxLayer(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, x):
       return torch.argmax(x, dim=1)

final_model = nn.Sequential(
    ReshapeLayer(),
    model,
    nn.Softmax(),
    ArgMaxLayer()
)

Convertir le modèle au format ONNX et l'enregistrer

Utilisez torch.onnx pour exporter le modèle de vision PyTorch vers un fichier ONNX nommé resnet18.onnx.

torch.onnx.export(final_model,            # model being run
                  dummy_input,            # model input
                  "resnet18.onnx",        # where to save the model
                  opset_version=10,       # the ONNX version to export the model to
                  input_names = ['input'],         # the model's input names
                  output_names = ['class_label'])  # the model's output names

Importer le modèle ONNX dans Cloud Storage

Créez un bucket Cloud Storage pour stocker le fichier de modèle ONNX, puis importez le fichier de modèle ONNX enregistré dans votre bucket Cloud Storage. Pour en savoir plus, consultez la page Importer des objets à partir d'un système de fichiers.

Importer le modèle ONNX dans BigQuery

Cette étape suppose que vous avez importé le modèle ONNX dans votre bucket Cloud Storage. Un exemple de modèle est stocké à l'emplacement gs://cloud-samples-data/bigquery/ml/onnx/resnet18.onnx.

Console

  1. Dans Google Cloud Console, accédez à la page "BigQuery".

    Accéder à BigQuery

  2. Dans l'éditeur de requêtes, saisissez l'instruction CREATE MODEL suivante :

     CREATE OR REPLACE MODEL `mydataset.mymodel`
      OPTIONS (MODEL_TYPE='ONNX',
       MODEL_PATH='gs://bucket/path/to/onnx_model/*')
    

    Exemple :

     CREATE OR REPLACE MODEL `example_dataset.imported_onnx_model`
      OPTIONS (MODEL_TYPE='ONNX',
       MODEL_PATH='gs://cloud-samples-data/bigquery/ml/onnx/resnet18.onnx')
    

    La requête précédente importe le modèle ONNX situé à l'emplacement gs://cloud-samples-data/bigquery/ml/onnx/resnet18.onnx en tant que modèle BigQuery nommé imported_onnx_model.

  3. Votre nouveau modèle devrait désormais s'afficher dans le panneau Ressources. À mesure que vous développez chacun des ensembles de données d'un projet, les modèles sont répertoriés avec les autres ressources BigQuery des ensembles de données. Les modèles sont indiqués par l'icône icône de modèle.

  4. Si vous sélectionnez le nouveau modèle dans le panneau Ressources, les informations relatives au modèle s'affichent sous l'éditeur de requête.

    informations sur le modèle onnx

bq

Pour importer un modèle ONNX à partir de Cloud Storage, exécutez une requête par lot en saisissant une commande semblable à la suivante :

bq query \
--use_legacy_sql=false \
"CREATE MODEL
  `mydataset.mymodel`
OPTIONS
  (MODEL_TYPE='ONNX',
   MODEL_PATH='gs://bucket/path/to/onnx_model/*')"

Exemple :

bq query --use_legacy_sql=false \
"CREATE OR REPLACE MODEL
  `example_dataset.imported_onnx_model`
OPTIONS
  (MODEL_TYPE='ONNX',
   MODEL_PATH='gs://cloud-samples-data/bigquery/ml/onnx/resnet18.onnx')"

Une fois le modèle importé, il doit apparaître dans le résultat de la requête bq ls [dataset_name] :

$ bq ls example_dataset

       tableId          Type    Labels   Time Partitioning
 --------------------- ------- -------- -------------------
  imported_onnx_model   MODEL

API

Insérez une nouvelle tâche et renseignez la propriété jobs#configuration.query comme dans le corps de la requête suivante :

{
  "query": "CREATE MODEL `project_id:mydataset.mymodel` OPTIONS(MODEL_TYPE='ONNX' MODEL_PATH='gs://bucket/path/to/onnx_model/*')"
}

Créer une table d'objets dans BigQuery pour accéder aux données d'image

Pour accéder aux données non structurées dans BigQuery, vous devez créer une table d'objets. Consultez la page Créer des tables d'objets pour obtenir des instructions détaillées.

Créez une table d'objets nommée goldfish_image_table sur une image d'un poisson rouge stockée dans gs://mybucket/goldfish.jpg.

CREATE EXTERNAL TABLE `example_dataset.goldfish_image_table`
WITH CONNECTION `us.my-connection`
OPTIONS(
  object_metadata = 'SIMPLE',
  uris = ['gs://mybucket/goldfish.jpg'],
  max_staleness = INTERVAL 1 DAY,
  metadata_cache_mode = 'AUTOMATIC');

Effectuer des prédictions à l'aide du modèle ONNX importé

Console

  1. Dans Google Cloud Console, accédez à la page "BigQuery".

    Accéder à BigQuery

  2. Dans l'éditeur de requête, saisissez une requête à l'aide de ML.PREDICT comme ceci :

     SELECT
       class_label
     FROM
       ML.PREDICT(MODEL example_dataset.imported_onnx_model,
         (
         SELECT
           ML.RESIZE_IMAGE(ML.DECODE_IMAGE(DATA),
             224,
             224,
             FALSE) AS input
         FROM
           example_dataset.goldfish_image_table) )
     

    La requête précédente utilise le modèle nommé imported_onnx_model dans l'ensemble de données example_dataset du projet en cours pour effectuer des prédictions à partir des données d'image de la table d'objets d'entrée goldfish_image_table. La fonction ML.DECODE_IMAGE est requise pour décoder les données d'image afin qu'elles puissent être interprétées par ML.PREDICT. De plus, la fonction ML.RESIZE_IMAGE est appelée pour redimensionner l'image en fonction de la taille de l'entrée du modèle (224 x 224). Pour en savoir plus sur l'exécution d'inférences sur des tables d'objets d'images, consultez la page Exécuter des inférences sur des tables d'objets d'images.

    Cette requête génère le libellé de classe prédit pour l'image d'entrée en fonction du dictionnaire LabelsNet.

    Résultats de la requête

bq

Pour effectuer des prédictions à partir des données d'entrée de la table input_data, saisissez une commande comme suit, à l'aide du modèle ONNX importé my_model :

bq query \
--use_legacy_sql=false \
'SELECT *
 FROM ML.PREDICT(
   MODEL `my_project.my_dataset.my_model`,
   (SELECT * FROM input_data))'

API

Insérez une nouvelle tâche et renseignez la propriété jobs#configuration.query comme dans le corps de la requête suivante :

{
  "query": "SELECT * FROM ML.PREDICT(MODEL `my_project.my_dataset.my_model`, (SELECT * FROM input_data))"
}

Étapes suivantes