Usa las funciones remotas de BigQuery para hacer preguntas a Vertex AI Visual Question Answering (VQA) en una consulta en SQL

1. Introducción

Descripción general

Las funciones remotas de BigQuery te permiten implementar una función en lenguajes distintos de SQL y JavaScript, o con bibliotecas y servicios no permitidos en las funciones definidas por el usuario de BigQuery. Las funciones remotas de BigQuery proporcionan una integración directa con las funciones de Cloud Run y Cloud Run. Para invocar una función remota de BigQuery dentro de una consulta SQL, toma una o más columnas como entrada y, luego, muestra un solo valor como resultado.

Las funciones de Cloud Run son una solución de procesamiento ligera que permite a los desarrolladores crear funciones independientes y de un solo propósito que se pueden activar con HTTPS o responder a CloudEvents sin necesidad de administrar un servidor o entorno de ejecución. Las funciones de Cloud Run son compatibles con Node.js, Python, Go, Java, .NET, Ruby y PHP.

En este codelab, aprenderás a crear una función remota de BigQuery para obtener respuestas a una pregunta sobre imágenes almacenadas en Cloud Storage con Visual Question Answering (VQA) de Vertex AI. Tu consulta en SQL recuperará un URI para una imagen de una tabla en BigQuery. Luego, con una función remota de BigQuery, enviarás el URI de la imagen a una función de Cloud Run que responderá con respuestas de VQA sobre la imagen.

Ilustración

5832020184ccf2b2.png

Desde una perspectiva de desarrollo, estos son los pasos que completarás en este codelab:

  1. Crea el extremo HTTP en las funciones de Cloud Run
  2. Crea una conexión del tipo CLOUD_RESOURCE
  3. Crea una tabla de objetos de BigQuery para el bucket de Cloud Storage
  4. Crea la función remota
  5. Usa la función remota en una consulta como cualquier otra función definida por el usuario

Qué aprenderás

2. Configuración y requisitos

Requisitos previos

Activar Cloud Shell

  1. En la consola de Cloud, haz clic en Activar Cloud Shelld1264ca30785e435.png.

cb81e7c8e34bc8d.png

Si es la primera vez que inicias Cloud Shell, aparecerá una pantalla intermedia en la que se describe qué es. Si aparece una pantalla intermedia, haz clic en Continuar.

d95252b003979716.png

El aprovisionamiento y la conexión a Cloud Shell solo tomará unos minutos.

7833d5e1c5d18f54.png

Esta máquina virtual está cargada con todas las herramientas de desarrollo necesarias. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que mejora considerablemente el rendimiento de la red y la autenticación. Gran parte de tu trabajo en este codelab, si no todo, se puede hacer con un navegador.

Una vez que te conectes a Cloud Shell, deberías ver que se te autenticó y que el proyecto se configuró con tu ID de proyecto.

  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que tienes la autenticación:
gcloud auth list

Resultado del comando

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que el comando gcloud conoce tu proyecto:
gcloud config list project

Resultado del comando

[core]
project = <PROJECT_ID>

De lo contrario, puedes configurarlo con el siguiente comando:

gcloud config set project <PROJECT_ID>

Resultado del comando

Updated property [core/project].

3. Configura variables de entorno local

En este código, crearás algunas variables de entorno para mejorar la legibilidad de los comandos gcloud que se usan en este 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 función de Cloud Run

Para crear una función remota de BigQuery, primero debes crear un extremo HTTP con la función de Cloud Run. El extremo debe poder procesar un lote de filas en una sola solicitud POST HTTP y mostrar los resultados para el lote como una respuesta HTTP.

Esta función de Cloud Run recibirá el URI de almacenamiento de imágenes y la instrucción de la pregunta como entrada de tu consulta de SQL, y mostrará la respuesta de la respuesta visual de preguntas (VQA).

En este codelab, se usa un ejemplo del entorno de ejecución de python311 con el SDK de Vertex AI para Python.

Crea el código fuente de la función

Primero, crea un directorio y ábrelo con el comando cd.

mkdir imagen-vqa && cd $_

Luego, crea un archivo requirements.txt.

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

A continuación, crea un archivo fuente 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

Implementa la función de Cloud Run

Ahora puedes implementar tu función de Cloud Run para el entorno de ejecución python311.

Para implementar una función de Cloud Run directamente en Cloud Run, ejecuta el siguiente comando:

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

Si prefieres implementarla como una función de Cloud Functions de 2ª gen., usa el siguiente comando:

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

y, luego, puedes guardar la URL de la función como una variable de entorno para usarla más adelante.

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

5. Crea el bucket de Cloud Storage

Primero, crea un bucket de Cloud Storage para almacenar tus imágenes.

gcloud storage buckets create gs://$BUCKET_NAME

A continuación, sube una imagen para que la use VQA. En este codelab, se usa la imagen de ejemplo de la documentación de VQA.

Puedes usar la consola de Cloud Storage para subir la imagen directamente a tu bucket. También puedes ejecutar los siguientes comandos para descargar la imagen de ejemplo en tu directorio actual de Cloud Shell.

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

y, luego, subirlo a tu bucket de Cloud Storage.

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

6. Crea una conexión de recursos de Cloud de BigQuery

BigQuery usa una conexión CLOUD_RESOURCE para interactuar con tu Cloud Function. Ejecuta el siguiente comando para crear esta conexión.

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

A continuación, muestra los detalles de la nueva conexión de BigQuery.

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

Guarda el nombre de la cuenta de servicio de conexión de BigQuery en una variable, como se muestra.

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

Otorga acceso a la cuenta de servicio para acceder a tu bucket de Cloud Storage.

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

7. Crea una tabla de objetos de BigQuery

Las tablas de objetos de BigQuery son tablas de solo lectura sobre objetos de datos no estructurados que residen en Cloud Storage.

Las tablas de objetos te permiten analizar datos no estructurados en Cloud Storage. Puedes realizar análisis con funciones remotas y, luego, unir los resultados de estas operaciones con el resto de tus datos estructurados en BigQuery.

Primero, crea un conjunto de datos.

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

El siguiente comando crea una tabla de objetos basada en tu bucket de imágenes de Cloud Storage. La tabla resultante contendrá los URIs de todas las imágenes de ese 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 función remota de BigQuery

El último paso es configurar la función remota de BigQuery.

Primero, otorga permisos a la cuenta de servicio de conexión de BigQuery para invocar la función de Cloud Run. No se recomienda permitir la invocación no autenticada para el servicio de funciones de Cloud Run.

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

A continuación, guarda la consulta de SQL en una 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'
)"

Ahora, ejecuta la consulta.

bq query --nouse_legacy_sql $SQL_CREATE_FUNCTION

Después de ejecutar la consulta para crear la función remota, verás Created <your-project-id>.remote_function_codelab.vqa.

9. Cómo llamar a la función remota de BigQuery en una consulta SQL

Acabas de completar los pasos de desarrollo para crear la función remota. Ahora puedes llamar a tu función de Cloud Run desde una consulta SQL.

Primero, guarda tu pregunta y tu consulta en SQL en una variable. En este codelab, se usa el ejemplo de la documentación de la Búsqueda de respuestas visuales. Esta consulta usa la imagen más reciente que se agregó a tu bucket de almacenamiento.

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

Luego, ejecuta la consulta de SQL para mostrar la respuesta del servicio de búsqueda de respuestas visuales (VQA) de Vertex AI.

bq query --nouse_legacy_sql $SQL_QUERY

Los resultados deberían ser similares al resultado de ejemplo a continuación:

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

10. Solución de problemas

Cuando crees la tabla de BigQuery, si recibes un error BigQuery error in mk operation: Source URI must be a Google Cloud Storage location: gs://$BUCKET_NAME, asegúrate de haber incluido la ruta de acceso /* después de $BUCKET_NAME en el comando.

Cuando ejecutes tu consulta SQL, si recibes un error Access Denied: BigQuery BigQuery: Received response code 403 from endpoint <your-function-endpoint>, espera entre 1 y 2 minutos para que se propague el permiso de rol de invocador de Cloud Function a la cuenta de servicio de conexión de BigQuery antes de volver a intentarlo.

11. ¡Felicitaciones!

¡Felicitaciones por completar el codelab!

Te recomendamos que revises la documentación sobre las funciones remotas de BigQuery y la búsqueda de respuestas visuales (VQA).

Temas abordados

  • Cómo configurar la autenticación en una función de Cloud Run y verificar que se haya configurado correctamente
  • Proporciona el token de tu identidad de gcloud para invocar una función autenticada desde un entorno de desarrollo local
  • Cómo crear una cuenta de servicio y otorgarle el rol adecuado para invocar una función
  • Cómo suplantar la identidad de un servicio desde un entorno de desarrollo local que tenga los roles adecuados para invocar una función

12. Limpia

Para evitar cargos involuntarios (por ejemplo, si esta función de Cloud Run se invoca de forma involuntaria más veces que la asignación mensual de invocación de funciones de Cloud Run en el nivel gratuito), puedes borrar la Cloud Function o borrar el proyecto que creaste en el paso 2.

Para borrar la función de Cloud Run, ve a la consola de Cloud Run en https://console.cloud.google.com/functions/ y borra la función imagen-vqa (o $FUNCTION_NAME en caso de que hayas usado un nombre diferente).

Si decides borrar el proyecto completo, puedes ir a https://console.cloud.google.com/cloud-resource-manager, seleccionar el proyecto que creaste en el paso 2 y elegir Borrar. Si borras el proyecto, deberás cambiar los proyectos en tu SDK de Cloud. Para ver la lista de todos los proyectos disponibles, ejecuta gcloud projects list.