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

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

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

מה תלמדו

תלמדו איך:

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

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

2. מבוא ל-Vertex AI

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

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

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

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

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

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

deployment_pool

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

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

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

עוברים אל 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

נותנים שם למחברת, ובקטע Permission בוחרים באפשרות Service account.

create_notebook

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

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

enable_terminal

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

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

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

open_jupyterlab

5. דגם הרכבת

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

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

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

launcher_terminal

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

PROJECT_ID='your-cloud-project'

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

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

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

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

launcher_tf2

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

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

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

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

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

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 בתוך אותו מאגר פריסה. נפרוס אותו באותה נקודת קצה כמו model_1. עם זאת, אפשר גם לפרוס את model_2 לנקודת קצה אחרת באותו מאגר משאבים.

מעדכנים את 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.']

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

endpoint.predict(instances=x_test)

🎉 מזל טוב! 🎉

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

  • אירוח משותף של מודלים באותה מכונה וירטואלית לצורך חיזויים אונליין

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

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

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

undeploy_model

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

הפסקת המכונה

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

מחיקת אחסון