שימוש בפונקציות מרחוק של BigQuery כדי לשלוח שאלות ל-Vertex AI Visual Question Answering (VQA) בשאילתת SQL

1. מבוא

סקירה כללית

פונקציות מרוחקות של BigQuery מאפשרות להטמיע פונקציה בשפות שאינן SQL ו-JavaScript, או עם הספריות והשירותים שאסורים בפונקציות מוגדרות המשתמש של BigQuery. פונקציות BigQuery מרוחקות מספקות שילוב ישיר עם פונקציות Cloud Run ועם Cloud Run. כדי להפעיל פונקציה מרוחקת של BigQuery בתוך שאילתה של SQL, צריך להשתמש בעמודה אחת או יותר כקלט ולאחר מכן להחזיר ערך יחיד כפלט.

פונקציות של Cloud Run הן פתרון מחשוב קל שמאפשר למפתחים ליצור פונקציות עצמאיות למטרה יחידה, שאפשר להפעיל באמצעות HTTPS או להגיב ל-CloudEvents בלי לנהל שרת או סביבת זמן ריצה. פונקציות Cloud Run תומכות ב-Node.js, ב-Python, ב-Go, ב-Java, ב-‎.NET, ב-Ruby וב-PHP.

בקודלאב הזה תלמדו איך ליצור פונקציה מרוחקת ב-BigQuery כדי לקבל תשובות לשאלה לגבי תמונות שמאוחסנות ב-Cloud Storage באמצעות Visual Question Answering‏ (VQA) של Vertex AI. שאילתת ה-SQL תאחזר מזהה URI של תמונה מטבלה ב-BigQuery. לאחר מכן, באמצעות הפונקציה המרוחקת של BigQuery, תשלחו את ה-URI של התמונה לפונקציה של Cloud Run שתחזיר תשובות מ-VQA לגבי התמונה.

איור

5832020184ccf2b2.png

מבחינת פיתוח, השלבים הבאים שתבצעו ב-Codelab הזה:

  1. יצירת נקודת הקצה מסוג HTTP בפונקציות של Cloud Run
  2. יצירת חיבור מסוג CLOUD_RESOURCE
  3. יצירת טבלת אובייקטים ב-BigQuery לקטגוריה של Cloud Storage
  4. יצירת הפונקציה מרחוק
  5. משתמשים בפונקציה מרחוק בשאילתה כמו בכל פונקציה אחרת בהגדרת המשתמש

מה תלמדו

  • איך יוצרים פונקציית HTTP ב-Cloud Run ב-Python
  • איך יוצרים פונקציה מרוחקת ב-BigQuery ומשתמשים בה בתוך שאילתת SQL
  • איך יוצרים טבלת אובייקטים ב-BigQuery
  • איך משתמשים ב-Vertex AI SDK ל-Python כדי להשתמש ב-Visual Question Answering‏ (VQA)

2. הגדרה ודרישות

דרישות מוקדמות

הפעלת Cloud Shell

  1. במסוף Cloud, לוחצים על Activate Cloud Shell d1264ca30785e435.png.

cb81e7c8e34bc8d.png

אם זו הפעם הראשונה שאתם מפעילים את Cloud Shell, יוצג מסך ביניים עם תיאור של השירות. אם יוצג מסך ביניים, לוחצים על Continue (המשך).

d95252b003979716.png

תהליך ההקצאה וההתחברות ל-Cloud Shell אמור להימשך רק כמה רגעים.

7833d5e1c5d18f54.png

המכונה הווירטואלית הזו כוללת את כל הכלים הנדרשים לפיתוח. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, משפרת מאוד את הביצועים והאימות של הרשת. אפשר לבצע את רוב העבודה ב-codelab הזה, אם לא את כולה, באמצעות דפדפן.

אחרי ההתחברות ל-Cloud Shell, אתם אמורים לראות שהפרויקט מאומת ושהפרויקט מוגדר לפי מזהה הפרויקט שלכם.

  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. הגדרת משתני סביבה מקומיים

בקוד הזה תיצורו כמה משתני סביבה כדי לשפר את הקריאוּת של הפקודות gcloud שבהן נעשה שימוש ב-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. יצירת הפונקציה ב-Cloud Run

כדי ליצור פונקציה מרוחקת ב-BigQuery, קודם צריך ליצור נקודת קצה מסוג HTTP באמצעות פונקציית Cloud Run. נקודת הקצה חייבת להיות מסוגלת לעבד קבוצה של שורות בבקשת HTTP POST יחידה ולהחזיר את התוצאות של האצווה כתגובת HTTP.

הפונקציה הזו ב-Cloud Run תקבל את ה-URI של אחסון התמונה ואת הנחיית השאלה כקלט משאילתת ה-SQL, ותחזיר את התשובה מ-Visual Question Answering‏ (VQA).

בשיעור ה-Codelab הזה נעשה שימוש בדוגמה לסביבת זמן ריצה של python311 באמצעות Vertex AI SDK ל-Python.

יצירת קוד המקור של הפונקציה

קודם יוצרים ספרייה ומעבירים את נתיב העבודה (cd) לספרייה הזו.

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

עכשיו אפשר לפרוס את הפונקציה של Cloud Run בסביבת זמן הריצה python311.

כדי לפרוס פונקציה של Cloud Run ישירות ב-Cloud Run, מריצים את הפקודה הבאה:

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

אם אתם מעדיפים לפרוס את Cloud Functions דור שני, תוכלו להשתמש בפקודה הבאה:

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. בקודלאב הזה נעשה שימוש בתמונה לדוגמה ממסמכי התיעוד של VQA.

אתם יכולים להעלות את התמונה ישירות לקטגוריה שלכם באמצעות מסוף Cloud Storage ב-Cloud Storage. לחלופין, אפשר להריץ את הפקודות הבאות כדי להוריד את קובץ האימג' לדוגמה לספרייה הנוכחית ב-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 Cloud Resource

BigQuery משתמש בחיבור CLOUD_RESOURCE כדי לקיים אינטראקציה עם Cloud Function. מריצים את הפקודה הבאה כדי ליצור את החיבור הזה.

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. קריאה לפונקציה המרוחקת של BigQuery בשאילתת SQL

סיימתם את שלבי הפיתוח ליצירת הפונקציה מרחוק. עכשיו אפשר להפעיל את הפונקציה של Cloud Run מתוך שאילתת SQL.

קודם כול, שומרים את השאלה ואת שאילתת ה-SQL במשתנה. בקודלאב הזה נעשה שימוש בדוגמה מהמסמכי העזרה בנושא מענה על שאלות חזותיות. השאילתה הזו משתמשת בתמונה האחרונה שנוספה לקטגוריית האחסון.

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 כדי להציג את התשובה משירות ה-VQA (Visual Question Answering) של Vertex AI.

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>, צריך להמתין כ-1-2 דקות עד שהרשאת התפקיד של Cloud Functions Invoker תתעדכן בחשבון השירות של החיבור ל-BigQuery, לפני הניסיון הבא.

11. מעולה!

כל הכבוד על השלמת ה-Codelab!

מומלץ לעיין במסמכי העזרה בנושא פונקציות מרוחקות של BigQuery ומענה על שאלות חזותיות (VQA).

מה עסקנו בו

  • איך להגדיר אימות בפונקציית Cloud Run ולוודא שהאימות הוגדר כראוי
  • הפעלת פונקציה מאומתת מסביבת פיתוח מקומית באמצעות מתן האסימון לזהות שלכם ב-gcloud
  • איך יוצרים חשבון שירות ומעניקים לו את התפקיד המתאים להפעלת פונקציה
  • איך מתחזים לשירות מסביבת פיתוח מקומית שיש לה את התפקידים המתאימים להפעלת פונקציה

12. הסרת המשאבים

כדי להימנע מחיובים לא מכוונים (לדוגמה, אם הפונקציה של Cloud Run הופעלה בטעות יותר פעמים מההקצאה החודשית של הפונקציה של Cloud Run בתוכנית ללא תשלום), אפשר למחוק את הפונקציה של Cloud Functions או למחוק את הפרויקט שיצרתם בשלב 2.

כדי למחוק את הפונקציה Cloud Run, נכנסים אל Cloud Run Cloud Console בכתובת https://console.cloud.google.com/functions/ ומוחקים את הפונקציה imagen-vqa (או את הפונקציה $FUNCTION_NAME אם השתמשתם בשם אחר).

אם בוחרים למחוק את הפרויקט כולו, אפשר לעבור אל https://console.cloud.google.com/cloud-resource-manager, לבחור את הפרויקט שיצרתם בשלב 2 ולבחור באפשרות Delete (מחיקה). אם תמחקו את הפרויקט, תצטרכו לשנות את הפרויקטים ב-Cloud SDK. כדי להציג את רשימת כל הפרויקטים הזמינים, מריצים את הפקודה gcloud projects list.