Vertex AI: כוונון היפר-פרמטרים מבוזר

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

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

מה לומדים

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

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

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

2. מבוא ל-Vertex AI

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

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

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

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

בשיעור ה-Lab הזה תשתמשו בכוונון היפר-פרמטרים כדי לגלות פרמטרים אופטימליים למודל סיווג תמונות שאומן על מערך הנתונים של סוסים או בני אדם מ-TensorFlow Datasets.

כוונון היפר-פרמטר

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

כדי להשתמש בכוונון היפר-פרמטרים באימון של Vertex AI, יש שני שינויים שצריך לבצע בקוד האימון:

  1. מגדירים ארגומנט של שורת הפקודה במודול האימון הראשי לכל היפר-פרמטר שרוצים לכוונן.
  2. משתמשים בערך שמועבר בארגומנטים האלה כדי להגדיר את ההיפר-פרמטר התואם בקוד של האפליקציה.

הדרכה מבוזרת

אם יש לכם יחידת GPU אחת, TensorFlow ישתמש במאיץ הזה כדי להאיץ את אימון המודלים בלי מאמץ נוסף מצידכם. אבל אם רוצים לשפר את השימוש בכמה מעבדי GPU, צריך להשתמש ב-tf.distribute, שהוא המודול של TensorFlow להרצת חישוב בכמה מכשירים.

בשיעור ה-Lab הזה נעשה שימוש ב-tf.distribute.MirroredStrategy, שניתן להוסיף ליישומי האימון באמצעות כמה שינויים קלים בקוד. האסטרטגיה הזו יוצרת עותק של המודל בכל יחידת GPU במחשב שלכם. עדכוני ההדרגתיות הבאים יתבצעו באופן סינכרוני. כלומר, כל יחידת GPU מחשבת את המעבר קדימה ואחורה במודל בקטע אחר של נתוני הקלט. לאחר מכן, ההדרגתיות המחושבים מכל אחת מהפרוסות האלה נצברות בין כל מעבדי ה-GPU, והממוצע מחושב בתהליך שנקרא all-reduce. הפרמטרים של המודל מתעדכנים באמצעות הממוצעים של ההדרגתיות האלו.

אתם לא צריכים לדעת את הפרטים כדי להשלים את שיעור ה-Lab הזה, אבל אם אתם רוצים לקבל מידע נוסף על האופן שבו אימון מבוזר ב-TensorFlow, אתם יכולים לצפות בסרטון הבא:

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

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

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

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

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

create_notebook

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

idle_timeout

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

הפעלה-טרמינל

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

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

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

open_jupyterlab

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

אימות

5. כתיבת קוד אימון

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

launcher_terminal

יוצרים ספרייה חדשה בשם vertex-codelab ומוסיפים אליה cd.

mkdir vertex-codelab
cd vertex-codelab

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

mkdir trainer
touch trainer/task.py

עכשיו אמורים להיות בספרייה vertex-codelab הפריטים הבאים:

+ trainer/
    + task.py

לאחר מכן, פותחים את הקובץ task.py שיצרתם ומדביקים את הקוד שבהמשך.

import tensorflow as tf
import tensorflow_datasets as tfds
import argparse
import hypertune
import os

NUM_EPOCHS = 10
BATCH_SIZE = 64

def get_args():
  '''Parses args. Must include all hyperparameters you want to tune.'''

  parser = argparse.ArgumentParser()
  parser.add_argument(
      '--learning_rate',
      required=True,
      type=float,
      help='learning rate')
  parser.add_argument(
      '--momentum',
      required=True,
      type=float,
      help='SGD momentum value')
  parser.add_argument(
      '--num_units',
      required=True,
      type=int,
      help='number of units in last hidden layer')
  args = parser.parse_args()
  return args


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

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


def create_dataset(batch_size):
  '''Loads Horses Or Humans dataset and preprocesses data.'''

  data, info = tfds.load(name='horses_or_humans', as_supervised=True, with_info=True)

  # Create train dataset
  train_data = data['train'].map(preprocess_data)
  train_data  = train_data.shuffle(1000)
  train_data  = train_data.batch(batch_size)

  # Create validation dataset
  validation_data = data['test'].map(preprocess_data)
  validation_data  = validation_data.batch(batch_size)

  return train_data, validation_data


def create_model(num_units, learning_rate, momentum):
  '''Defines and compiles model.'''

  inputs = tf.keras.Input(shape=(150, 150, 3))
  x = tf.keras.layers.Conv2D(16, (3, 3), activation='relu')(inputs)
  x = tf.keras.layers.MaxPooling2D((2, 2))(x)
  x = tf.keras.layers.Conv2D(32, (3, 3), activation='relu')(x)
  x = tf.keras.layers.MaxPooling2D((2, 2))(x)
  x = tf.keras.layers.Conv2D(64, (3, 3), activation='relu')(x)
  x = tf.keras.layers.MaxPooling2D((2, 2))(x)
  x = tf.keras.layers.Flatten()(x)
  x = tf.keras.layers.Dense(num_units, activation='relu')(x)
  outputs = tf.keras.layers.Dense(1, activation='sigmoid')(x)
  model = tf.keras.Model(inputs, outputs)
  model.compile(
      loss='binary_crossentropy',
      optimizer=tf.keras.optimizers.SGD(learning_rate=learning_rate, momentum=momentum),
      metrics=['accuracy'])
  return model


def main():
  args = get_args()

  # Create distribution strategy
  strategy = tf.distribute.MirroredStrategy()

  # Get data
  GLOBAL_BATCH_SIZE = BATCH_SIZE * strategy.num_replicas_in_sync
  train_data, validation_data = create_dataset(GLOBAL_BATCH_SIZE)

  # Wrap variable creation within strategy scope
  with strategy.scope():
    model = create_model(args.num_units, args.learning_rate, args.momentum)

  # Train model
  history = model.fit(train_data, epochs=NUM_EPOCHS, validation_data=validation_data)

  # Define metric
  hp_metric = history.history['val_accuracy'][-1]

  hpt = hypertune.HyperTune()
  hpt.report_hyperparameter_tuning_metric(
      hyperparameter_metric_tag='accuracy',
      metric_value=hp_metric,
      global_step=NUM_EPOCHS)


if __name__ == "__main__":
    main()

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

הדרכה מבוזרת

  1. בפונקציה main(), נוצר האובייקט MirroredStrategy. לאחר מכן, אתם כוללים את היצירה של משתני המודל בתוך היקף האסטרטגיה. השלב הזה מורה ל-TensorFlow אילו משתנים יש לשקף בין ה-GPUs.
  2. גודל קבוצת הקבצים מוגדל על ידי num_replicas_in_sync. השיטה המומלצת היא שינוי גודל האצווה כשמשתמשים באסטרטגיות סינכרוניות של נתונים במקביל ב-TensorFlow. מידע נוסף

כוונון היפר-פרמטר

  1. הסקריפט מייבא את הספרייה hypertune. מאוחר יותר, כשנבנה את קובץ האימג' של הקונטיינר, נצטרך לוודא שנתקין את הספרייה הזו.
  2. הפונקציה get_args() מגדירה ארגומנט של שורת פקודה לכל היפר-פרמטר שרוצים לכוונן. בדוגמה הזו, ההיפר-פרמטרים שאמורים להיות כווננו הם קצב הלמידה, ערך התנע בכלי האופטימיזציה ומספר היחידות בשכבה המוסתרת האחרונה של המודל, אבל אתם מוזמנים להתנסות עם אחרים. הערך המועבר בארגומנטים האלה משמש לאחר מכן להגדרת ההיפר-פרמטר התואם בקוד (למשל, קבוצה learning_rate = args.learning_rate)
  3. בסוף הפונקציה main(), הספרייה hypertune משמשת להגדרת המדד שרוצים לבצע אופטימיזציה. ב-TensorFlow, שיטת Keras model.fit מחזירה אובייקט History. המאפיין History.history הוא תיעוד של ערכי אובדן ומדדי אימונים בתקופות עוקבות. אם מעבירים נתוני אימות אל model.fit, המאפיין History.history יכלול גם את ערכי המדדים וההפסד של האימות. לדוגמה, אם אימנתם מודל לשלוש תקופות עם נתוני אימות וסיפקתם את accuracy כמדד, המאפיין History.history ייראה דומה למילון הבא.
{
 "accuracy": [
   0.7795261740684509,
   0.9471358060836792,
   0.9870933294296265
 ],
 "loss": [
   0.6340447664260864,
   0.16712145507335663,
   0.04546636343002319
 ],
 "val_accuracy": [
   0.3795261740684509,
   0.4471358060836792,
   0.4870933294296265
 ],
 "val_loss": [
   2.044623374938965,
   4.100203514099121,
   3.0728273391723633
 ]

אם רוצים ששירות הכוונון של ההיפר-פרמטרים יגלה את הערכים שמשפרים את דיוק האימות של המודל, צריך להגדיר את המדד בתור הרשומה האחרונה (או NUM_EPOCS - 1) ברשימה val_accuracy. לאחר מכן, מעבירים את המדד הזה למופע של HyperTune. אפשר לבחור כל מחרוזת שרוצים עבור hyperparameter_metric_tag, אבל תצטרכו להשתמש במחרוזת שוב מאוחר יותר כשתתחילו את עבודת הכוונון של ההיפר-פרמטר.

6. יצירת קונטיינרים של הקוד

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

שלב 1: כותבים קובץ Docker

מה-Terminal, מוודאים שנמצאים בספרייה vertex-codelab ויוצרים קובץ Docker ריק:

touch Dockerfile

עכשיו אמורים להיות בספרייה vertex-codelab הפריטים הבאים:

+ Dockerfile
+ trainer/
    + task.py

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

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

WORKDIR /

# Installs hypertune library
RUN pip install cloudml-hypertune

# 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: יוצרים את המאגר

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

PROJECT_ID='your-cloud-project'

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

IMAGE_URI="gcr.io/$PROJECT_ID/horse-human-codelab:latest"

הגדרת Docker

gcloud auth configure-docker

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

docker build ./ -t $IMAGE_URI

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

docker push $IMAGE_URI

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

במשימת האימון שלנו נעביר את הנתיב לקטגוריית Staging.

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

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

7. הפעלה של משימת כוונון היפר-פרמטרים

שלב 1: יוצרים משימת אימון מותאמת אישית באמצעות כוונון היפר-פרמטרים

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

new_notebook

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

from google.cloud import aiplatform
from google.cloud.aiplatform import hyperparameter_tuning as hpt

כדי להפעיל את משימת הכוונון של ההיפר-פרמטרים, צריך קודם להגדיר את worker_pool_specs, שמציין את סוג המכונה ואת תמונת ה-Docker. במפרט הבא מוגדרת מכונה אחת עם שני מעבדי GPU NVIDIA Tesla V100.

צריך להחליף את {PROJECT_ID} באפליקציה image_uri בפרויקט שלך.

# The spec of the worker pools including machine type and Docker image
# Be sure to replace PROJECT_ID in the "image_uri" with your project.

worker_pool_specs = [{
    "machine_spec": {
        "machine_type": "n1-standard-4",
        "accelerator_type": "NVIDIA_TESLA_V100",
        "accelerator_count": 2
    },
    "replica_count": 1,
    "container_spec": {
        "image_uri": "gcr.io/{PROJECT_ID}/horse-human-codelab:latest"
    }
}]

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

לכל היפר-פרמטר, צריך להגדיר את הסוג ואת הגבולות של הערכים ששירות הכוונון ינסה. היפר-פרמטרים יכולים להיות מסוג Double, Integer, Categorical או Discrete (מספר קטגורי). אם בוחרים בסוג 'כפול' או 'מספר שלם', צריך לציין ערך מינימלי ומקסימלי. אם בוחרים באפשרות 'קטגורית' או 'בדיד', יש לספק את הערכים. עבור הסוגים Double ו-Integer, צריך גם לציין את ערך ההתאמה. בסרטון הזה מוסבר איך לבחור את קנה המידה הטוב ביותר.

# Dictionary representing parameters to optimize.
# The dictionary key is the parameter_id, which is passed into your training
# job as a command line argument,
# And the dictionary value is the parameter specification of the metric.
parameter_spec = {
    "learning_rate": hpt.DoubleParameterSpec(min=0.001, max=1, scale="log"),
    "momentum": hpt.DoubleParameterSpec(min=0, max=1, scale="linear"),
    "num_units": hpt.DiscreteParameterSpec(values=[64, 128, 512], scale=None)
}

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

# Dicionary representing metrics to optimize.
# The dictionary key is the metric_id, which is reported by your training job,
# And the dictionary value is the optimization goal of the metric.
metric_spec={'accuracy':'maximize'}

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

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

# Replace YOUR_BUCKET
my_custom_job = aiplatform.CustomJob(display_name='horses-humans',
                              worker_pool_specs=worker_pool_specs,
                              staging_bucket='gs://{YOUR_BUCKET}')

לאחר מכן, יוצרים ומפעילים את HyperparameterTuningJob.

hp_job = aiplatform.HyperparameterTuningJob(
    display_name='horses-humans',
    custom_job=my_custom_job,
    metric_spec=metric_spec,
    parameter_spec=parameter_spec,
    max_trial_count=6,
    parallel_trial_count=2,
    search_algorithm=None)

hp_job.run()

חשוב לשים לב למספר ארגומנטים:

  • max_trial_count: תצטרכו לקבוע גבול עליון למספר תקופות הניסיון שהשירות יפעל. לרוב, ניסויים רבים יותר מובילים לתוצאות טובות יותר, אבל יש נקודת ירידה בתשואות. לאחר מכן, לניסויים נוספים תהיה השפעה מועטה מאוד על המדד שברצונך לבצע אופטימיזציה שלו, או לא תהיה להם השפעה בכלל. מומלץ להתחיל עם מספר קטן יותר של ניסויים ולקבל מושג לגבי ההשפעה של ההיפר-פרמטרים שבחרתם לפני ההגדלה.
  • parallel_trial_count: אם אתם משתמשים בניסויים מקבילים, השירות מקצה מספר אשכולות עיבוד אימון. הגדלת מספר הניסיונות המקבילים מפחיתה את משך הזמן שנדרש להרצה של משימת הכוונון ההיפר-פרמטרים. עם זאת, הוא עלול לפגוע ביעילות של העבודה באופן כללי. הסיבה לכך היא שאסטרטגיית הכוונון שמוגדרת כברירת מחדל משתמשת בתוצאות מניסויים קודמים כדי לשפר את הקצאת הערכים בניסויים הבאים.
  • search_algorithm: אפשר להגדיר את אלגוריתם החיפוש לרשת, לבחור אקראי או לערך ברירת המחדל (ללא). אפשרות ברירת המחדל מחילה אופטימיזציה בייסיאנית כדי לחפש את השטח של ערכי היפר-פרמטרים אפשריים, והיא האלגוריתם המומלץ. מידע נוסף על האלגוריתם הזה זמין כאן.

כשהמשימה תתחיל, תוכלו לעקוב אחרי הסטטוס בממשק המשתמש בכרטיסייה HYPERPARAMETER TUNING JOBS.

HP_job

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

HP_results

🎉 כל הכבוד! 🎉

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

  • הרצת משימת כוונון היפר-פרמטרים באמצעות אימון מבוזר

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

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

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

delete

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

מחיקת האחסון