Utilizzare le funzioni remote di BigQuery per porre domande a Vertex AI Visual Question Answering (VQA) in una query SQL

1. Introduzione

Panoramica

Le funzioni remote di BigQuery ti consentono di implementare una funzione in linguaggi diversi da SQL e JavaScript o con le librerie e i servizi non consentiti nelle funzioni definite dall'utente di BigQuery. Le funzioni remote di BigQuery forniscono un'integrazione diretta con le funzioni di Cloud Run e Cloud Run. Puoi richiamare una funzione remota di BigQuery all'interno di una query SQL prendendo una o più colonne come input e restituendo un singolo valore come output.

Le funzioni Cloud Run sono una soluzione di calcolo leggera che consente agli sviluppatori di creare funzioni autonome a uso specifico che possono essere attivate tramite HTTPS o rispondere a CloudEvents senza dover gestire un ambiente server o di runtime. Le funzioni Cloud Run supportano Node.js, Python, Go, Java, .NET, Ruby e PHP.

In questo codelab imparerai a creare una funzione remota BigQuery per ottenere risposte a una domanda sulle immagini archiviate in Cloud Storage utilizzando Visual Question Answering (VQA) di Vertex AI. La query SQL recupererà un URI per un'immagine da una tabella in BigQuery. Quindi, utilizzando una funzione remota di BigQuery, invierai l'URI dell'immagine a una funzione Cloud Run che risponderà con le risposte di VQA sull'immagine.

Illustrazione

5832020184ccf2b2.png

Dal punto di vista dello sviluppo, questi sono i passaggi che dovrai completare in questo codelab:

  1. Crea l'endpoint HTTP nelle funzioni di Cloud Run
  2. Crea una connessione di tipo CLOUD_RESOURCE
  3. crea una tabella di oggetti BigQuery per il bucket Cloud Storage
  4. Crea la funzione remota
  5. Utilizza la funzione remota in una query come qualsiasi altra funzione definita dall'utente

Cosa imparerai a fare

2. Configurazione e requisiti

Prerequisiti

Attiva Cloud Shell

  1. Nella console Cloud, fai clic su Attiva Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

Se è la prima volta che avvii Cloud Shell, viene visualizzata una schermata intermedia che descrive di cosa si tratta. Se viene visualizzata una schermata intermedia, fai clic su Continua.

d95252b003979716.png

Dovrebbero bastare pochi istanti per eseguire il provisioning e connettersi a Cloud Shell.

7833d5e1c5d18f54.png

Questa macchina virtuale viene caricata con tutti gli strumenti di sviluppo necessari. Offre una home directory permanente da 5 GB e viene eseguita in Google Cloud, migliorando notevolmente le prestazioni e l'autenticazione della rete. Gran parte, se non tutto, del lavoro in questo codelab può essere svolto con un browser.

Una volta eseguita la connessione a Cloud Shell, dovresti vedere che il tuo account è già autenticato e il progetto è già impostato sul tuo ID progetto.

  1. Esegui questo comando in Cloud Shell per verificare che l'account sia autenticato:
gcloud auth list

Output comando

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Esegui il seguente comando in Cloud Shell per verificare che il comando gcloud conosca il tuo progetto:
gcloud config list project

Output comando

[core]
project = <PROJECT_ID>

In caso contrario, puoi impostarlo con questo comando:

gcloud config set project <PROJECT_ID>

Output comando

Updated property [core/project].

3. Configura le variabili di ambiente locale

In questo codice, creerai alcune variabili di ambiente per migliorare la leggibilità dei comandi gcloud utilizzati in questo codelab.

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. Crea la funzione Cloud Run

Per creare una funzione remota BigQuery, devi prima creare un endpoint HTTP utilizzando la funzione Cloud Run. L'endpoint deve essere in grado di elaborare un batch di righe in una singola richiesta POST HTTP e restituire i risultati del batch come risposta HTTP.

Questa funzione Cloud Run riceverà l'URI di archiviazione delle immagini e il prompt della domanda come input dalla query SQL e restituirà la risposta dalla Visual Question Answering (VQA).

Questo codelab utilizza un esempio per l'ambiente di runtime python311 che utilizza l'SDK Vertex AI per Python.

Crea il codice sorgente della funzione

Innanzitutto, crea una directory e accedi tramite cd.

mkdir imagen-vqa && cd $_

Poi, crea un file requirements.txt.

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

Successivamente, crea un file di origine 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

Esegui il deployment della funzione Cloud Run

Ora puoi eseguire il deployment della funzione Cloud Run per il runtime python311.

Per eseguire il deployment di una funzione Cloud Run direttamente su Cloud Run, esegui il seguente comando:

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

Se preferisci eseguire il deployment come Cloud Functions (2a gen), utilizza il seguente comando:

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

e poi salvare l'URL della funzione come variabile di ambiente da utilizzare in seguito.

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

5. Crea il bucket Cloud Storage

Per prima cosa, crea un bucket Cloud Storage per archiviare le immagini.

gcloud storage buckets create gs://$BUCKET_NAME

Successivamente, carica un'immagine da utilizzare per la VQA. Questo codelab utilizza l'immagine di esempio della documentazione di VQA.

Puoi utilizzare la console Cloud per Cloud Storage per caricare l'immagine direttamente nel tuo bucket. In alternativa, puoi eseguire i seguenti comandi per scaricare l'immagine di esempio nella directory Cloud Shell corrente

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

e poi caricalo nel tuo bucket Cloud Storage.

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

6. Crea una connessione a una risorsa cloud per BigQuery

BigQuery utilizza una connessione CLOUD_RESOURCE per interagire con la funzione Cloud Functions. Esegui questo comando per creare questa connessione.

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

A questo punto, vengono visualizzati i dettagli della nuova connessione BigQuery.

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

Salva il nome dell'account di servizio della connessione BigQuery in una variabile, come mostrato.

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

Concedi all'account di servizio l'accesso al bucket Cloud Storage.

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

7. Creare una tabella di oggetti BigQuery

Le tabelle di oggetti BigQuery sono tabelle di sola lettura su oggetti di dati non strutturati che risiedono in Cloud Storage.

Le tabelle di oggetti ti consentono di analizzare i dati non strutturati in Cloud Storage. Puoi eseguire analisi con le funzioni remote e unire i risultati di queste operazioni con il resto dei dati strutturati in BigQuery.

Per prima cosa, crea un set di dati.

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

Il seguente comando crea una tabella di oggetti basata sul bucket di immagini Cloud Storage. La tabella risultante conterrà gli URI di tutte le immagini nel bucket.

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

8. Crea la funzione remota BigQuery

L'ultimo passaggio consiste nel configurare la funzione remota BigQuery.

Innanzitutto, concedi all'account di servizio della connessione BigQuery le autorizzazioni per richiamare la funzione Cloud Run. Non è consigliabile consentire l'invocazione non autenticata per il servizio di funzioni Cloud Run.

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

Poi, salva la query SQL in una variabile.

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

Ora esegui la query.

bq query --nouse_legacy_sql $SQL_CREATE_FUNCTION

Dopo aver eseguito la query per creare la funzione remota, vedrai Created <your-project-id>.remote_function_codelab.vqa

9. Chiamare la funzione remota di BigQuery in una query SQL

Hai completato i passaggi di sviluppo per la creazione della funzione remota. Ora puoi chiamare la funzione Cloud Run da una query SQL.

Innanzitutto, salva la domanda e la query SQL in una variabile. Questo codelab utilizza l'esempio riportato nella documentazione di Visual Question Answering. Questa query utilizza l'immagine più recente aggiunta al bucket di archiviazione.

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;
"

Quindi esegui la query SQL per mostrare la risposta del servizio Vertex AI Visual Question Answering (VQA).

bq query --nouse_legacy_sql $SQL_QUERY

I risultati dovrebbero essere simili all'output di esempio seguente:

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

10. Risoluzione dei problemi

Durante la creazione della tabella BigQuery, se ricevi un errore BigQuery error in mk operation: Source URI must be a Google Cloud Storage location: gs://$BUCKET_NAME, assicurati di aver incluso il percorso /* dopo $BUCKET_NAME nel comando.

Quando esegui la query SQL, se ricevi un errore Access Denied: BigQuery BigQuery: Received response code 403 from endpoint <your-function-endpoint>, prova ad attendere circa 1-2 minuti affinché la concessione dell'autorizzazione del ruolo Invoker di funzione cloud venga propagata all'account di servizio di connessione BigQuery prima di riprovare.

11. Complimenti!

Complimenti per aver completato il codelab.

Ti consigliamo di consultare la documentazione sulle funzioni remote di BigQuery e sulla risposta alle domande visive (VQA).

Argomenti trattati

  • Come configurare l'autenticazione in una funzione Cloud Run e verificare che sia stata configurata correttamente
  • Esegui una chiamata a una funzione autenticata da un ambiente di sviluppo locale fornendo il token per la tua identità gcloud
  • Come creare un account di servizio e concedergli il ruolo appropriato per richiamare una funzione
  • Come impersonare un servizio da un ambiente di sviluppo locale che dispone dei ruoli appropriati per richiamare una funzione

12. Esegui la pulizia

Per evitare addebiti involontari, ad esempio se questa funzione Cloud Run viene richiamata inavvertitamente più volte rispetto all'allocazione mensile dei richiami della funzione Cloud Run nel livello senza costi, puoi eliminare la funzione Cloud Functions o eliminare il progetto che hai creato nel passaggio 2.

Per eliminare la funzione Cloud Run, vai alla console Cloud Run all'indirizzo https://console.cloud.google.com/functions/ ed elimina la funzione imagen-vqa (o $FUNCTION_NAME se hai utilizzato un nome diverso).

Se scegli di eliminare l'intero progetto, puoi andare all'indirizzo https://console.cloud.google.com/cloud-resource-manager, selezionare il progetto che hai creato nel passaggio 2 e scegliere Elimina. Se elimini il progetto, dovrai modificare i progetti nel tuo Cloud SDK. Puoi visualizzare l'elenco di tutti i progetti disponibili eseguendo gcloud projects list.