Używaj funkcji zdalnych BigQuery do zadawania pytań usłudze Vertex AI Visual Question Answering (VQA) w zapytaniu SQL

1. Wprowadzenie

Przegląd

Funkcje zdalne BigQuery umożliwiają implementowanie funkcji w językach innych niż SQL i JavaScript lub z bibliotekami i usługami niedozwolonymi w funkcjach zdefiniowanych przez użytkownika BigQuery. Funkcje zdalne BigQuery zapewniają bezpośrednią integrację z funkcjami Cloud Run i Cloud Run. Funkcję zdalną BigQuery możesz wywołać w zapytaniu SQL, podając co najmniej jedną kolumnę jako dane wejściowe, a następnie zwracając pojedynczą wartość jako dane wyjściowe.

Funkcje Cloud Run to wymagające niewielu zasobów rozwiązanie do przetwarzania danych, które umożliwia programistom tworzenie samodzielnych funkcji o ściśle zdefiniowanym przeznaczeniu, które można wywoływać za pomocą protokołu HTTPS lub które reagują na CloudEvents bez konieczności zarządzania serwerem lub środowiskiem wykonawczym. Funkcje Cloud Run obsługują Node.js, Python, Go, Java, .NET, Ruby i PHP.

Z tego ćwiczenia w Codelabs dowiesz się, jak utworzyć funkcję zdalną BigQuery, aby uzyskiwać odpowiedzi na pytania dotyczące obrazów przechowywanych w Cloud Storage za pomocą usługi generowania wizualnych odpowiedzi na pytania (VQA) w Vertex AI. Zapytanie SQL pobierze z tabeli w BigQuery adres URI obrazu. Następnie za pomocą funkcji zdalnej BigQuery wyślesz URI obrazu do funkcji Cloud Run, która zwróci odpowiedzi z VQA dotyczące obrazu.

Ilustracja

5832020184ccf2b2.png

Z perspektywy programisty w tym ćwiczeniu wykonasz te czynności:

  1. Tworzenie punktu końcowego HTTP w funkcjach Cloud Run
  2. Utwórz połączenie typu CLOUD_RESOURCE
  3. Tworzenie tabeli obiektów BigQuery dla zasobnika Cloud Storage
  4. Tworzenie funkcji zdalnej
  5. Używaj funkcji zdalnej w zapytaniu tak samo jak innych funkcji zdefiniowanych przez użytkownika.

Czego się nauczysz

2. Konfiguracja i wymagania

Wymagania wstępne

Aktywowanie Cloud Shell

  1. W konsoli Cloud kliknij Aktywuj Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

Jeśli uruchamiasz Cloud Shell po raz pierwszy, zobaczysz ekran pośredni z opisem tego środowiska. Jeśli pojawił się ekran pośredni, kliknij Dalej.

d95252b003979716.png

Uzyskanie dostępu do środowiska Cloud Shell i połączenie się z nim powinno zająć tylko kilka chwil.

7833d5e1c5d18f54.png

Ta maszyna wirtualna zawiera wszystkie potrzebne narzędzia dla programistów. Zawiera również stały katalog domowy o pojemności 5 GB i działa w Google Cloud, co znacznie zwiększa wydajność sieci i usprawnia proces uwierzytelniania. Większość zadań w tym ćwiczeniu, a być może wszystkie, możesz wykonać w przeglądarce.

Po połączeniu z Cloud Shell zobaczysz, że uwierzytelnianie zostało już przeprowadzone, a projekt jest już ustawiony na Twój identyfikator projektu.

  1. Aby potwierdzić, że uwierzytelnianie zostało przeprowadzone, uruchom w Cloud Shell to polecenie:
gcloud auth list

Wynik polecenia

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Aby potwierdzić, że polecenie gcloud zna Twój projekt, uruchom w Cloud Shell to polecenie:
gcloud config list project

Wynik polecenia

[core]
project = <PROJECT_ID>

Jeśli nie, możesz go ustawić za pomocą tego polecenia:

gcloud config set project <PROJECT_ID>

Wynik polecenia

Updated property [core/project].

3. Konfigurowanie lokalnych zmiennych środowiskowych

W tym kodzie utworzysz kilka zmiennych środowiskowych, aby zwiększyć czytelność poleceń gcloud używanych w tym ćwiczeniu.

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. Tworzenie funkcji Cloud Run

Aby utworzyć funkcję zdalną BigQuery, musisz najpierw utworzyć punkt końcowy HTTP za pomocą funkcji Cloud Run. Punkt końcowy musi być w stanie przetworzyć partię wierszy w ramach jednego żądania HTTP POST i zwrócić wyniki dla tej partii jako odpowiedź HTTP.

Ta funkcja Cloud Run otrzyma z zapytania SQL adres URI pamięci obrazów i prompta z pytaniem jako dane wejściowe, a następnie zwróci odpowiedź z usługi generowania wizualnych odpowiedzi na pytania (VQA).

W tym ćwiczeniu używamy przykładu środowiska wykonawczego python311 z pakietem Vertex AI SDK for Python.

Tworzenie kodu źródłowego funkcji

Najpierw utwórz katalog i przejdź do niego.

mkdir imagen-vqa && cd $_

Następnie utwórz plik requirements.txt.

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

Następnie utwórz plik źródłowy 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

Wdrażanie funkcji Cloud Run

Teraz możesz wdrożyć funkcję Cloud Run dla środowiska wykonawczego python311.

Aby wdrożyć funkcję Cloud Run bezpośrednio w Cloud Run, uruchom to polecenie:

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

Jeśli wolisz wdrożyć funkcję jako Cloud Functions 2 generacji, użyj tego polecenia:

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

Następnie możesz zapisać adres URL funkcji jako zmienną środowiskową, aby użyć jej później.

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

5. Tworzenie zasobnika Cloud Storage

Najpierw utwórz zasobnik Cloud Storage, w którym będziesz przechowywać obrazy.

gcloud storage buckets create gs://$BUCKET_NAME

Następnie prześlij obraz, który ma być użyty w VQA. W tym ćwiczeniu używamy przykładowego obrazu z dokumentacji VQA.

Możesz użyć konsoli Cloud Storage, aby przesłać obraz bezpośrednio do zasobnika. Możesz też uruchomić te polecenia, aby pobrać przykładowy obraz do bieżącego katalogu Cloud Shell.

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

a następnie przesłać do zasobnika Cloud Storage.

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

6. Tworzenie połączenia z zasobem Cloud BigQuery

BigQuery używa połączenia CLOUD_RESOURCE do interakcji z funkcją Cloud Function. Aby utworzyć to połączenie, uruchom to polecenie.

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

Następnie wyświetl szczegóły nowego połączenia BigQuery.

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

Zapisz nazwę konta usługi połączenia BigQuery w zmiennej, jak pokazano poniżej.

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

Przyznaj kontu usługi dostęp do zasobnika Cloud Storage.

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

7. Tworzenie tabeli obiektów BigQuery

Tabele obiektów BigQuery to tabele tylko do odczytu zawierające nieuporządkowane obiekty danych znajdujące się w Cloud Storage.

Tabele obiektów umożliwiają analizowanie nieustrukturyzowanych danych w Cloud Storage. Możesz przeprowadzać analizy za pomocą funkcji zdalnych, a następnie łączyć wyniki tych operacji z pozostałymi danymi strukturalnymi w BigQuery.

Najpierw utwórz zbiór danych.

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

To polecenie tworzy tabelę obiektów na podstawie zasobnika obrazów Cloud Storage. Wynikowa tabela będzie zawierać identyfikatory URI wszystkich obrazów w tym zasobniku.

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

8. Tworzenie funkcji zdalnej BigQuery

Ostatnim krokiem jest skonfigurowanie funkcji zdalnej BigQuery.

Najpierw przyznaj kontu usługi połączenia z BigQuery uprawnienia do wywoływania funkcji Cloud Run. Nie zalecamy zezwalania na nieuwierzytelnione wywołania usługi funkcji Cloud Run.

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

Następnie zapisz zapytanie SQL w zmiennej.

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

Teraz uruchom zapytanie.

bq query --nouse_legacy_sql $SQL_CREATE_FUNCTION

Po uruchomieniu zapytania w celu utworzenia funkcji zdalnej zobaczysz Created <your-project-id>.remote_function_codelab.vqa

9. Wywoływanie funkcji zdalnej BigQuery w zapytaniu SQL

Ukończono już wszystkie kroki tworzenia funkcji zdalnej. Możesz teraz wywoływać funkcję Cloud Run z poziomu zapytania SQL.

Najpierw zapisz pytanie i zapytanie SQL w zmiennej. W tym ćwiczeniu wykorzystujemy przykład z dokumentacji dotyczącej generowania wizualnych odpowiedzi na pytania. To zapytanie używa najnowszego obrazu dodanego do zasobnika pamięci masowej.

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

Następnie uruchom zapytanie SQL, aby wyświetlić odpowiedź z usługi generowania wizualnych odpowiedzi na pytania (VQA) w Vertex AI.

bq query --nouse_legacy_sql $SQL_QUERY

Wyniki powinny wyglądać podobnie do tych poniżej:

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

10. Rozwiązywanie problemów

Jeśli podczas tworzenia tabeli BigQuery pojawi się błąd BigQuery error in mk operation: Source URI must be a Google Cloud Storage location: gs://$BUCKET_NAME, upewnij się, że po znaku $BUCKET_NAME w poleceniu znajduje się ścieżka /*.

Jeśli podczas uruchamiania zapytania SQL pojawi się błąd Access Denied: BigQuery BigQuery: Received response code 403 from endpoint <your-function-endpoint>, przed ponowną próbą odczekaj około 1–2 minut, aż uprawnienia roli Wywołujący funkcję w Cloud Functions zostaną przeniesione na konto usługi połączenia BigQuery.

11. Gratulacje!

Gratulujemy ukończenia ćwiczenia!

Zalecamy zapoznanie się z dokumentacją dotyczącą funkcji zdalnych BigQuerygenerowania wizualnych odpowiedzi na pytania (VQA).

Omówione zagadnienia

  • Jak skonfigurować uwierzytelnianie w funkcji Cloud Run i sprawdzić, czy zostało ono prawidłowo skonfigurowane
  • Wywoływanie uwierzytelnionej funkcji z lokalnego środowiska programistycznego przez podanie tokena tożsamości gcloud
  • Jak utworzyć konto usługi i przypisać mu odpowiednią rolę do wywoływania funkcji
  • Jak przyjmować tożsamość usługi w lokalnym środowisku programistycznym, które ma odpowiednie role do wywoływania funkcji

12. Czyszczenie danych

Aby uniknąć przypadkowych opłat (np. jeśli ta funkcja Cloud Run zostanie przypadkowo wywołana więcej razy niż miesięczny limit wywołań funkcji Cloud Run w warstwie bezpłatnej), możesz usunąć funkcję Cloud Function lub projekt utworzony w kroku 2.

Aby usunąć funkcję Cloud Run, otwórz konsolę Cloud Run pod adresem https://console.cloud.google.com/functions/ i usuń funkcję imagen-vqa (lub $FUNCTION_NAME, jeśli używasz innej nazwy).

Jeśli zdecydujesz się usunąć cały projekt, otwórz stronę https://console.cloud.google.com/cloud-resource-manager, wybierz projekt utworzony w kroku 2 i kliknij Usuń. Jeśli usuniesz projekt, musisz zmienić projekty w Cloud SDK. Listę wszystkich dostępnych projektów możesz wyświetlić, uruchamiając polecenie gcloud projects list.