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

מבחינת הפיתוח, אלה השלבים שתבצעו בסדנת הקוד הזו:

  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. יצירת חיבור של משאב Cloud ב-BigQuery

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

אם מוצגת השגיאה Access Denied: BigQuery BigQuery: Received response code 403 from endpoint <your-function-endpoint> כשמריצים את שאילתה ה-SQL, כדאי להמתין כ-1-2 דקות עד שההרשאה של תפקיד Cloud Function Invoker תופץ לחשבון השירות של החיבור ל-BigQuery, ואז לנסות שוב.

11. מעולה!

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

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

אילו נושאים דיברנו?

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

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

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

כדי למחוק את הפונקציה של Cloud Run, נכנסים למסוף Cloud של Cloud Run בכתובת 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.