Utiliser les fonctions distantes BigQuery pour poser des questions à Vertex AI grâce à un système de questions-réponses visuelles (VQA) dans une requête SQL

1. Introduction

Présentation

Les fonctions distantes BigQuery vous permettent d'implémenter une fonction dans d'autres langages que SQL et JavaScript, ou avec les bibliothèques et les services qui ne sont pas autorisés dans les fonctions définies par l'utilisateur de BigQuery. Les fonctions distantes BigQuery s'intègrent directement aux fonctions Cloud Run et à Cloud Run. Vous pouvez appeler une fonction à distance BigQuery dans une requête SQL en prenant une ou plusieurs colonnes en entrée, puis en renvoyant une seule valeur en sortie.

Cloud Run Functions est une solution de calcul légère permettant aux développeurs de créer des fonctions autonomes à usage unique qui peuvent être déclenchées à l'aide d'HTTPS ou qui répondent aux CloudEvents sans avoir à gérer de serveur ni d'environnement d'exécution. Les fonctions Cloud Run sont compatibles avec Node.js, Python, Go, Java, .NET, Ruby et PHP.

Dans cet atelier de programmation, vous allez apprendre à créer une fonction distante BigQuery pour obtenir des réponses à une question sur des images stockées dans Cloud Storage à l'aide de la fonctionnalité Visual Question Answering (VQA) (Répondre à des questions visuelles) de Vertex AI. Votre requête SQL récupère un URI pour une image à partir d'une table dans BigQuery. Ensuite, à l'aide d'une fonction distante BigQuery, vous enverrez l'URI de l'image à une fonction Cloud Run qui vous répondra avec les réponses de VQA sur l'image.

Illustration

5832020184ccf2b2.png

Du point de vue du développement, voici les étapes que vous allez suivre dans cet atelier de programmation:

  1. Créer le point de terminaison HTTP dans les fonctions Cloud Run
  2. Créer une connexion de type CLOUD_RESOURCE
  3. Créer une table d'objets BigQuery pour le bucket Cloud Storage
  4. Créer la fonction distante
  5. Utilisez la fonction distante dans une requête comme n'importe quelle autre fonction définie par l'utilisateur.

Points abordés

2. Préparation

Prérequis

Activer Cloud Shell

  1. Dans Cloud Console, cliquez sur Activer Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

Si vous démarrez Cloud Shell pour la première fois, un écran intermédiaire s'affiche. Si un écran intermédiaire vous a été présenté, cliquez sur Continuer.

d95252b003979716.png

Le provisionnement et la connexion à Cloud Shell ne devraient pas prendre plus de quelques minutes.

7833d5e1c5d18f54.png

Cette machine virtuelle contient tous les outils de développement nécessaires. Elle comprend un répertoire d'accueil persistant de 5 Go et s'exécute dans Google Cloud, ce qui améliore considérablement les performances du réseau et l'authentification. Une grande partie, voire la totalité, de votre travail dans cet atelier de programmation peut être effectué dans un navigateur.

Une fois connecté à Cloud Shell, vous êtes en principe authentifié, et le projet est défini avec votre ID de projet.

  1. Exécutez la commande suivante dans Cloud Shell pour vérifier que vous êtes authentifié :
gcloud auth list

Résultat de la commande

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Exécutez la commande suivante dans Cloud Shell pour vérifier que la commande gcloud connaît votre projet:
gcloud config list project

Résultat de la commande

[core]
project = <PROJECT_ID>

Si vous obtenez un résultat différent, exécutez cette commande :

gcloud config set project <PROJECT_ID>

Résultat de la commande

Updated property [core/project].

3. Configurer des variables d'environnement locales

Dans ce code, vous allez créer quelques variables d'environnement pour améliorer la lisibilité des commandes gcloud utilisées dans cet atelier de programmation.

PROJECT_ID=$(gcloud config get-value project)

# Cloud Function variables
FUNCTION_NAME="imagen-vqa"
FUNCTION_REGION="us-central1"

# Cloud Function variables
BUCKET_NAME=$PROJECT_ID-imagen-vqa

# BigQuery variables
DATASET_ID="remote_function_codelab"
TABLE_NAME="images"
BQ_REGION="US"
CONNECTION_ID="imagen_vqa_connection"

4. Créer la fonction Cloud Run

Pour créer une fonction distante BigQuery, vous devez d'abord créer un point de terminaison HTTP à l'aide de la fonction Cloud Run. Le point de terminaison doit pouvoir traiter un lot de lignes dans une seule requête HTTP POST et renvoyer les résultats du lot sous forme de réponse HTTP.

Cette fonction Cloud Run recevra l'URI de stockage d'images et l'invite à la question en tant qu'entrée de votre requête SQL, et renverra la réponse du système de questions-réponses visuelles (VQA).

Cet atelier de programmation utilise un exemple d'environnement d'exécution Python 311 utilisant le SDK Vertex AI pour Python.

Créer le code source de la fonction

Commencez par créer un répertoire et utilisez la commande cd pour y accéder.

mkdir imagen-vqa && cd $_

Ensuite, créez un fichier requirements.txt.

google-cloud-aiplatform[preview]
google-cloud-storage
functions-framework==3.*

Ensuite, créez un fichier source main.py.

from vertexai.preview.vision_models import ImageQnAModel
from vertexai.preview.vision_models import Image
from flask import jsonify
from google.cloud import storage
from urllib.parse import urlparse
import functions_framework

# This is the entry point for the cloud function
@functions_framework.http
def imagen_vqa(request):
    try:
        # See if you can parse the incoming JSON
        return_value = []
        request_json = request.get_json()
        # This grabs the input into the function as called from the SQL function 
        calls = request_json['calls']
        for call in calls:
            # We call the VQA function here in another function defined below
            ai_result = vqa(call)
            # The result to BigQuery is in the order it was prepared in 
            return_value.append(ai_result[0])
        # Prepare the response back to BigQuery
        return_json = jsonify( { "replies": return_value } )
        return return_json
    except Exception as e:
        return jsonify( { "errorMessage": str(e) } ), 400

# Helper function to split apart the GCS URI 
def decode_gcs_url(url):
    # Read the URI and parse it
    p = urlparse(url)
    bucket = p.netloc
    file_path = p.path[0:].split('/', 1)
    # Return the relevant objects (bucket, path to object)
    return bucket, file_path[1]
    
# We can't use the image load from local file since it expects a local path
# We use a GCS URL and get the bytes of the image 
def read_file(object_path):
    # Parse the path
    bucket, file_path = decode_gcs_url(object_path)
    storage_client = storage.Client()
    bucket = storage_client.bucket(bucket)
    blob = bucket.blob(file_path)
    # Return the object as bytes
    return blob.download_as_bytes()

# This is the function that calls the VQA function
def vqa (parameters):
    # This is the model we want to use
    image_qna_model = ImageQnAModel.from_pretrained("imagetext@001")
    # The location is the first parameter 
    image_loc = parameters[0]
    # Get the bytes 
    image_bytes = read_file(image_loc)
    # Load the bytes into the Image handler
    input_image = Image(image_bytes)
    # Ask the VQA the question
    results = image_qna_model.ask_question(
        image=input_image,
        # The prompt was the second parameter
        question=parameters[1],
        number_of_results=1
    )
    return results

Déployer la fonction Cloud Run

Vous pouvez maintenant déployer votre fonction Cloud Run pour l'environnement d'exécution python311.

Pour déployer une fonction Cloud Run directement sur Cloud Run, exécutez la commande suivante:

gcloud beta run deploy $FUNCTION_NAME \
      --source . \
      --function imagen_vqa \
      --region $FUNCTION_REGION \
      --no-allow-unauthenticated

Si vous préférez déployer en tant que Cloud Functions (2e génération), utilisez la commande suivante:

gcloud functions deploy $FUNCTION_NAME \
--gen2 \
--region=$FUNCTION_REGION \
--runtime=python311 \
--trigger-http \
--source=. \
--no-allow-unauthenticated

Vous pouvez ensuite enregistrer l'URL de la fonction en tant que variable d'environnement pour l'utiliser ultérieurement.

ENDPOINT_URL="$(gcloud beta run services describe $FUNCTION_NAME --region $FUNCTION_REGION --format='value(status.url)')"

5. Créer le bucket Cloud Storage

Commencez par créer un bucket Cloud Storage pour stocker vos images.

gcloud storage buckets create gs://$BUCKET_NAME

Ensuite, importez une image que VQA pourra utiliser. Cet atelier de programmation utilise l'exemple d'image de la documentation sur la VQA.

Vous pouvez utiliser la console Cloud pour Cloud Storage pour importer l'image directement dans votre bucket. Vous pouvez également exécuter les commandes suivantes pour télécharger l'exemple d'image dans votre répertoire Cloud Shell actuel :

wget -O image.jpg -o /dev/null https://unsplash.com/photos/QqN25A3iF9w/download?ixid=M3wxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNjk1NzYxMjY2fA&force=true

puis importez-le dans votre bucket Cloud Storage.

gcloud storage cp image.jpg gs://$BUCKET_NAME

6. Créer une connexion à une ressource cloud BigQuery

BigQuery utilise une connexion CLOUD_RESOURCE pour interagir avec votre fonction Cloud. Exécutez la commande suivante pour créer cette connexion.

bq mk --connection --location=$BQ_REGION --project_id=$PROJECT_ID \
--connection_type=CLOUD_RESOURCE $CONNECTION_ID

Affichez ensuite les détails de la nouvelle connexion BigQuery.

bq show --connection $PROJECT_ID.$BQ_REGION.$CONNECTION_ID

Enregistrez le nom du compte de service de connexion BigQuery dans une variable, comme indiqué.

CONNECTION_SA="<YOUR-SERVICE-ACCOUNT-ID>@gcp-sa-bigquery-condel.iam.gserviceaccount.com"

Accordez au compte de service l'accès à votre bucket Cloud Storage.

gsutil iam ch serviceAccount:$CONNECTION_SA:objectAdmin gs://$BUCKET_NAME

7. Créer une table d'objets BigQuery

Les tables d'objets BigQuery sont des tables en lecture seule sur des objets de données non structurés stockés dans Cloud Storage.

Les tables d'objets vous permettent d'analyser des données non structurées dans Cloud Storage. Vous pouvez effectuer une analyse avec des fonctions à distance, puis joindre les résultats de ces opérations aux autres données structurées dans BigQuery.

Commencez par créer un ensemble de données.

bq --location=$BQ_REGION mk \
    --dataset \
    $DATASET_ID

La commande suivante crée une table d'objets basée sur votre bucket d'images Cloud Storage. La table générée contient les URI de toutes les images de ce bucket.

bq mk --table \
--external_table_definition=gs://$BUCKET_NAME/*@$BQ_REGION.$CONNECTION_ID \
--object_metadata=SIMPLE \
$PROJECT_ID:$DATASET_ID.$TABLE_NAME

8. Créer la fonction distante BigQuery

La dernière étape consiste à configurer la fonction distante BigQuery.

Commencez par accorder au compte de service de connexion BigQuery les autorisations nécessaires pour appeler la fonction Cloud Run. Il n'est pas recommandé d'autoriser les appels non authentifiés pour votre service de fonction Cloud Run.

gcloud run services add-iam-policy-binding $FUNCTION_NAME \
 --member=serviceAccount:$CONNECTION_SA \
 --role="roles/run.invoker" \
 --region $FUNCTION_REGION

Enregistrez ensuite la requête SQL dans une variable.

SQL_CREATE_FUNCTION="CREATE FUNCTION \`$PROJECT_ID.$DATASET_ID\`.vqa(uri STRING, image_prompt STRING) RETURNS STRING
REMOTE WITH CONNECTION \`$PROJECT_ID.$BQ_REGION.$CONNECTION_ID\`
OPTIONS (
  endpoint = '$ENDPOINT_URL'
)"

Maintenant, exécutez la requête.

bq query --nouse_legacy_sql $SQL_CREATE_FUNCTION

Après avoir exécuté la requête permettant de créer la fonction distante, le message Created <your-project-id>.remote_function_codelab.vqa s'affiche.

9. Appeler la fonction distante BigQuery dans une requête SQL

Vous avez maintenant terminé les étapes de développement pour créer la fonction distante. Vous pouvez désormais appeler votre fonction Cloud Run à partir d'une requête SQL.

Commencez par enregistrer votre question et votre requête SQL dans une variable. Cet atelier de programmation utilise l'exemple de la documentation Visual Question Answering. Cette requête utilise la dernière image ajoutée à votre bucket de stockage.

export SQL_QUERY="DECLARE question STRING DEFAULT 'What objects are in the image?';
SELECT uri, image_prompt ,\`$DATASET_ID\`.vqa(uri, image_prompt) as result
FROM ( 
  SELECT 
  *, 
  dense_rank() over (order by updated) as rnk ,
  question as image_prompt
  FROM \`$PROJECT_ID.$DATASET_ID.images\`) as innertable
  WHERE rnk  = 1;
"

Exécutez ensuite la requête SQL pour afficher la réponse du service de réponse visuelle (VQA) de Vertex AI.

bq query --nouse_legacy_sql $SQL_QUERY

Les résultats doivent ressembler à l'exemple ci-dessous:

+---------------------------------+--------------------------------+----------+
|               uri               |    image_prompt                |  result  |
+---------------------------------+--------------------------------+----------+
| gs://<YOUR_BUCKET>/image.jpg    | What objects are in the image? |  marbles |
+---------------------------------+--------------------------------+----------+

10. Dépannage

Lorsque vous créez la table BigQuery, si vous recevez une erreur BigQuery error in mk operation: Source URI must be a Google Cloud Storage location: gs://$BUCKET_NAME, assurez-vous d'avoir inclus le chemin d'accès /* après $BUCKET_NAME dans la commande.

Lorsque vous exécutez votre requête SQL, si vous obtenez une erreur Access Denied: BigQuery BigQuery: Received response code 403 from endpoint <your-function-endpoint>, essayez d'attendre environ une à deux minutes pour que l'autorisation de rôle d'appelant de fonction Cloud se propage au compte de service de connexion BigQuery avant de réessayer.

11. Félicitations !

Félicitations, vous avez terminé l'atelier de programmation.

Nous vous recommandons de consulter la documentation sur les fonctions distantes BigQuery et la résolution de questions visuelles (VQA).

Points abordés

  • Configurer l'authentification sur une fonction Cloud Run et vérifier qu'elle a été correctement configurée
  • Appeler une fonction authentifiée à partir d'un environnement de développement local en fournissant le jeton de votre identité gcloud
  • Créer un compte de service et lui attribuer le rôle approprié pour appeler une fonction
  • usurper l'identité d'un service à partir d'un environnement de développement local disposant des rôles appropriés pour appeler une fonction.

12. Effectuer un nettoyage

Pour éviter les frais involontaires (par exemple, si cette fonction Cloud Run est appelée par inadvertance plus de fois que votre quota mensuel d'appels de fonctions Cloud Run dans le niveau sans frais), vous pouvez supprimer la fonction Cloud ou le projet que vous avez créé à l'étape 2.

Pour supprimer la fonction Cloud Run, accédez à la console Cloud Run à l'adresse https://console.cloud.google.com/functions/, puis supprimez la fonction imagen-vqa (ou $FUNCTION_NAME si vous avez utilisé un autre nom).

Si vous choisissez de supprimer l'ensemble du projet, accédez à https://console.cloud.google.com/cloud-resource-manager, sélectionnez le projet que vous avez créé à l'étape 2, puis choisissez "Supprimer". Si vous supprimez le projet, vous devrez le modifier dans Cloud SDK. Vous pouvez afficher la liste de tous les projets disponibles en exécutant gcloud projects list.