Vertex AI: אימון רב-עובדים והעברת למידה באמצעות TensorFlow

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

בשיעור ה-Lab הזה תלמדו להשתמש ב-Vertex AI כדי להריץ משימה אימון עם עובדים מרובים למודל TensorFlow.

מה תלמדו

תלמדו איך:

  • שינוי קוד האפליקציה של האימון לאימון של כמה עובדים
  • הגדרה והפעלה של משימת אימון עם עובדים מרובים דרך ממשק המשתמש של Vertex AI
  • הגדרה והשקה של משימת אימון מרובה עובדים באמצעות Vertex SDK

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

2. מבוא ל-Vertex AI

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

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

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

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

בשיעור ה-Lab הזה נעזרים בלמידת העברה כדי לאמן מודל לסיווג תמונות על סמך מערך הנתונים של קסאווה מ-TensorFlow Datasets. הארכיטקטורה שבה תשתמשו היא מודל ResNet50 מהספרייה tf.keras.applications, שעבר אימון מראש על מערך הנתונים Imagenet.

למה כדאי להשתמש באימון מבוזבז?

אם יש לכם GPU אחד, TensorFlow ישתמש במאיץ הזה כדי לזרז את אימון המודל בלי שתצטרכו לעשות שום דבר נוסף. עם זאת, אם אתם רוצים לקבל הגדלה של מספר מעבדי GPU במחשב אחד או בכמה מכונות (בכל אחת מהן יש כמה מעבדי GPU), תצטרכו להשתמש ב-tf.distribute, שהיא הספרייה של TensorFlow להרצת חישוב בכמה מכשירים. מכשיר מתייחס למעבד (CPU) או למאיץ, כמו מעבדי GPU או מעבדי TPU, במכונות מסוימות ש-TensorFlow יכול להריץ בהן פעולות.

הדרך הפשוטה ביותר להתחיל באימון מבוזר היא מכונה אחת עם כמה מכשירי GPU. אסטרטגיית הפצה של TensorFlow מהמודול tf.distribute תנהל את התיאום של הפצת נתונים ועדכונים הדרגתיים בין כל מעבדי ה-GPU. אם כבר רכשתם מיומנות בהדרכה במארח יחיד ואתם רוצים להרחיב את היקף העבודה עוד יותר, הוספת מכונות מרובות לאשכול יכולה לעזור לכם לשפר את הביצועים עוד יותר. אתם יכולים להשתמש באשכול של מכונות שהן מעבד (CPU) בלבד, או שלכל אחת מהן יש יחידת GPU אחת או יותר. בשיעור ה-Lab הזה תלמדו איך להשתמש ב-MultiWorkerMirroredStrategy כדי להפיץ אימון של מודל TensorFlow במספר מכונות ב-Vertex AI.

MultiWorkerMirroredStrategy היא אסטרטגיה של סינכרון מקבילי של נתונים, שאפשר להשתמש בה עם כמה שינויים קטנים בקוד. עותק של המודל נוצר בכל מכשיר באשכול. עדכוני ההדרגתיות הבאים יתבצעו באופן סינכרוני. כלומר, כל מכשיר עבודה מחשב את החזרות הקדימה והלאחור דרך המודל בחלק שונה של נתוני הקלט. לאחר מכן, הנגזרות המחושבות מכל אחד מהפלחים האלה נצברות בכל המכשירים במכונה ובכל המכונות באשכול, ומצטמצמות (בדרך כלל ממוצעות) בתהליך שנקרא all-reduce. לאחר מכן כלי האופטימיזציה מעדכן את הפרמטר עם ההדרגתיות המופחתת האלה, ובכך שומר על סנכרון המכשירים. למידע נוסף על אימון מבוזר באמצעות TensorFlow, כדאי לצפות בסרטון הבא:

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

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

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

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

שלב 2: מפעילים את Container Registry API

עוברים אל Container Registry ובוחרים באפשרות Enable (הפעלה) אם היא עדיין לא מסומנת. תשתמשו בו כדי ליצור קונטיינר למשימת האימון בהתאמה אישית.

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

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

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

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

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

התפריט של Vertex AI

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

Notebook_api

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

Notebooks_UI

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

new_notebook

נותנים שם למחברת ולוחצים על הגדרות מתקדמות.

create_notebook

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

idle_timeout

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

enable_terminal

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

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

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

open_jupyterlab

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

אימות

5. אריזה בקונטיינר של קוד אפליקציית האימון

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

כדי להתחיל, פותחים חלון Terminal במכונה של המחברת בתפריט Launcher:

פתיחת הטרמינל ב-notebook

יוצרים ספרייה חדשה בשם cassava ומוסיפים אליה cd:

mkdir cassava
cd cassava

שלב 1: יוצרים קובץ Docker

השלב הראשון ביצירת קונטיינרים לקוד הוא יצירת קובץ Docker. בקובץ Dockerfile תכללו את כל הפקודות הנדרשות להרצת קובץ האימג'. הספריות הנדרשות יותקנו ותתבצע הגדרה של נקודת הכניסה לקוד האימון.

יוצרים קובץ Dockerfile ריק ב-Terminal:

touch Dockerfile

פותחים את Dockerfile ומעתיקים אליו את הטקסט הבא:

FROM gcr.io/deeplearning-platform-release/tf2-gpu.2-7

WORKDIR /

# Copies the trainer code to the docker image.
COPY trainer /trainer

# Sets up the entry point to invoke the trainer.
ENTRYPOINT ["python", "-m", "trainer.task"]

קובץ ה-Dockerfile הזה משתמש בקובץ אימג' של Docker ב-Deep Learning Container TensorFlow Enterprise 2.7 GPU. הקונטיינרים של Deep Learning ב-Google Cloud מגיעים עם הרבה frameworks נפוצים של מדעי נתונים ולמידת מכונה שהותקנו מראש. אחרי הורדת התמונה, קובץ ה-Dockerfile הזה מגדיר את נקודת הכניסה לקוד האימון. עדיין לא יצרתם את הקבצים האלה – בשלב הבא תוסיפו את הקוד לאימון ולכוונון המודל.

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

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

PROJECT_ID='your-cloud-project'

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

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

שלב 3: מוסיפים קוד לאימון המודלים

בטרמינל, מריצים את הפקודה הבאה כדי ליצור ספרייה לקוד האימון וקובץ Python שאליו מוסיפים את הקוד:

mkdir trainer
touch trainer/task.py

עכשיו אמורים להופיע בספרייה cassava/:

+ Dockerfile
+ trainer/
    + task.py

אחר כך פותחים את הקובץ task.py שיצרתם ומעתיקים את הקוד שבהמשך. צריך להחליף את {your-gcs-bucket} בשם של הקטגוריה ב-Cloud Storage שיצרתם.

import tensorflow as tf
import tensorflow_datasets as tfds
import os


PER_REPLICA_BATCH_SIZE = 64
EPOCHS = 2

# TODO: replace {your-gcs-bucket} with the name of the Storage bucket you created earlier
BUCKET = 'gs://{your-gcs-bucket}/mwms'

def preprocess_data(image, label):
  '''Resizes and scales images.'''

  image = tf.image.resize(image, (300,300))
  return tf.cast(image, tf.float32) / 255., label


def create_dataset(batch_size):
  '''Loads Cassava dataset and preprocesses data.'''

  data, info = tfds.load(name='cassava', as_supervised=True, with_info=True)
  number_of_classes = info.features['label'].num_classes
  train_data = data['train'].map(preprocess_data,
                                 num_parallel_calls=tf.data.experimental.AUTOTUNE)
  train_data  = train_data.shuffle(1000)
  train_data  = train_data.batch(batch_size)
  train_data  = train_data.prefetch(tf.data.experimental.AUTOTUNE)

  # Set AutoShardPolicy
  options = tf.data.Options()
  options.experimental_distribute.auto_shard_policy = tf.data.experimental.AutoShardPolicy.DATA
  train_data = train_data.with_options(options)

  return train_data, number_of_classes


def create_model(number_of_classes):
  '''Creates and compiles pretrained ResNet50 model.'''

  base_model = tf.keras.applications.ResNet50(weights='imagenet', include_top=False)
  x = base_model.output
  x = tf.keras.layers.GlobalAveragePooling2D()(x)
  x = tf.keras.layers.Dense(1016, activation='relu')(x)
  predictions = tf.keras.layers.Dense(number_of_classes, activation='softmax')(x)
  model = tf.keras.Model(inputs=base_model.input, outputs=predictions)

  model.compile(
      loss='sparse_categorical_crossentropy',
      optimizer=tf.keras.optimizers.Adam(0.0001),
      metrics=['accuracy'])

  return model


def _is_chief(task_type, task_id):
  '''Helper function. Determines if machine is chief.'''

  return task_type == 'chief'


def _get_temp_dir(dirpath, task_id):
  '''Helper function. Gets temporary directory for saving model.'''

  base_dirpath = 'workertemp_' + str(task_id)
  temp_dir = os.path.join(dirpath, base_dirpath)
  tf.io.gfile.makedirs(temp_dir)
  return temp_dir


def write_filepath(filepath, task_type, task_id):
  '''Helper function. Gets filepath to save model.'''

  dirpath = os.path.dirname(filepath)
  base = os.path.basename(filepath)
  if not _is_chief(task_type, task_id):
    dirpath = _get_temp_dir(dirpath, task_id)
  return os.path.join(dirpath, base)


def main():
  # Create strategy
  strategy = tf.distribute.MultiWorkerMirroredStrategy()

  # Get data
  global_batch_size = PER_REPLICA_BATCH_SIZE * strategy.num_replicas_in_sync
  train_data, number_of_classes = create_dataset(global_batch_size)

  # Wrap variable creation within strategy scope
  with strategy.scope():
    model = create_model(number_of_classes)

  model.fit(train_data, epochs=EPOCHS)

  # Determine type and task of the machine from
  # the strategy cluster resolver
  task_type, task_id = (strategy.cluster_resolver.task_type,
                        strategy.cluster_resolver.task_id)

  # Based on the type and task, write to the desired model path
  write_model_path = write_filepath(BUCKET, task_type, task_id)
  model.save(write_model_path)

if __name__ == "__main__":
    main()

לפני שמפתחים את הקונטיינר, נבחן לעומק את הקוד, שמשתמש ב-MultiWorkerMirroredStrategy מ-API של tf.distribute.Strategy.

הקוד כולל מספר רכיבים שנדרשים כדי לעבוד עם MultiWorkerMirroredStrategy.

  1. צריך לפצל את הנתונים – כלומר, לכל עובד מוקצית קבוצת משנה של כל מערך הנתונים. לכן, בכל שלב כל עובד יעבד קבוצה גלובלית של רכיבי מערך נתונים שלא חופפים זה לזה. חלוקת המשנה מתבצעת באופן אוטומטי באמצעות tf.data.experimental.AutoShardPolicy, שאפשר להגדיר כ-FILE או כ-DATA. בדוגמה הזו, הפונקציה create_dataset() מגדירה את AutoShardPolicy כ-DATA כי מערך הנתונים של הקסאווה לא מוריד כמספר קבצים. עם זאת, אם לא תגדירו את המדיניות ל-DATA, תופעל מדיניות ברירת המחדל AUTO והתוצאה הסופית תהיה זהה. מידע נוסף על חלוקת מערכי נתונים באמצעות MultiWorkerMirroredStrategy
  2. בפונקציה main(), נוצר האובייקט MultiWorkerMirroredStrategy. בשלב הבא, צריך לתחום את יצירת משתני המודל בהיקף של האסטרטגיה. השלב הזה חיוני כדי להורות ל-TensorFlow אילו משתנים צריך לשקף בין הרפליקות.
  3. גודל האצווה יגדל לפי הערך של num_replicas_in_sync. כך אפשר להבטיח שכל רפליקה תעבד אותו מספר של דוגמאות בכל שלב. שינוי הגודל של האצווה היא שיטה מומלצת כשמשתמשים בשיטות של עיבוד נתונים סינכרוני במקביל ב-TensorFlow.
  4. שמירת המודל מורכבת יותר במקרה של כמה עובדים, כי היעד צריך להיות שונה לכל אחד מהעובדים. העובד הראשי ישמור את המודל בספריית המודל הרצויה, והעובדים האחרים ישמרו את המודל בספריות זמניות. חשוב שהספריות הזמניות האלה יהיו ייחודיות כדי למנוע מכמה עובדים לכתוב באותו מיקום. חיסכון יכול לכלול פעולות קולקטיביות, כלומר כל העובדים צריכים להציל ולא רק את המנהל. הפונקציות _is_chief(), _get_temp_dir(), write_filepath() והפונקציות main() כוללות קוד סטנדרטי שעוזר לשמור את המודל.

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

שלב 4: יצירת הקונטיינר

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

PROJECT_ID='your-cloud-project'

מגדירים משתנה עם ה-URI של קובץ האימג' בקונטיינר ב-Google Container Registry:

IMAGE_URI="gcr.io/$PROJECT_ID/multiworker:cassava"

הגדרת Docker

gcloud auth configure-docker

לאחר מכן, כדי ליצור את הקונטיינר, מריצים את הפקודה הבאה מהשורש של ספריית cassava:

docker build ./ -t $IMAGE_URI

לבסוף, מעבירים אותו ל-Google Container Registry:

docker push $IMAGE_URI

הקונטיינר הועבר ל-Container Registry. עכשיו אתם מוכנים להתחיל את משימת האימון.

6. הרצת משימת אימון מרובת עובדים ב-Vertex AI

בסדנת העבודה הזו נעשה שימוש באימון בהתאמה אישית באמצעות קונטיינר בהתאמה אישית ב-Google Container Registry, אבל אפשר גם להריץ משימת אימון באמצעות הקונטיינרים שנוצרו מראש.

כדי להתחיל, עוברים לקטע Training בקטע Vertex במסוף Cloud:

תפריט uCAIP

שלב 1: הגדרה של משימת האימון

לוחצים על יצירה כדי להזין את הפרמטרים למשימת האימון.

  • בקטע מערך נתונים, בוחרים באפשרות ללא מערך נתונים מנוהל.
  • לאחר מכן בוחרים באפשרות אימון מותאם אישית (מתקדם) כשיטת האימון ולוחצים על המשך.
  • מזינים multiworker-cassava (או כל שם אחר שרוצים לתת למודל) בשדה שם המודל.
  • לוחצים על המשך.

בשלב 'הגדרות מאגר התגים', בוחרים באפשרות מאגר תגים בהתאמה אישית:

אפשרות של מאגר בהתאמה אישית

בתיבה הראשונה (תמונה של קונטיינר), מזינים את הערך של המשתנה IMAGE_URI מהקטע הקודם. הערך צריך להיות: gcr.io/your-cloud-project/multiworker:cassava, עם מזהה הפרויקט שלכם. משאירים את שאר השדות ריקים ולוחצים על המשך.

כדי לדלג על השלב של הפרמטרים הסופר-היפרטרמיים, לוחצים שוב על Continue.

שלב 2: הגדרת אשכול המחשוב

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

Worker pool 0 מגדיר את המארח הראשי, המארח הראשי, מתזמן או 'מאסטר'. ב-MultiWorkerMirroredStrategy, כל המכונות מוגדרות כמכונות עבודה, שהן המכונות הפיזיות שבהן מתבצע החישוב המשוכפל. בנוסף לכך שכל מכונה היא worker, צריך להיות עובד אחד שמבצע עבודה נוספת כמו שמירת נקודות ביקורת וכתיבת קובצי סיכום ב-TensorBoard. המכונה הזו נקראת 'הראשית'. תמיד יש רק עובד ראשי אחד, כך שמספר העובדים במאגר העובדים 0 יהיה תמיד 1.

בקטע Compute andpricing, משאירים את האזור שנבחר כפי שהוא ומגדירים את Worker pool 0 באופן הבא:

Worker_pool_0

במאגר העובדים 1 מגדירים את העובדים של האשכולות.

מגדירים את מאגר העובדים 1 באופן הבא:

Worker_pool_1

האשכול מוגדר עכשיו עם שתי מכונות עם מעבדים בלבד. כשמפעילים את קוד האפליקציה של האימון, MultiWorkerMirroredStrategy יפיץ את האימון בין שתי המכונות.

ב-MultiWorkerMirroredStrategy יש רק את סוגי המשימות chief ו-worker, לכן אין צורך להגדיר את מאגרי העובדים הנוספים. עם זאת, אם משתמשים ב-ParameterServerStrategy של TensorFlow, צריך להגדיר את שרתי הפרמטרים במאגר העובדים 2. אם רוצים להוסיף למקבץ מכונה להערכה, צריך להגדיר את המכונה הזו במאגר העובדים 3.

לוחצים על Start training (התחלת האימון) כדי להתחיל את עבודת הכוונון של ההיפר-פרמטרים. בקטע Training במסוף, בכרטיסייה TRAINING PIPELINES, תוכלו לראות את המשימה החדשה שהפעלתם:

משרות הדרכה

🎉 כל הכבוד! 🎉

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

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

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

7. [אופציונלי] שימוש ב-Vertex SDK

בקטע הקודם הוסבר איך להפעיל את משימת האימון דרך ממשק המשתמש. בקטע הזה תוצג דרך חלופית לשלוח את משימת האימון באמצעות Vertex Python API.

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

new_notebook

מייבאים את Vertex AI SDK.

from google.cloud import aiplatform

כדי להפעיל את משימת האימון של ריבוי עובדים, קודם צריך להגדיר את המפרט של מאגר העובדים. חשוב לשים לב שהשימוש במעבדי GPU במפרט הוא אופציונלי לחלוטין, ואפשר להסיר את accelerator_type ואת accelerator_count אם רוצים אשכול של מעבד (CPU) בלבד כפי שמוצג בקטע הקודם.

# The spec of the worker pools including machine type and Docker image
# Be sure to replace {YOUR-PROJECT-ID} with your project ID.
worker_pool_specs=[
     {
        "replica_count": 1,
        "machine_spec": {
          "machine_type": "n1-standard-8", "accelerator_type": "NVIDIA_TESLA_V100", "accelerator_count": 1
        },
        "container_spec": {"image_uri": "gcr.io/{YOUR-PROJECT-ID}/multiworker:cassava"}
      },
      {
        "replica_count": 1,
        "machine_spec": {
          "machine_type": "n1-standard-8", "accelerator_type": "NVIDIA_TESLA_V100", "accelerator_count": 1
        },
        "container_spec": {"image_uri": "gcr.io/{YOUR-PROJECT-ID}/multiworker:cassava"}
      }
]

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

# Replace YOUR_BUCKET
my_multiworker_job = aiplatform.CustomJob(display_name='multiworker-cassava-sdk',
                              worker_pool_specs=worker_pool_specs,
                              staging_bucket='gs://{YOUR_BUCKET}')

my_multiworker_job.run()

בקטע Training במסוף, בכרטיסייה CUSTOM JOBS, תוכלו לראות את משימה האימון:

משימות בהתאמה אישית

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

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

עצירת המופע

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

מחיקת אחסון