การฝึกและการปรับแต่งไฮเปอร์พารามิเตอร์สำหรับโมเดล PyTorch บน Cloud AI Platform

1. ภาพรวม

ในแล็บนี้ คุณจะได้ดูเวิร์กโฟลว์การฝึก ML ที่สมบูรณ์ใน Google Cloud โดยใช้ PyTorch เพื่อสร้างโมเดล จากสภาพแวดล้อมของ Cloud AI Platform Notebooks คุณจะได้เรียนรู้วิธีแพ็กเกจงานการฝึกเพื่อเรียกใช้ใน AI Platform Training ด้วยการปรับไฮเปอร์พารามิเตอร์

สิ่งที่คุณจะได้เรียนรู้

โดยคุณจะได้เรียนรู้วิธีต่อไปนี้

  • สร้างอินสแตนซ์ AI Platform Notebooks
  • สร้างโมเดล PyTorch
  • ฝึกโมเดลด้วยการปรับแต่งไฮเปอร์พารามิเตอร์ใน AI Platform Training

ต้นทุนทั้งหมดในการเรียกใช้ Lab นี้ใน Google Cloud อยู่ที่ประมาณ $1

2. ตั้งค่าสภาพแวดล้อม

คุณจะต้องมีโปรเจ็กต์ Google Cloud Platform ที่เปิดใช้การเรียกเก็บเงินเพื่อเรียกใช้ Codelab นี้ หากต้องการสร้างโปรเจ็กต์ ให้ทำตามวิธีการที่นี่

ขั้นตอนที่ 1: เปิดใช้ Cloud AI Platform Models API

ไปที่ส่วนโมเดล AI Platform ใน Cloud Console แล้วคลิกเปิดใช้หากยังไม่ได้เปิดใช้

d0d38662851c6af3.png

ขั้นตอนที่ 2: เปิดใช้ Compute Engine API

ไปที่ Compute Engine แล้วเลือกเปิดใช้หากยังไม่ได้เปิดใช้ คุณจะต้องใช้ข้อมูลนี้เพื่อสร้างอินสแตนซ์ Notebook

ขั้นตอนที่ 3: สร้างอินสแตนซ์ AI Platform Notebooks

ไปที่ส่วน AI Platform Notebooks ใน Cloud Console แล้วคลิกอินสแตนซ์ใหม่ จากนั้นเลือกประเภทอินสแตนซ์ PyTorch ล่าสุด (ไม่มี GPU)

892b7588f940d145.png

ใช้ตัวเลือกเริ่มต้นหรือตั้งชื่อที่กำหนดเองได้ตามต้องการ แล้วคลิกสร้าง เมื่อสร้างอินสแตนซ์แล้ว ให้เลือกเปิด JupyterLab

63d2cf44801c2df5.png

จากนั้นเปิดอินสแตนซ์ Notebook ของ Python 3 จากตัวเรียกใช้โดยทำดังนี้

de4c86c6c7f9438f.png

คุณพร้อมที่จะเริ่มต้นแล้ว

ขั้นตอนที่ 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 เราจะต้องแพ็กเกจโค้ดการฝึกในเครื่องในอินสแตนซ์ Notebook และมี Bucket ของ Cloud Storage เพื่อจัดเก็บชิ้นงานสำหรับงานของเรา ก่อนอื่น เราจะสร้างที่เก็บข้อมูล คุณสามารถข้ามขั้นตอนนี้ได้หากมีอยู่แล้ว

ขั้นตอนที่ 1: สร้าง Bucket ของ Cloud Storage สำหรับโมเดล

ก่อนอื่นเรามากำหนดตัวแปรสภาพแวดล้อมบางอย่างที่จะใช้ตลอดทั้ง Codelab ที่เหลือกัน กรอกค่าด้านล่างด้วยชื่อโปรเจ็กต์ Google Cloud และชื่อของที่เก็บข้อมูล Cloud ที่คุณต้องการสร้าง (ต้องไม่ซ้ำกันทั่วโลก)

# Update these to your own GCP project, model, and version names
GCP_PROJECT = 'your-gcp-project'
BOCKET_URL = 'gs://storage_bucket_name'

ตอนนี้เราพร้อมที่จะสร้างที่เก็บข้อมูลแล้ว ซึ่งเราจะชี้ไปยังที่เก็บข้อมูลนี้เมื่อเริ่มงานการฝึก

เรียกใช้คำสั่ง gsutil นี้จากภายใน Notebook เพื่อสร้าง Bucket

!gsutil mb $BUCKET_URL

ขั้นตอนที่ 2: สร้างไฟล์เริ่มต้นสำหรับแพ็กเกจ Python

หากต้องการเรียกใช้การฝึกโมเดลใน AI Platform เราจะต้องกำหนดค่าโค้ดเป็นแพ็กเกจ Python ซึ่งประกอบด้วยไฟล์ setup.py ในไดเรกทอรีรากที่ระบุการอ้างอิงแพ็กเกจภายนอก ไดเรกทอรีย่อยที่มีชื่อแพ็กเกจของเรา (ในที่นี้เราจะเรียกว่า trainer/) และไฟล์ __init__.py ว่างภายในไดเรกทอรีย่อยนี้

ก่อนอื่นมาเขียนไฟล์ setup.py กัน เราใช้คำสั่ง %%writefile ของ iPython เพื่อบันทึกไฟล์ลงในอินสแตนซ์ ในที่นี้ เราได้ระบุไลบรารีภายนอก 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.'
)

จากนั้นมาสร้างไดเรกทอรีเทรนเนอร์/ และไฟล์ init.py ที่ว่างเปล่าภายในไดเรกทอรีกัน Python ใช้ไฟล์นี้เพื่อระบุว่านี่คือแพ็กเกจ

!mkdir trainer
!touch trainer/__init__.py

ตอนนี้เราพร้อมที่จะเริ่มสร้างงานการฝึกแล้ว

4. ดูตัวอย่างชุดข้อมูล

ห้องทดลองนี้มุ่งเน้นที่เครื่องมือสำหรับการฝึกโมเดลที่นี่ แต่เรามาดูชุดข้อมูลที่เราจะใช้ฝึกโมเดลเพื่อให้เข้าใจกันอย่างรวดเร็ว เราจะใช้ชุดข้อมูลการเกิดที่มีอยู่ใน BigQuery ซึ่งมีข้อมูลการเกิดจากสหรัฐอเมริกาในช่วงหลายทศวรรษ เราจะใช้ 2-3 คอลัมน์จากชุดข้อมูลเพื่อคาดการณ์น้ำหนักแรกเกิดของทารก ชุดข้อมูลต้นฉบับมีขนาดค่อนข้างใหญ่ และเราจะใช้ชุดข้อมูลย่อยซึ่งเราได้จัดเตรียมไว้ให้คุณใน Bucket ของ 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()

งานการฝึกประกอบด้วย 2 ฟังก์ชันซึ่งเป็นที่ที่งานส่วนใหญ่เกิดขึ้น

  • get_args(): ตัวเลือกนี้จะแยกวิเคราะห์อาร์กิวเมนต์บรรทัดคำสั่งที่เราจะส่งเมื่อสร้างงานการฝึก พร้อมกับไฮเปอร์พารามิเตอร์ที่เราต้องการให้ AI Platform เพิ่มประสิทธิภาพ ในตัวอย่างนี้ รายการอาร์กิวเมนต์มีเฉพาะไฮเปอร์พารามิเตอร์ที่เราจะเพิ่มประสิทธิภาพ ได้แก่ อัตราการเรียนรู้ของโมเดล โมเมนตัม และจำนวนนิวรอนในเลเยอร์ที่ซ่อนอยู่
  • train_model(): ในที่นี้ เราจะดาวน์โหลดข้อมูลลงใน Pandas DataFrame, ทำให้เป็นมาตรฐาน, แปลงเป็น PyTorch Tensors แล้วจึงกำหนดโมเดล ในการสร้างโมเดล เราใช้ PyTorch nn.Sequential API ซึ่งช่วยให้เรากำหนดโมเดลเป็นเลเยอร์ซ้อนกันได้
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

แทนที่จะลองใช้ค่าไฮเปอร์พารามิเตอร์ต่างๆ ด้วยตนเองและฝึกโมเดลใหม่ทุกครั้ง เราจะใช้บริการการเพิ่มประสิทธิภาพไฮเปอร์พารามิเตอร์ของ Cloud AI Platform หากเราตั้งค่างานการฝึกด้วยอาร์กิวเมนต์ไฮเปอร์พารามิเตอร์ AI Platform จะใช้การเพิ่มประสิทธิภาพแบบเบย์เพื่อค้นหาค่าที่เหมาะสมสำหรับไฮเปอร์พารามิเตอร์ที่เราระบุ

ในการปรับแต่งไฮเปอร์พารามิเตอร์ การทดลองครั้งเดียวประกอบด้วยการเรียกใช้การฝึกโมเดล 1 ครั้งโดยใช้ชุดค่าผสมของค่าไฮเปอร์พารามิเตอร์ที่เฉพาะเจาะจง 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

หากสร้างงานอย่างถูกต้อง ให้ไปที่ส่วนงานของคอนโซล AI Platform เพื่อตรวจสอบบันทึก

ขั้นตอนที่ 3: ตรวจสอบงาน

เมื่ออยู่ในส่วนงานของคอนโซลแล้ว ให้คลิกงานที่คุณเพิ่งเริ่มเพื่อดูรายละเอียด

c184167641bb7ed7.png

เมื่อเริ่มการทดลองรอบแรก คุณจะเห็นค่าไฮเปอร์พารามิเตอร์ที่เลือกสําหรับการทดลองแต่ละครั้ง ดังนี้

787c053ef9110e6b.png

เมื่อการทดสอบเสร็จสมบูรณ์ ระบบจะบันทึกมูลค่าที่ได้จากเมตริกการเพิ่มประสิทธิภาพ (ในกรณีนี้คือ val_mse) ไว้ที่นี่ งานควรใช้เวลา 15-20 นาทีในการเรียกใช้ และแดชบอร์ดจะมีลักษณะดังนี้เมื่องานเสร็จสิ้น (ค่าที่แน่นอนจะแตกต่างกันไป)

47ef6b9b4ecb532c.png

หากต้องการแก้ไขข้อบกพร่องที่อาจเกิดขึ้นและตรวจสอบงานอย่างละเอียด ให้คลิกดูบันทึกจากหน้ารายละเอียดของงาน

18c32dcd36351930.png

คำสั่ง print() ทุกรายการในโค้ดการฝึกโมเดลจะแสดงที่นี่ หากพบปัญหา ให้ลองเพิ่มคำสั่งพิมพ์เพิ่มเติมและเริ่มงานการฝึกใหม่

เมื่องานการฝึกเสร็จสมบูรณ์แล้ว ให้ค้นหาไฮเปอร์พารามิเตอร์ที่ให้ค่า val_mse ต่ำที่สุด คุณจะใช้พารามิเตอร์เหล่านี้เพื่อฝึกและส่งออกโมเดลเวอร์ชันสุดท้าย หรือใช้เป็นแนวทางในการเริ่มงานการฝึกอีกงานที่มีการทดลองการปรับไฮเปอร์พารามิเตอร์เพิ่มเติมก็ได้

7. ล้างข้อมูล

หากต้องการใช้ Notebook นี้ต่อไป ขอแนะนำให้ปิดเมื่อไม่ได้ใช้งาน จาก UI ของ Notebook ใน Cloud Console ให้เลือก Notebook แล้วเลือกหยุด

879147427150b6c7.png

หากต้องการลบทรัพยากรทั้งหมดที่คุณสร้างไว้ใน Lab นี้ เพียงลบอินสแตนซ์ Notebook แทนการหยุด

ใช้เมนูการนำทางใน Cloud Console เพื่อไปที่ Storage แล้วลบทั้ง 2 Bucket ที่คุณสร้างขึ้นเพื่อจัดเก็บชิ้นงานโมเดล