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

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

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

מה לומדים

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

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

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

2. מבוא ל-Vertex AI

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

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

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

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

בשיעור ה-Lab הזה תשתמשו בלמידת העברה כדי לאמן מודל לסיווג תמונות במערך הנתונים Cassava מ-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 היא אסטרטגיה סינכרונית של מקביליות נתונים שאפשר להשתמש בה רק בכמה שינויים בקוד. עותק של המודל נוצר בכל מכשיר באשכול. עדכוני ההדרגתיות הבאים יתבצעו באופן סינכרוני. כלומר, כל מכשיר של עובד מחשב את המעבר קדימה ואחורה במודל, בקטע שונה של נתוני הקלט. לאחר מכן, ההדרגתיות המחושבים מכל אחת מהפרוסות האלה נצברים בין כל המכשירים במכונה ובכל המכונות באשכול, ומצטמצמות (בדרך כלל בממוצע) בתהליך שנקרא 'צמצום מלא'. לאחר מכן כלי האופטימיזציה מעדכן את הפרמטר עם ההדרגתיות המופחתת האלה, ובכך שומר על סנכרון המכשירים. למידע נוסף על אימון מבוזר באמצעות TensorFlow, כדאי לצפות בסרטון הבא:

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

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

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

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

שלב 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

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

create_notebook

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

idle_timeout

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

enable_terminal

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

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

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

open_jupyterlab

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

אימות

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

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

כדי להתחיל, פותחים חלון Terminal במכונה של ה-notebook מתפריט מרכז האפליקציות:

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

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

mkdir cassava
cd cassava

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

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

בטרמינל, יוצרים קובץ Docker ריק:

touch Dockerfile

פותחים את קובץ ה-Docker ומעתיקים אליו את הפקודה הבאה:

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"]

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

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

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

PROJECT_ID='your-cloud-project'

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

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

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

docker build ./ -t $IMAGE_URI

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

docker push $IMAGE_URI

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

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

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

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

תפריט uCAIP

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

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

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

בשלב Container settings (הגדרות מאגר תגים), בוחרים באפשרות CustomContainer (מאגר מותאם אישית):

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

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

מדלגים על השלב של ההיפר-פרמטרים בלחיצה על המשך שוב.

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

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

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

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

Worker_pool_0

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

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

Worker_pool_1

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

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

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

# 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()

בקטע 'אימון' במסוף, בכרטיסייה ועוד JOBS, תופיע משימת האימון:

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

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

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

עצירת המופע

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

מחיקת האחסון