1. סקירה כללית
בשיעור ה-Lab הזה תלמדו על תהליך עבודה מלא של אימון למידת מכונה ב-Google Cloud, באמצעות PyTorch כדי לבנות את המודל. בסביבת Cloud AI Platform Notebooks, תלמדו איך לארוז את משימת האימון כדי להריץ אותה ב-AI Platform Training עם כוונון של היפרפרמטרים.
מה תלמדו
במאמר הזה נסביר איך:
- יצירת מכונה של 'שירות ניסוי ופיתוח של AI Platform'
- יצירת מודל PyTorch
- אימון המודל באמצעות כוונון היפרפרמטרים ב-AI Platform Training
העלות הכוללת להרצת שיעור ה-Lab הזה ב-Google Cloud היא בערך 1$.
2. הגדרת הסביבה
כדי להפעיל את ה-codelab הזה, צריך פרויקט ב-Google Cloud Platform שמופעל בו חיוב. כדי ליצור פרויקט, פועלים לפי ההוראות האלה.
שלב 1: הפעלת Cloud AI Platform Models API
עוברים אל AI Platform Models section במסוף Cloud ולוחצים על Enable אם הוא עדיין לא מופעל.

שלב 2: הפעלת Compute Engine API
עוברים אל Compute Engine ובוחרים באפשרות הפעלה אם הוא עדיין לא מופעל. תצטרכו את זה כדי ליצור את מופע המחברת.
שלב 3: יצירת מופע של AI Platform Notebooks
עוברים אל AI Platform Notebooks section ב-Cloud Console ולוחצים על New Instance. לאחר מכן בוחרים את סוג האירוע האחרון של PyTorch (ללא GPU):

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

לאחר מכן, פותחים מופע של Python 3 Notebook ממרכז האפליקציות:

הכול מוכן!
שלב 5: ייבוא חבילות Python
בתא הראשון של ה-Notebook, מוסיפים את הייבוא הבא ומריצים את התא. כדי להפעיל אותו, לוחצים על לחצן החץ ימינה בתפריט העליון או על Command-Enter:
import datetime
import numpy as np
import os
import pandas as pd
import time
אפשר לראות שלא מייבאים כאן את PyTorch. הסיבה לכך היא שאנחנו מריצים את משימת האימון ב-AI Platform Training, ולא ממופע ה-Notebook שלנו.
3. יצירת חבילה למשימת האימון
כדי להריץ את משימת האימון ב-AI Platform Training, נצטרך לארוז את קוד האימון באופן מקומי ב-Notebooks instance, וקטגוריה של Cloud Storage לאחסון נכסים עבור המשימה. קודם ניצור קטגוריית אחסון. אפשר לדלג על השלב הזה אם כבר יש לכם חשבון.
שלב 1: יצירת קטגוריה של Cloud Storage עבור המודל
קודם נגדיר כמה משתני סביבה שנשתמש בהם בהמשך ה-codelab. ממלאים את הערכים הבאים בשם הפרויקט בענן ב-Google Cloud ובשם הקטגוריה ב-Cloud Storage שרוצים ליצור (השם חייב להיות ייחודי באופן גלובלי):
# Update these to your own GCP project, model, and version names
GCP_PROJECT = 'your-gcp-project'
BOCKET_URL = 'gs://storage_bucket_name'
עכשיו אפשר ליצור מאגר אחסון, שאליו נפנה כשנתחיל את משימת האימון.
מריצים את הפקודה gsutil מתוך ה-notebook כדי ליצור קטגוריה:
!gsutil mb $BUCKET_URL
שלב 2: יצירת הקבצים הראשוניים לחבילת Python
כדי להריץ משימת אימון ב-AI Platform, צריך להגדיר את הקוד כחבילת Python. הוא כולל קובץ setup.py בספריית השורש שמציין את כל התלות בחבילות חיצוניות, ספריית משנה עם שם החבילה (במקרה הזה נקרא לה trainer/) וקובץ __init__.py ריק בתוך ספריית המשנה הזו.
קודם כול, נכתוב את הקובץ setup.py. אנחנו משתמשים בפקודות הקסם של iPython %%writefile כדי לשמור את הקובץ במופע שלנו. בדוגמה הזו ציינו 3 ספריות חיצוניות שנשתמש בהן בקוד ההדרכה: PyTorch, Scikit-learn ו-Pandas:
%%writefile setup.py
from setuptools import find_packages
from setuptools import setup
REQUIRED_PACKAGES = ['torch>=1.5', 'scikit-learn>=0.20', 'pandas>=1.0']
setup(
name='trainer',
version='0.1',
install_requires=REQUIRED_PACKAGES,
packages=find_packages(),
include_package_data=True,
description='My training application package.'
)
בשלב הבא, ניצור את הספרייה trainer/ ואת הקובץ הריק init.py בתוכה. קובץ Python משמש לזיהוי חבילה:
!mkdir trainer
!touch trainer/__init__.py
עכשיו אפשר להתחיל ליצור את משימת האימון.
4. תצוגה מקדימה של מערך הנתונים
המיקוד של שיעור ה-Lab הזה הוא בכלים לאימון מודלים, אבל נסתכל רגע על מערך הנתונים שבו נשתמש כדי לאמן את המודל להבין. נשתמש במערך הנתונים של לידות שזמין ב-BigQuery. המאגר הזה מכיל נתוני לידות בארה"ב במשך כמה עשורים. נשתמש בכמה עמודות ממערך הנתונים כדי לחזות את משקל הלידה של תינוק. מערך הנתונים המקורי גדול מאוד, ואנחנו נשתמש בחלק ממנו שהעמדנו לרשותכם בקטגוריה של Cloud Storage.
שלב 1: הורדת מערך הנתונים של BigQuery בנושא שיעור ילודה
נוריד את הגרסה של מערך הנתונים שזמינה לכם ב-Cloud Storage ל-Pandas DataFrame ונציג תצוגה מקדימה שלו.
natality = pd.read_csv('https://storage.googleapis.com/ml-design-patterns/natality.csv')
natality.head()
במערך הנתונים הזה יש קצת פחות מ-100,000 שורות. נשתמש ב-5 מאפיינים כדי לחזות את משקל הלידה של התינוק: גיל האם והאב, שבועות ההיריון, העלייה במשקל של האם (בליברות) ומגדר התינוק (מיוצג כערך בוליאני).
5. הגדרת משימת האימון עם כוונון היפר-פרמטרים
נכתוב את סקריפט האימון שלנו לקובץ בשם model.py בתוך ספריית המשנה trainer/ שיצרנו קודם. משימת האימון שלנו תפעל ב-AI Platform Training, ותשתמש גם בשירות כוונון ההיפרפרמטרים של AI Platform כדי למצוא את ההיפרפרמטרים האופטימליים למודל שלנו באמצעות אופטימיזציה בייסיאנית.
שלב 1: יצירת תסריט ההדרכה
קודם ניצור את קובץ Python עם סקריפט ההדרכה. לאחר מכן ננתח את מה שקורה בו. הרצת הפקודה %%writefile תכתוב את קוד המודל לקובץ Python מקומי:
%%writefile trainer/model.py
import argparse
import hypertune
import numpy as np
import pandas as pd
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.utils import shuffle
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import normalize
def get_args():
"""Argument parser.
Returns:
Dictionary of arguments.
"""
parser = argparse.ArgumentParser(description='PyTorch MNIST')
parser.add_argument('--job-dir', # handled automatically by AI Platform
help='GCS location to write checkpoints and export ' \
'models')
parser.add_argument('--lr', # Specified in the config file
type=float,
default=0.01,
help='learning rate (default: 0.01)')
parser.add_argument('--momentum', # Specified in the config file
type=float,
default=0.5,
help='SGD momentum (default: 0.5)')
parser.add_argument('--hidden-layer-size', # Specified in the config file
type=int,
default=8,
help='hidden layer size')
args = parser.parse_args()
return args
def train_model(args):
# Get the data
natality = pd.read_csv('https://storage.googleapis.com/ml-design-patterns/natality.csv')
natality = natality.dropna()
natality = shuffle(natality, random_state = 2)
natality.head()
natality_labels = natality['weight_pounds']
natality = natality.drop(columns=['weight_pounds'])
train_size = int(len(natality) * 0.8)
traindata_natality = natality[:train_size]
trainlabels_natality = natality_labels[:train_size]
testdata_natality = natality[train_size:]
testlabels_natality = natality_labels[train_size:]
# Normalize and convert to PT tensors
normalized_train = normalize(np.array(traindata_natality.values), axis=0)
normalized_test = normalize(np.array(testdata_natality.values), axis=0)
train_x = torch.Tensor(normalized_train)
train_y = torch.Tensor(np.array(trainlabels_natality))
test_x = torch.Tensor(normalized_test)
test_y = torch.Tensor(np.array(testlabels_natality))
# Define our data loaders
train_dataset = torch.utils.data.TensorDataset(train_x, train_y)
train_dataloader = torch.utils.data.DataLoader(train_dataset, batch_size=128, shuffle=True)
test_dataset = torch.utils.data.TensorDataset(test_x, test_y)
test_dataloader = torch.utils.data.DataLoader(test_dataset, batch_size=128, shuffle=False)
# Define the model, while tuning the size of our hidden layer
model = nn.Sequential(nn.Linear(len(train_x[0]), args.hidden_layer_size),
nn.ReLU(),
nn.Linear(args.hidden_layer_size, 1))
criterion = nn.MSELoss()
# Tune hyperparameters in our optimizer
optimizer = optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum)
epochs = 20
for e in range(epochs):
for batch_id, (data, label) in enumerate(train_dataloader):
optimizer.zero_grad()
y_pred = model(data)
label = label.view(-1,1)
loss = criterion(y_pred, label)
loss.backward()
optimizer.step()
val_mse = 0
num_batches = 0
# Evaluate accuracy on our test set
with torch.no_grad():
for i, (data, label) in enumerate(test_dataloader):
num_batches += 1
y_pred = model(data)
mse = criterion(y_pred, label.view(-1,1))
val_mse += mse.item()
avg_val_mse = (val_mse / num_batches)
# Report the metric we're optimizing for to AI Platform's HyperTune service
# In this example, we're mimizing error on our test set
hpt = hypertune.HyperTune()
hpt.report_hyperparameter_tuning_metric(
hyperparameter_metric_tag='val_mse',
metric_value=avg_val_mse,
global_step=epochs
)
def main():
args = get_args()
print('in main', args)
train_model(args)
if __name__ == '__main__':
main()
משימת האימון מורכבת משתי פונקציות שבהן מתבצע רוב העבודה.
-
get_args(): הפקודה הזו מנתחת את הארגומנטים של שורת הפקודה שנעביר כשניצור את משימת האימון, יחד עם ההיפר-פרמטרים שאנחנו רוצים ש-AI Platform יבצע אופטימיזציה שלהם. בדוגמה הזו, רשימת הארגומנטים כוללת רק את ההיפר-פרמטרים שאנחנו רוצים לבצע להם אופטימיזציה – קצב הלמידה של המודל, המומנטום ומספר הנוירונים בשכבה הנסתרת. -
train_model(): כאן אנחנו מורידים את הנתונים ל-Pandas DataFrame, מבצעים נורמליזציה, ממירים אותם ל-PyTorch Tensors ואז מגדירים את המודל. כדי לבנות את המודל, אנחנו משתמשים ב-PyTorchnn.SequentialAPI, שמאפשר לנו להגדיר את המודל כמערך של שכבות:
model = nn.Sequential(nn.Linear(len(train_x[0]), args.hidden_layer_size),
nn.ReLU(),
nn.Linear(args.hidden_layer_size, 1))
שימו לב שבמקום להגדיר את הגודל של השכבה הנסתרת של המודל שלנו כקבוע, אנחנו מגדירים אותו כהיפרפרמטר ש-AI Platform יכוון בשבילנו. מידע נוסף על כך מופיע בקטע הבא.
שלב 2: שימוש בשירות לכוונון היפרפרמטרים של AI Platform
במקום לנסות ידנית ערכים שונים של היפרפרמטרים ולאמן מחדש את המודל בכל פעם, נשתמש בשירות האופטימיזציה של היפרפרמטרים של AI Platform ב-Cloud. אם נגדיר את משימת האימון עם ארגומנטים של היפרפרמטרים, AI Platform ישתמש באופטימיזציה בייסיאנית כדי למצוא את הערכים האידיאליים להיפרפרמטרים שציינו.
בכוונון היפר-פרמטרים, ניסיון יחיד מורכב מהרצת אימון אחת של המודל עם שילוב ספציפי של ערכי היפר-פרמטרים. בהתאם למספר הניסויים שנריץ, AI Platform ישתמש בתוצאות של ניסויים שהושלמו כדי לבצע אופטימיזציה של ההיפרפרמטרים שהוא בוחר עבור ניסויים עתידיים. כדי להגדיר כוונון היפר-פרמטרים, צריך להעביר קובץ תצורה כשמפעילים את משימת האימון עם נתונים על כל אחד מההיפר-פרמטרים שמבצעים להם אופטימיזציה.
לאחר מכן, יוצרים את קובץ התצורה באופן מקומי:
%%writefile config.yaml
trainingInput:
hyperparameters:
goal: MINIMIZE
maxTrials: 10
maxParallelTrials: 5
hyperparameterMetricTag: val_mse
enableTrialEarlyStopping: TRUE
params:
- parameterName: lr
type: DOUBLE
minValue: 0.0001
maxValue: 0.1
scaleType: UNIT_LINEAR_SCALE
- parameterName: momentum
type: DOUBLE
minValue: 0.0
maxValue: 1.0
scaleType: UNIT_LINEAR_SCALE
- parameterName: hidden-layer-size
type: INTEGER
minValue: 8
maxValue: 32
scaleType: UNIT_LINEAR_SCALE
לכל היפרפרמטר אנחנו מציינים את הסוג, את טווח הערכים שאנחנו רוצים לחפש ואת קנה המידה שבו הערך יגדל בניסויים שונים.
בתחילת העבודה אנחנו מציינים גם את המדד שאנחנו מבצעים אופטימיזציה שלו. שימו לב שבסוף הפונקציה train_model() שלמעלה, אנחנו מדווחים על המדד הזה ל-AI Platform בכל פעם שניסוי מסתיים. כאן אנחנו מצמצמים את השגיאה הריבועית הממוצעת של המודל, ולכן אנחנו רוצים להשתמש בהיפרפרמטרים שמובילים לשגיאה הריבועית הממוצעת הנמוכה ביותר עבור המודל שלנו. השם של המדד הזה (val_mse) זהה לשם שבו אנחנו משתמשים כדי לדווח עליו כשאנחנו מתקשרים אל report_hyperparameter_tuning_metric() בסוף תקופת הניסיון.
6. הרצה של משימת אימון ב-AI Platform
בקטע הזה נתחיל את משימת אימון המודל עם כוונון של היפרפרמטרים ב-AI Platform.
שלב 1: הגדרה של משתני סביבה
קודם נגדיר כמה משתני סביבה שבהם נשתמש כדי להפעיל את משימת האימון. אם רוצים להריץ את העבודה באזור אחר, צריך לעדכן את המשתנה REGION שלמטה:
MAIN_TRAINER_MODULE = "trainer.model"
TRAIN_DIR = os.getcwd() + '/trainer'
JOB_DIR = BUCKET_URL + '/output'
REGION = "us-central1"
לכל משימת אימון ב-AI Platform צריך להיות שם ייחודי. מריצים את הפקודה הבאה כדי להגדיר משתנה לשם של העבודה באמצעות חותמת זמן:
timestamp = str(datetime.datetime.now().time())
JOB_NAME = 'caip_training_' + str(int(time.time()))
שלב 2: הפעלת משימת האימון
ניצור את משימת האימון באמצעות gcloud, Google Cloud CLI. אפשר להריץ את הפקודה הזו ישירות ב-notebook, עם הפניה למשתנים שהגדרנו למעלה:
!gcloud ai-platform jobs submit training $JOB_NAME \
--scale-tier basic \
--package-path $TRAIN_DIR \
--module-name $MAIN_TRAINER_MODULE \
--job-dir $JOB_DIR \
--region $REGION \
--runtime-version 2.1 \
--python-version 3.7 \
--config config.yaml
אם יצרתם את המשימה בצורה נכונה, תוכלו לעבור אל הקטע Jobs במסוף AI Platform כדי לעקוב אחרי היומנים.
שלב 3: מעקב אחרי העבודה
אחרי שנכנסים לקטע 'משרות' במסוף, לוחצים על המשרה שהתחלתם לפרסם כדי לראות את הפרטים:

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

בסיום תקופות הניסיון, הערך שמתקבל של מדד האופטימיזציה (במקרה הזה val_mse) יתועד כאן. ההרצה של המשימה אמורה להימשך 15-20 דקות, וכשהיא תסתיים לוח הבקרה ייראה בערך כך (הערכים המדויקים ישתנו):

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

כל הצהרה של print() בקוד האימון של המודל תופיע כאן. אם נתקלתם בבעיות, נסו להוסיף עוד הצהרות הדפסה ולהתחיל משימת אימון חדשה.
אחרי שהרצתם את משימת האימון, חפשו את ההיפרפרמטרים שהניבו את הערך הנמוך ביותר של val_mse. אפשר להשתמש בהם כדי לאמן ולייצא גרסה סופית של המודל, או להשתמש בהם כהנחיות כדי להתחיל עוד משימת אימון עם ניסיונות נוספים של כוונון היפרפרמטרים.
7. הסרת המשאבים
אם רוצים להמשיך להשתמש ב-notebook הזה, מומלץ להשבית אותו כשלא משתמשים בו. בממשק המשתמש של Notebooks במסוף Cloud, בוחרים את מחברת ה-Notebook ואז בוחרים באפשרות Stop:

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