Vertex AI: מודלים של מארחים נוספים באותה מכונה וירטואלית עבור חיזויים

1. סקירה כללית

בשיעור ה-Lab הזה תשתמשו בתכונה של מודל אירוח משותף ב-Vertex AI כדי לארח כמה מודלים באותה VM לצורך חיזוי אונליין.

מה לומדים

נסביר לכם איך:

  • צור DeploymentResourcePool
  • פריסת מודלים בתוך DeploymentResourcePool

העלות הכוללת של הפעלת שיעור ה-Lab הזה ב-Google Cloud היא כ-$2.

2. מבוא ל-Vertex AI

בשיעור ה-Lab הזה נעשה שימוש במוצר ה-AI החדש ביותר שזמין ב-Google Cloud. Vertex AI משלב את הצעות למידת המכונה ב-Google Cloud ליצירת חוויית פיתוח חלקה. בעבר, ניתן היה לגשת למודלים שעברו אימון באמצעות AutoML ומודלים בהתאמה אישית דרך שירותים נפרדים. המוצר החדש משלב את כל ממשקי ה-API האלה בממשק API אחד, לצד מוצרים חדשים אחרים. תוכלו גם להעביר פרויקטים קיימים ל-Vertex AI. יש לך משוב? אפשר למצוא אותו בדף התמיכה.

Vertex AI כולל מוצרים רבים ושונים לתמיכה בתהליכי עבודה של למידת מכונה מקצה לקצה. שיעור ה-Lab הזה יתמקד במוצרים שמודגשים בהמשך: Predictions ו-Workbench

סקירה כללית של המוצר Vertex

3. סקירה כללית של התרחיש לדוגמה

כשפורסים מודלים בשירות החיזוי של Vertex AI, כל מודל נפרס כברירת מחדל במכונה וירטואלית משלו. כדי לייעל את האירוח, יש כמה מודלים שאפשר לארח באותה מכונה וירטואלית. כתוצאה מכך, תוכלו להשתמש טוב יותר בזיכרון ובמשאבי החישוב. מספר המודלים שתבחרו לפרוס באותה מכונה וירטואלית תלוי בגודל של המודלים ובדפוסי התנועה, אבל התכונה הזו שימושית במיוחד בתרחישים שבהם יש לכם הרבה מודלים פרוסים עם מעט תעבורת נתונים.

תמיכה במודל אירוח משותף מציגה את הקונספט Deployment Resource Pool, שמקבץ מודלים כדי לשתף משאבים במכונה וירטואלית. המודלים יכולים לשתף VM אם הם חולקים נקודת קצה (endpoint) וגם אם היא נפרסת בנקודות קצה שונות. נכון לעכשיו, למודלים באותו מאגר משאבים צריכה להיות אותה קובץ אימג' של קונטיינר, כולל גרסת framework של קונטיינרים שנוצרו מראש ב-Vertex Prediction. בנוסף, בגרסה הזו יש תמיכה רק בקונטיינרים שנוצרו מראש ב-Vertex Prediction עם framework של מודל Tensorflow. עדיין אין תמיכה ב-frameworks אחרות של מודלים וקונטיינרים מותאמים אישית.

deployment_pool

4. הגדרת הסביבה

כדי להריץ את ה-Codelab הזה צריך פרויקט ב-Google Cloud Platform שהחיוב מופעל בו. כדי ליצור פרויקט, יש לפעול לפי ההוראות האלה.

שלב 1: מפעילים את ממשק ה-API של Compute Engine

עוברים אל Compute Engine ובוחרים באפשרות Enable (הפעלה) אם היא לא מופעלת עדיין.

שלב 2: מפעילים את Vertex AI API

עוברים לקטע Vertex AI במסוף Cloud ולוחצים על Enable Vertex AI API.

מרכז הבקרה של Vertex AI

שלב 3: יצירת מכונה של Vertex AI Workbench

בקטע Vertex AI במסוף Cloud, לוחצים על Workbench:

תפריט Vertex AI

מפעילים את Notebooks API, אם עדיין לא פועלים.

Notebook_api

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

Notebooks_UI

לאחר מכן בוחרים פנקס רשימות חדש.

new_notebook

נותנים שם ל-notebook, ובקטע הרשאה בוחרים באפשרות חשבון שירות.

create_notebook

בוחרים באפשרות הגדרות מתקדמות.

בקטע אבטחה, בוחרים באפשרות 'הפעלת הטרמינל'. אם היא לא מופעלת עדיין.

enable_terminal

אפשר להשאיר את כל שאר ההגדרות המתקדמות כפי שהן.

לאחר מכן, לוחצים על יצירה. הקצאה של המכונה תימשך כמה דקות.

אחרי שיוצרים את המכונה, בוחרים באפשרות Open JUPYTERLAB.

open_jupyterlab

5. דגם של רכבת

כדי לנסות את תכונת האירוח הנוסף, קודם אנחנו צריכים לאמן מודל ולאחסן את הארטיפקטים של המודל שנשמרו בקטגוריה של Cloud Storage. כדי להפעיל את משימת האימון, נשתמש במנהל ה-notebook ב-Workbench.

שלב 1: יצירת קטגוריה של Cloud Storage

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

launcher_terminal

מהטרמינל, מריצים את הפקודה הבאה כדי להגדיר משתנה env לפרויקט ומקפידים להחליף את your-cloud-project במזהה הפרויקט:

PROJECT_ID='your-cloud-project'

לאחר מכן, מריצים את הפקודה הבאה כדי ליצור קטגוריה חדשה בפרויקט.

BUCKET="gs://${PROJECT_ID}-bucket"
gsutil mb -l us-central1 $BUCKET

שלב 2: הפעלת ה-notebook

במרכז האפליקציות של המכונה של Workbench, פותחים notebook חדש של TensorFlow 2.

launcher_tf2

הקוד שבהמשך אימון מסווג סנטימנטים בינאריים (חיובי או שלילי) במערך הנתונים של ביקורות על סרטים מ-IMDB. מדביקים את הקוד ב-notebook.

חשוב להחליף את {YOUR_BUCKET} בקטגוריה שיצרתם בשלב הקודם (או בקטגוריה אחרת בפרויקט). כאן נאחסן את פריטי המידע השמורים של המודל שנשמר, ונצטרך מאוחר יותר כשתעלו את המודל אל מרשם המודלים של Vertex AI.

import numpy as np

import tensorflow_datasets as tfds
import tensorflow as tf

# REPLACE WITH YOUR BUCKET!
OUTPUT_PATH='gs://{YOUR_BUCKET}/model_output'

BUFFER_SIZE = 10000
BATCH_SIZE = 64
VOCAB_SIZE = 1000

# Load data
dataset, info = tfds.load('imdb_reviews', with_info=True,
                          as_supervised=True)
train_dataset, test_dataset = dataset['train'], dataset['test']

train_dataset = train_dataset.shuffle(BUFFER_SIZE).batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)
test_dataset = test_dataset.batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)

# Create text encoder
encoder = tf.keras.layers.TextVectorization(
    max_tokens=VOCAB_SIZE)
encoder.adapt(train_dataset.map(lambda text, label: text))

# Create model
model = tf.keras.Sequential([
    encoder,
    tf.keras.layers.Embedding(
        input_dim=len(encoder.get_vocabulary()),
        output_dim=64,
        # Use masking to handle the variable sequence lengths
        mask_zero=True),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64)),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dense(1)
])

# Compile model
model.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              optimizer=tf.keras.optimizers.Adam(1e-4),
              metrics=['accuracy'])

# Fit model
history = model.fit(train_dataset, epochs=10,
                    validation_data=test_dataset,
                    validation_steps=30)

# Save model
model.save(OUTPUT_PATH)

בשלב הבא לוחצים על הלחצן Execute.

execute_nb

לאחר מכן, הגדירו את הביצוע באופן הבא ולחצו על שליחה

execution_config

בכרטיסייה 'פעולות' במסוף אפשר לעקוב אחרי הסטטוס של משימת האימון.

execution_status

6. פריסת מודל

שלב 1: העלאת המודל

בסיום הביצוע, חוזרים ל-notebook של Workbench כדי להעלות את המודל. יצירת notebook חדש של TensorFlow.

tf_nb

קודם כול, מייבאים את Vertex AI Python SDK

from google.cloud import aiplatform

אחר כך מעלים את המודל, ומחליפים את {YOUR_BUCKET} בקטגוריה שציינתם בקוד האימון.

# replace {YOUR_BUCKET}
model_1 = aiplatform.Model.upload(display_name='text-model-1',
                                  artifact_uri='gs://{YOUR_BUCKET}/model_output',
                                  serving_container_image_uri='us-docker.pkg.dev/vertex-ai/prediction/tf2-cpu.2-8:latest')

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

# replace {YOUR_BUCKET}
model_2 = aiplatform.Model.upload(display_name='text-model-2',
                                  artifact_uri='gs://{YOUR_BUCKET}/model_output',
                                  serving_container_image_uri='us-docker.pkg.dev/vertex-ai/prediction/tf2-cpu.2-8:latest')

עכשיו אתם אמורים לראות במרשם המודלים של Vertex AI את שני המודלים. סטטוס הפריסה ריק כי עדיין לא פרסנו את המודלים.

model_registry

שלב 2: יוצרים נקודת קצה

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

endpoint = aiplatform.Endpoint.create('cohost-endpoint')

כשנקודת הקצה נוצרת, היא תוצג במסוף.

console_endpoint

שלב 3: יוצרים את DeploymentResourcePool

אפשר ליצור את DeploymentResourcePool באמצעות הפקודה הבאה. חשוב להחליף את המזהה {YOUR_PROJECT} במזהה הפרויקט.

# replace {YOUR_PROJECT}
PROJECT_ID={YOUR_PROJECT}
REGION="us-central1"
VERTEX_API_URL=REGION + "-aiplatform.googleapis.com"
VERTEX_PREDICTION_API_URL=REGION + "-prediction-aiplatform.googleapis.com"
MULTI_MODEL_API_VERSION="v1beta1"

# Give the pool a name
DEPLOYMENT_RESOURCE_POOL_ID="my-resource-pool"

import json
import pprint
pp = pprint.PrettyPrinter(indent=4)

CREATE_RP_PAYLOAD = {
  "deployment_resource_pool":{
    "dedicated_resources":{
      "machine_spec":{
        "machine_type":"n1-standard-4"
      },
      "min_replica_count":1,
      "max_replica_count":2
    }
  },
  "deployment_resource_pool_id":DEPLOYMENT_RESOURCE_POOL_ID
}
CREATE_RP_REQUEST=json.dumps(CREATE_RP_PAYLOAD)
pp.pprint("CREATE_RP_REQUEST: " + CREATE_RP_REQUEST)

!curl \
-X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
https://{VERTEX_API_URL}/{MULTI_MODEL_API_VERSION}/projects/{PROJECT_ID}/locations/{REGION}/deploymentResourcePools \
-d '{CREATE_RP_REQUEST}'

כדי לראות את המאגר, צריך להריץ

!curl -X GET \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
https://{VERTEX_API_URL}/{MULTI_MODEL_API_VERSION}/projects/{PROJECT_ID}/locations/{REGION}/deploymentResourcePools/{DEPLOYMENT_RESOURCE_POOL_ID}

שלב 4: פורסים את המודלים בנקודת הקצה

עכשיו, אחרי שמאגר המשאבים נוצר, אנחנו יכולים לפרוס את המודלים בתוך מאגר המשאבים.

קודם נפרוס את model_1. חשוב להחליף את MODEL_1_ID ואת ENDPOINT_ID במזהים המתאימים.

MODEL_1_ID="{MODEL_1_ID}"
ENDPOINT_ID="{ENDPOINT_ID}"

הפקודה הבאה תפרוס את model_1 בנקודת הקצה (endpoint) שמאגר המשאבים.

MODEL_NAME = "projects/{project_id}/locations/{region}/models/{model_id}".format(project_id=PROJECT_ID, region=REGION, model_id=MODEL_1_ID)
SHARED_RESOURCE = "projects/{project_id}/locations/{region}/deploymentResourcePools/{deployment_resource_pool_id}".format(project_id=PROJECT_ID, region=REGION, deployment_resource_pool_id=DEPLOYMENT_RESOURCE_POOL_ID)

DEPLOY_MODEL_PAYLOAD = {
  "deployedModel": {
    "model": MODEL_NAME,
    "shared_resources": SHARED_RESOURCE
  },
  "trafficSplit": {
    "0": 100
  }
}
DEPLOY_MODEL_REQUEST=json.dumps(DEPLOY_MODEL_PAYLOAD)
pp.pprint("DEPLOY_MODEL_REQUEST: " + DEPLOY_MODEL_REQUEST)

!curl -X POST \
 -H "Authorization: Bearer $(gcloud auth print-access-token)" \
 -H "Content-Type: application/json" \
https://{VERTEX_API_URL}/{MULTI_MODEL_API_VERSION}/projects/{PROJECT_ID}/locations/{REGION}/endpoints/{ENDPOINT_ID}:deployModel \
-d '{DEPLOY_MODEL_REQUEST}'

הפעולה תימשך כמה דקות, אבל בסיום תראו את המודל נפרס בנקודת הקצה במסוף.

model_1_endpoint

בשלב הבא אפשר לפרוס את model_2 בתוך אותו מאגר פריסה. נפרוס אותו לאותה נקודת קצה (endpoint) כמו model_1. אבל אפשר גם לפרוס אתmodel_2 בנקודת קצה (endpoint) אחרת באותו מאגר משאבים.

יש לעדכן את MODEL_ID עם המזהה של model_2. שוב, אפשר לקבל את המזהה הזה באמצעות הרצת model_2.name

MODEL_2_ID="{MODEL_2_ID}"

לאחר מכן פורסים את model_2. מכיוון שכבר פרסנו את model_1 בנקודת הקצה, צריך לעדכן את trafficSplit כך שהתנועה תפוצל בין שני המודלים. לא נצטרך לעדכן את השדה trafficSplit אם נחליט לפרוס את model_2 בנקודת קצה אחרת בתוך אותו מאגר משאבים.

כדי לעדכן את חלוקת התנועה, צריך להגדיר מזהה DeployedModel ל-model_1. הערה: המזהה הזה שונה ממזהה המודל.

DEPLOYED_MODEL_1_ID = {DEPLOYED_MODEL_1_ID}

לאחר מכן מבצעים את הפקודה הבאה כדי לפרוס את המודל השני.

MODEL_NAME = "projects/{project_id}/locations/{region}/models/{model_id}".format(project_id=PROJECT_ID, region=REGION, model_id=MODEL_2_ID)
SHARED_RESOURCE = "projects/{project_id}/locations/{region}/deploymentResourcePools/{deployment_resource_pool_id}".format(project_id=PROJECT_ID, region=REGION, deployment_resource_pool_id=DEPLOYMENT_RESOURCE_POOL_ID)

#`trafficSplit` is a map from a DeployedModel's ID to the percentage of this Endpoint's traffic that should be forwarded to that DeployedModel.
# The traffic percentage values for an endpoint must add up to 100.
# The key for the model being deployed is "0".

DEPLOY_MODEL_PAYLOAD = {
  "deployedModel": {
    "model": MODEL_NAME,
    "shared_resources": SHARED_RESOURCE
  },
  "trafficSplit": {
    "0": 50,
    DEPLOYED_MODEL_1_ID: 50
  }
}
DEPLOY_MODEL_REQUEST=json.dumps(DEPLOY_MODEL_PAYLOAD)
pp.pprint("DEPLOY_MODEL_REQUEST: " + DEPLOY_MODEL_REQUEST)

!curl -X POST \
 -H "Authorization: Bearer $(gcloud auth print-access-token)" \
 -H "Content-Type: application/json" \
https://{VERTEX_API_URL}/{MULTI_MODEL_API_VERSION}/projects/{PROJECT_ID}/locations/{REGION}/endpoints/{ENDPOINT_ID}:deployModel \
-d '{DEPLOY_MODEL_REQUEST}'

שוב, בדוגמה הזו שני המודלים נפרסו באותה נקודת קצה, אבל אפשר גם לארח מודלים באירוח נוסף באותו מאגר משאבים שנפרס בנקודות קצה שונים. במקרה כזה, לא צריך לדאוג לגבי פיצול התנועה.

לאחר פריסת המודל השני, תראו את שניהם במסוף.

deployed_models

שלב 5: קבלת חיזויים

בשלב האחרון בודקים את נקודת הקצה ומקבלים חיזויים.

קודם כול, מגדירים את משפט הבדיקה.

x_test=['The movie was cool. The animation and the graphics were out of this world. I would recommend this movie.']

לאחר מכן, הפעלת חיזוי (prediction) בנקודת הקצה שתחזיר חיזוי מאחד מהמודלים שנפרסו לנקודת הקצה.

endpoint.predict(instances=x_test)

🎉 כל הכבוד! 🎉

למדתם איך להשתמש ב-Vertex AI כדי:

  • מודלים של מארחים נוספים באותה VM לחיזויים אונליין

כדי לקבל מידע נוסף על החלקים השונים ב-Vertex, אתם יכולים לעיין במסמכי העזרה.

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

כדאי לבטל את הפריסה של המודלים מנקודת הקצה אם לא מתכננים להשתמש בהם. אפשר גם למחוק לגמרי את נקודת הקצה. תמיד אפשר לפרוס מחדש את המודל בנקודת קצה במקרה הצורך.

undeploy_model

אחרי 180 דקות ללא פעילות, notebooks שמנוהלים ב-Workbench מופסק באופן אוטומטי, כך שלא צריך לחשוש מכיבוי המכונה. כדי לכבות את המכונה באופן ידני, לוחצים על הלחצן Stop (עצירה) בקטע Vertex AI Workbench במסוף. אם אתה רוצה למחוק לגמרי את ה-notebook, לחץ על הלחצן 'מחיקה'.

עצירת המופע

כדי למחוק את קטגוריית האחסון, באמצעות תפריט הניווט במסוף Cloud, עוברים אל Storage (אחסון), בוחרים את הקטגוריה ולוחצים על סמל המחיקה:

מחיקת האחסון