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.
3. סקירה כללית של תרחיש השימוש
בשיעור ה-Lab הזה תשתמשו בכוונון היפר-פרמטרים כדי לגלות פרמטרים אופטימליים למודל סיווג תמונות שאומן על מערך הנתונים של סוסים או בני אדם מ-TensorFlow Datasets.
כוונון היפר-פרמטר
כוונון היפר-פרמטרים באמצעות הדרכת Vertex AI פועל על ידי הרצה של כמה ניסויים באפליקציית האימון, עם ערכים להיפר-פרמטרים שבחרתם, במסגרת המגבלות שהגדרתם. Vertex AI עוקב אחרי התוצאות של כל ניסוי ומבצע התאמות בניסויים הבאים.
כדי להשתמש בכוונון היפר-פרמטרים באימון של Vertex AI, יש שני שינויים שצריך לבצע בקוד האימון:
- מגדירים ארגומנט של שורת הפקודה במודול האימון הראשי לכל היפר-פרמטר שרוצים לכוונן.
- משתמשים בערך שמועבר בארגומנטים האלה כדי להגדיר את ההיפר-פרמטר התואם בקוד של האפליקציה.
הדרכה מבוזרת
אם יש לכם יחידת 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.
שלב 4: יצירת מכונה של Vertex AI Workbench
בקטע Vertex AI במסוף Cloud, לוחצים על Workbench:
מפעילים את Notebooks API, אם עדיין לא פועלים.
לאחר ההפעלה, לוחצים על פנקסי רשימות מנוהלים:
לאחר מכן בוחרים פנקס רשימות חדש.
נותנים שם ל-notebook ולוחצים על הגדרות מתקדמות.
בקטע 'הגדרות מתקדמות', מפעילים כיבוי ללא פעילות ומגדירים את מספר הדקות ל-60. כלומר, המחשב יכבה באופן אוטומטי כשהוא לא בשימוש כדי שלא תצברו עלויות מיותרות.
בקטע 'אבטחה', בוחרים באפשרות 'הפעלת הטרמינל' אם היא לא מופעלת עדיין.
אפשר להשאיר את כל שאר ההגדרות המתקדמות כפי שהן.
לאחר מכן, לוחצים על יצירה. הקצאה של המכונה תימשך כמה דקות.
אחרי שהמכונה נוצרה, בוחרים באפשרות Open JupyterLab.
בפעם הראשונה שתשתמשו במכונה חדשה, תתבקשו לבצע אימות. כדי לעשות זאת, פועלים לפי השלבים שבממשק המשתמש.
5. כתיבת קוד אימון
כדי להתחיל, פותחים חלון Terminal במכונה של ה-notebook מתפריט מרכז האפליקציות:
יוצרים ספרייה חדשה בשם 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()
בואו נבחן לעומק את הקוד ונבחן את הרכיבים הספציפיים לאימון מבוזר ולכוונון היפר-פרמטרים.
הדרכה מבוזרת
- בפונקציה
main()
, נוצר האובייקטMirroredStrategy
. לאחר מכן, אתם כוללים את היצירה של משתני המודל בתוך היקף האסטרטגיה. השלב הזה מורה ל-TensorFlow אילו משתנים יש לשקף בין ה-GPUs. - גודל קבוצת הקבצים מוגדל על ידי
num_replicas_in_sync
. השיטה המומלצת היא שינוי גודל האצווה כשמשתמשים באסטרטגיות סינכרוניות של נתונים במקביל ב-TensorFlow. מידע נוסף
כוונון היפר-פרמטר
- הסקריפט מייבא את הספרייה
hypertune
. מאוחר יותר, כשנבנה את קובץ האימג' של הקונטיינר, נצטרך לוודא שנתקין את הספרייה הזו. - הפונקציה
get_args()
מגדירה ארגומנט של שורת פקודה לכל היפר-פרמטר שרוצים לכוונן. בדוגמה הזו, ההיפר-פרמטרים שאמורים להיות כווננו הם קצב הלמידה, ערך התנע בכלי האופטימיזציה ומספר היחידות בשכבה המוסתרת האחרונה של המודל, אבל אתם מוזמנים להתנסות עם אחרים. הערך המועבר בארגומנטים האלה משמש לאחר מכן להגדרת ההיפר-פרמטר התואם בקוד (למשל, קבוצהlearning_rate = args.learning_rate
) - בסוף הפונקציה
main()
, הספרייהhypertune
משמשת להגדרת המדד שרוצים לבצע אופטימיזציה. ב-TensorFlow, שיטת Kerasmodel.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.
מייבאים את 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.
בסיום המשימה, תוכלו להציג ולמיין את תוצאות הניסויים כדי לגלות את השילוב הטוב ביותר של ערכי היפר-פרמטרים.
🎉 כל הכבוד! 🎉
למדתם איך להשתמש ב-Vertex AI כדי:
- הרצת משימת כוונון היפר-פרמטרים באמצעות אימון מבוזר
כדי לקבל מידע נוסף על החלקים השונים ב-Vertex AI, אתם יכולים לעיין במסמכי העזרה.
8. הסרת המשאבים
בגלל שהגדרנו את ה-notebook להפסקה של הזמן הקצוב לתפוגה אחרי 60 דקות ללא פעילות, אנחנו לא צריכים לדאוג לכיבוי המכונה. כדי לכבות את המכונה באופן ידני, לוחצים על הלחצן Stop (עצירה) בקטע Vertex AI Workbench במסוף. אם אתה רוצה למחוק לגמרי את ה-notebook, לחץ על הלחצן 'מחיקה'.
כדי למחוק את קטגוריית האחסון, באמצעות תפריט הניווט במסוף Cloud, עוברים אל Storage (אחסון), בוחרים את הקטגוריה ולוחצים על סמל המחיקה: