BigQuery 원격 함수를 사용하여 SQL 쿼리에서 Vertex AI VQA (시각적 질의 응답)에 질문하기

1. 소개

개요

BigQuery 원격 함수를 사용하면 SQL 및 JavaScript 이외의 언어나 BigQuery 사용자 정의 함수에서 허용되지 않는 라이브러리 및 서비스로 함수를 구현할 수 있습니다. BigQuery 원격 함수는 Cloud Run 함수Cloud Run과의 직접 통합을 제공합니다. 하나 이상의 열을 입력으로 취한 후 단일 값을 출력으로 반환하여 SQL 쿼리 내에서 BigQuery 원격 함수를 호출할 수 있습니다.

Cloud Run 함수는 개발자가 서버 또는 런타임 환경을 관리할 필요 없이 HTTPS를 사용하여 트리거하거나 CloudEvents에 응답할 수 있는 단일 목적의 독립형 함수를 만들 수 있는 경량형 컴퓨팅 솔루션입니다. Cloud Run 함수는 Node.js, Python, Go, Java, .NET, Ruby, PHP를 지원합니다.

이 Codelab에서는 Vertex AI 시각적 질의 응답 (VQA)을 사용하여 Cloud Storage에 저장된 이미지에 관한 질문에 대한 답변을 가져오는 BigQuery 원격 함수를 만드는 방법을 알아봅니다. SQL 쿼리는 BigQuery의 테이블에서 이미지의 URI를 가져옵니다. 그런 다음 BigQuery 원격 함수를 사용하여 이미지 URI를 Cloud Run 함수로 전송합니다. 이 함수는 이미지에 관한 VQA의 답변으로 응답합니다.

이미지

5832020184ccf2b2.png

개발 관점에서 이 Codelab에서 완료할 단계는 다음과 같습니다.

  1. Cloud Run 함수에서 HTTP 엔드포인트 만들기
  2. CLOUD_RESOURCE 유형의 연결 만들기
  3. Cloud Storage 버킷의 BigQuery 객체 테이블 만들기
  4. 원격 함수 만들기
  5. 다른 사용자 정의 함수와 마찬가지로 쿼리에서 원격 함수 사용

학습할 내용

  • Python으로 HTTP Cloud Run 함수를 만드는 방법
  • SQL 쿼리 내에서 BigQuery 원격 함수를 만들고 사용하는 방법
  • BigQuery 객체 테이블을 만드는 방법
  • Python용 Vertex AI SDK를 사용하여 시각적 질의 응답 (VQA)을 사용하는 방법

2. 설정 및 요구사항

기본 요건

Cloud Shell 활성화

  1. Cloud Console에서 Cloud Shell 활성화d1264ca30785e435.png를 클릭합니다.

cb81e7c8e34bc8d.png

Cloud Shell을 처음 시작하는 경우 Cloud Shell에 대한 설명이 포함된 중간 화면이 표시됩니다. 중간 화면이 표시되면 계속을 클릭합니다.

d95252b003979716.png

Cloud Shell을 프로비저닝하고 연결하는 데 몇 분 정도만 걸립니다.

7833d5e1c5d18f54.png

가상 머신에는 필요한 개발 도구가 모두 들어 있습니다. 영구적인 5GB 홈 디렉터리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 이 Codelab에서 대부분의 작업은 브라우저만으로도 수행할 수 있습니다.

Cloud Shell에 연결되면 인증이 완료되었고 프로젝트가 해당 프로젝트 ID로 설정된 것을 확인할 수 있습니다.

  1. Cloud Shell에서 다음 명령어를 실행하여 인증되었는지 확인합니다.
gcloud auth list

명령어 결과

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

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. Cloud Shell에서 다음 명령어를 실행하여 gcloud 명령어가 프로젝트를 알고 있는지 확인합니다.
gcloud config list project

명령어 결과

[core]
project = <PROJECT_ID>

또는 다음 명령어로 설정할 수 있습니다.

gcloud config set project <PROJECT_ID>

명령어 결과

Updated property [core/project].

3. 로컬 환경 변수 설정

이 코드에서는 이 Codelab에서 사용되는 gcloud 명령어의 가독성을 개선하기 위해 몇 가지 환경 변수를 만듭니다.

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. Cloud Run 함수 만들기

BigQuery 원격 함수를 만들려면 먼저 Cloud Run 함수를 사용하여 HTTP 엔드포인트를 만들어야 합니다. 엔드포인트는 단일 HTTP POST 요청에서 행 배치를 처리하고 배치 결과를 HTTP 응답으로 반환할 수 있어야 합니다.

이 Cloud Run 함수는 이미지 스토리지 URI와 질문 프롬프트를 SQL 쿼리의 입력으로 수신하고 VQA (시각적 질의 응답)에서 답변을 반환합니다.

이 Codelab에서는 Python용 Vertex AI SDK를 사용하는 python311 런타임의 예시를 사용합니다.

함수의 소스 코드 만들기

먼저 디렉터리를 만들고 해당 디렉터리로 이동합니다.

mkdir imagen-vqa && cd $_

그런 다음 requirements.txt 파일을 만듭니다.

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

다음으로 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

Cloud Run 함수 배포

이제 python311 런타임용 Cloud Run 함수를 배포할 수 있습니다.

Cloud Run 함수를 Cloud Run에 직접 배포하려면 다음 명령어를 실행합니다.

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

Cloud Functions 2세대로 배포하려면 다음 명령어를 사용하세요.

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

그런 다음 함수 URL을 환경 변수로 저장하여 나중에 사용할 수 있습니다.

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

5. Cloud Storage 버킷 만들기

먼저 이미지를 저장할 Cloud Storage 버킷을 만듭니다.

gcloud storage buckets create gs://$BUCKET_NAME

다음으로 VQA에서 사용할 이미지를 업로드합니다. 이 Codelab에서는 VQA 문서예시 이미지를 사용합니다.

Cloud Storage용 Cloud 콘솔을 사용하여 이미지를 버킷에 직접 업로드할 수 있습니다. 또는 다음 명령어를 실행하여 예시 이미지를 현재 Cloud Shell 디렉터리에 다운로드할 수 있습니다.

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

그런 다음 Cloud Storage 버킷에 업로드합니다.

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

6. BigQuery 클라우드 리소스 연결 만들기

BigQuery는 CLOUD_RESOURCE 연결을 사용하여 Cloud 함수와 상호작용합니다. 다음 명령어를 실행하여 이 연결을 만듭니다.

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

다음으로 새 BigQuery 연결의 세부정보를 표시합니다.

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

표시된 대로 BigQuery 연결 서비스 계정의 이름을 변수에 저장합니다.

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

Cloud Storage 버킷에 액세스할 수 있도록 서비스 계정에 액세스 권한을 부여합니다.

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

7. BigQuery 객체 테이블 만들기

BigQuery 객체 테이블은 Cloud Storage에 있는 비정형 데이터 객체에 대한 읽기 전용 테이블입니다.

객체 테이블을 사용하면 Cloud Storage에서 구조화되지 않은 데이터를 분석할 수 있습니다. 원격 함수로 분석을 수행한 다음 이러한 작업 결과를 BigQuery의 나머지 구조화된 데이터와 조인할 수 있습니다.

먼저 데이터 세트를 만듭니다.

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

다음 명령어는 Cloud Storage 이미지 버킷을 기반으로 객체 테이블을 만듭니다. 결과 테이블에는 해당 버킷의 모든 이미지에 대한 URI가 포함됩니다.

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

8. BigQuery 원격 함수 만들기

이제 마지막 단계로 BigQuery 원격 함수를 구성합니다.

먼저 BigQuery 연결 서비스 계정에 Cloud Run 함수를 호출할 수 있는 권한을 부여합니다. Cloud Run 함수 서비스에 인증되지 않은 호출을 허용하지 않는 것이 좋습니다.

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

그런 다음 SQL 쿼리를 변수에 저장합니다.

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

이제 쿼리를 실행합니다.

bq query --nouse_legacy_sql $SQL_CREATE_FUNCTION

쿼리를 실행하여 원격 함수를 만든 후 Created <your-project-id>.remote_function_codelab.vqa가 표시됩니다.

9. SQL 쿼리에서 BigQuery 원격 함수 호출

이제 원격 함수를 생성하기 위한 개발 단계를 완료했습니다. 이제 SQL 쿼리 내에서 Cloud Run 함수를 호출할 수 있습니다.

먼저 질문과 SQL 쿼리를 변수에 저장합니다. 이 Codelab에서는 시각적 질문 답변 문서의 를 사용합니다. 이 쿼리는 저장소 버킷에 추가된 최신 이미지를 사용합니다.

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

그런 다음 SQL 쿼리를 실행하여 Vertex AI VQA (시각적 질의 응답) 서비스의 응답을 표시합니다.

bq query --nouse_legacy_sql $SQL_QUERY

결과는 아래 출력 예와 유사합니다.

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

10. 문제 해결

BigQuery 테이블을 만들 때 BigQuery error in mk operation: Source URI must be a Google Cloud Storage location: gs://$BUCKET_NAME 오류가 발생하면 명령어에서 $BUCKET_NAME 뒤에 /* 경로를 포함했는지 확인합니다.

SQL 쿼리를 실행할 때 Access Denied: BigQuery BigQuery: Received response code 403 from endpoint <your-function-endpoint> 오류가 발생하면 Cloud 함수 호출자 역할 권한 부여가 BigQuery 연결 서비스 계정에 적용될 때까지 약 1~2분 정도 기다린 후 다시 시도해 보세요.

11. 축하합니다.

Codelab을 완료했습니다. 축하합니다.

BigQuery 원격 함수시각적 질의 응답 (VQA)에 대한 문서를 검토하는 것이 좋습니다.

학습한 내용

  • Cloud Run 함수에서 인증을 구성하고 인증이 올바르게 구성되었는지 확인하는 방법
  • gcloud ID의 토큰을 제공하여 로컬 개발 환경에서 인증된 함수 호출
  • 서비스 계정을 만들고 함수를 호출하는 적절한 역할을 부여하는 방법
  • 함수 호출에 적절한 역할이 있는 로컬 개발 환경에서 서비스를 가장하는 방법

12. 삭제

의도치 않은 청구를 방지하려면(예: 이 Cloud Run 함수가 무료 등급의 월별 Cloud Run 함수 호출 할당량보다 더 많은 횟수로 실수로 호출된 경우) Cloud 함수를 삭제하거나 2단계에서 만든 프로젝트를 삭제하면 됩니다.

Cloud Run 함수를 삭제하려면 Cloud Run Cloud 콘솔(https://console.cloud.google.com/functions/)으로 이동하여 imagen-vqa 함수(또는 다른 이름을 사용한 경우 $FUNCTION_NAME)를 삭제합니다.

전체 프로젝트를 삭제하려면 https://console.cloud.google.com/cloud-resource-manager로 이동하여 2단계에서 만든 프로젝트를 선택하고 삭제를 선택합니다. 프로젝트를 삭제하면 Cloud SDK에서 프로젝트를 변경해야 합니다. gcloud projects list를 실행하면 사용 가능한 모든 프로젝트의 목록을 볼 수 있습니다.