usar as funções remotas do BigQuery para fazer perguntas ao recurso visual de resposta a perguntas (VQA, na sigla em inglês) da Vertex AI em uma consulta SQL.

1. Introdução

Visão geral

As funções remotas do BigQuery permitem implementar uma função em outras linguagens além do SQL e do JavaScript ou com bibliotecas e serviços não permitidos nas funções definidas pelo usuário do BigQuery. As funções remotas do BigQuery oferecem uma integração direta com as funções do Cloud Run e o Cloud Run. É possível invocar uma função remota do BigQuery em uma consulta SQL usando uma ou mais colunas como entrada e retornando um único valor como saída.

Funções do Cloud Run é uma solução de computação leve para desenvolvedores. Ele cria funções autônomas com uma finalidade única que podem ser acionadas usando HTTPS ou responder a CloudEvents sem a necessidade de gerenciar um servidor ou um ambiente de execução. As funções do Cloud Run são compatíveis com Node.js, Python, Go, Java, .NET, Ruby e PHP.

Neste codelab, você vai aprender a criar uma função remota do BigQuery para receber respostas a uma pergunta sobre imagens armazenadas no Cloud Storage usando a resposta a perguntas visuais (VQA) da Vertex AI. Sua consulta SQL recuperará um URI para uma imagem de uma tabela no BigQuery. Em seguida, usando uma função remota do BigQuery, você vai enviar o URI da imagem para uma função do Cloud Run, que vai responder com respostas da VQA sobre a imagem.

Ilustração

5832020184ccf2b2.png

Do ponto de vista do desenvolvimento, estas são as etapas que você vai concluir neste codelab:

  1. Crie o endpoint HTTP nas funções do Cloud Run
  2. Criar uma conexão do tipo CLOUD_RESOURCE
  3. Criar uma tabela de objetos do BigQuery para o bucket do Cloud Storage
  4. Criar a função remota
  5. Use a função remota em uma consulta como qualquer outra função definida pelo usuário.

O que você vai aprender

2. Configuração e requisitos

Pré-requisitos

Ativar o Cloud Shell

  1. No Console do Cloud, clique em Ativar o Cloud Shelld1264ca30785e435.png.

cb81e7c8e34bc8d.png

Se esta for a primeira vez que você iniciar o Cloud Shell, uma tela intermediária vai aparecer com uma descrição dele. Se esse for o caso, clique em Continuar.

d95252b003979716.png

Leva apenas alguns instantes para provisionar e se conectar ao Cloud Shell.

7833d5e1c5d18f54.png

Essa máquina virtual tem todas as ferramentas de desenvolvimento necessárias. Ela oferece um diretório principal persistente de 5 GB e é executada no Google Cloud. Isso aprimora o desempenho e a autenticação da rede. Grande parte do trabalho neste codelab, se não todo, pode ser feito em um navegador.

Depois de se conectar ao Cloud Shell, você verá sua autenticação e o projeto estará configurado com o ID do seu projeto.

  1. Execute o seguinte comando no Cloud Shell para confirmar se a conta está autenticada:
gcloud auth list

Resposta ao comando

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Execute o comando a seguir no Cloud Shell para confirmar se o comando gcloud sabe sobre seu projeto:
gcloud config list project

Resposta ao comando

[core]
project = <PROJECT_ID>

Se o projeto não estiver configurado, configure-o usando este comando:

gcloud config set project <PROJECT_ID>

Resposta ao comando

Updated property [core/project].

3. Configurar variáveis de ambiente locais

Neste código, você vai criar algumas variáveis de ambiente para melhorar a legibilidade dos comandos gcloud usados neste 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. Criar a função do Cloud Run

Para criar uma função remota do BigQuery, você precisa primeiro criar um endpoint HTTP usando a função do Cloud Run. O endpoint precisa processar um lote de linhas em uma única solicitação POST HTTP e retornar os resultados em lote como uma resposta HTTP.

Esse função do Cloud Run vai receber o URI de armazenamento de imagens e a pergunta como entrada da consulta SQL e retornar a resposta da resposta visual para perguntas (VQA).

Este codelab usa um exemplo para o ambiente de execução python311 com o SDK da Vertex AI para Python.

Criar o código-fonte da função

Primeiro, crie um diretório e use cd nele.

mkdir imagen-vqa && cd $_

Em seguida, crie um arquivo requirements.txt.

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

Em seguida, crie um arquivo de origem 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

Implantar a Cloud Run function

Agora você pode implantar sua função do Cloud Run para o ambiente de execução python311.

Para implantar uma função do Cloud Run diretamente no Cloud Run, execute o seguinte comando:

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

Se preferir implantar como um Cloud Functions (2nd gen), use o seguinte comando:

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

e salve o URL da função como uma variável de ambiente para usar mais tarde.

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

5. Criar o bucket do Cloud Storage

Primeiro, crie um bucket do Cloud Storage para armazenar suas imagens.

gcloud storage buckets create gs://$BUCKET_NAME

Em seguida, faça upload de uma imagem para usar o VQA. Este codelab usa a imagem de exemplo da documentação da VQA.

Você pode usar o console do Cloud Storage para fazer o upload da imagem diretamente no bucket. Ou execute os comandos a seguir para fazer o download da imagem de exemplo no diretório atual do Cloud Shell.

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

e faça upload para o bucket do Cloud Storage.

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

6. Criar uma conexão do recurso de nuvem do BigQuery

O BigQuery usa uma conexão CLOUD_RESOURCE para interagir com a função do Cloud. Execute o comando a seguir para criar essa conexão.

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

Em seguida, mostre os detalhes da nova conexão do BigQuery.

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

Salve o nome da conta de serviço de conexão do BigQuery em uma variável, conforme mostrado.

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

Conceda à conta de serviço acesso ao bucket do Cloud Storage.

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

7. Crie uma tabela de objetos do BigQuery

As tabelas de objetos do BigQuery são tabelas somente leitura sobre objetos de dados não estruturados que residem no Cloud Storage.

As tabelas de objetos permitem analisar dados não estruturados no Cloud Storage. É possível fazer análises com funções remotas e, em seguida, mesclar os resultados dessas operações com o restante dos seus dados estruturados no BigQuery.

Primeiro, crie um conjunto de dados.

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

O comando a seguir cria uma tabela de objetos com base no bucket de imagens do Cloud Storage. A tabela resultante vai conter os URIs de todas as imagens nesse bucket.

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

8. Criar a função remota do BigQuery

A última etapa é configurar a função remota do BigQuery.

Primeiro, conceda permissões à conta de serviço de conexão do BigQuery para invocar a função do Cloud Run. Não recomendamos invocações não autenticadas para seu serviço de função do Cloud Run.

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

Em seguida, salve a consulta SQL em uma variável.

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

Agora, execute a consulta.

bq query --nouse_legacy_sql $SQL_CREATE_FUNCTION

Depois de executar a consulta para criar a função remota, você verá Created <your-project-id>.remote_function_codelab.vqa

9. Chamar a função remota do BigQuery em uma consulta SQL

Você concluiu as etapas de desenvolvimento para criar a função remota. Agora você pode chamar sua função do Cloud Run em uma consulta SQL.

Primeiro, salve sua pergunta e consulta SQL em uma variável. Este codelab usa o exemplo da documentação da Resposta visual a perguntas. Essa consulta usa a imagem mais recente adicionada ao bucket de armazenamento.

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

Em seguida, execute a consulta SQL para mostrar a resposta do serviço de resposta visual a perguntas (VQA) da Vertex AI.

bq query --nouse_legacy_sql $SQL_QUERY

Os resultados devem ser semelhantes ao exemplo abaixo:

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

10. Solução de problemas

Ao criar a tabela do BigQuery, se você receber um erro BigQuery error in mk operation: Source URI must be a Google Cloud Storage location: gs://$BUCKET_NAME, verifique se incluiu o caminho /* após o $BUCKET_NAME no comando.

Ao executar a consulta SQL, se você receber um erro Access Denied: BigQuery BigQuery: Received response code 403 from endpoint <your-function-endpoint>, aguarde cerca de um a dois minutos para que a concessão de permissão de função do Cloud Function seja propagada para a conta de serviço de conexão do BigQuery antes de tentar novamente.

11. Parabéns!

Parabéns por concluir o codelab.

Recomendamos que você analise a documentação sobre Funções remotas do BigQuery e Respostas visuais a perguntas (VQA).

O que vimos

  • Como configurar a autenticação em uma função do Cloud Run e verificar se a autenticação foi configurada corretamente
  • Invocar uma função autenticada de um ambiente de desenvolvimento local fornecendo o token para sua identidade do gcloud
  • Como criar uma conta de serviço e conceder a ela o papel apropriado para invocar uma função
  • Como falsificar um serviço em um ambiente de desenvolvimento local que tenha as funções adequadas para invocar uma função

12. Limpar

Para evitar cobranças acidentais (por exemplo, se essa função do Cloud Run for invocada acidentalmente mais vezes do que sua alocação mensal de invocação de função do Cloud Run no nível sem custo financeiro), exclua a Cloud Function ou o projeto criado na etapa 2.

Para excluir a função do Cloud Run, acesse o console do Cloud Run em https://console.cloud.google.com/functions/ e exclua a função imagen-vqa (ou $FUNCTION_NAME, caso você tenha usado um nome diferente).

Se você quiser excluir o projeto inteiro, acesse https://console.cloud.google.com/cloud-resource-manager, selecione o projeto criado na etapa 2 e escolha "Excluir". Se você excluir o projeto, vai precisar mudar os projetos no Cloud SDK. Para conferir a lista de todos os projetos disponíveis, execute gcloud projects list.