Cloud AI Platform'da bir PyTorch modelini eğitme ve hiperparametre ayarı

1. Genel Bakış

Bu laboratuvarda, modelinizi oluşturmak için PyTorch'u kullanarak Google Cloud üzerinde eksiksiz bir makine öğrenimi eğitimi iş akışını inceleyeceksiniz. Cloud AI Platform Notebooks ortamından, eğitim işinizi hiperparametre ayarı ile AI Platform Eğitim'de çalıştırmak için nasıl paketleyeceğinizi öğreneceksiniz.

Öğrendikleriniz

Öğrenecekleriniz:

  • AI Platform Notebooks örneği oluşturma
  • PyTorch modeli oluşturma
  • AI Platform Training'de modelinizi hiperparametre ayarıyla eğitme

Bu laboratuvarı Google Cloud'da çalıştırmanın toplam maliyeti yaklaşık 1 ABD dolarıdır.

2. Ortamınızı ayarlama

Bu codelab'i çalıştırmak için faturalandırmanın etkin olduğu bir Google Cloud Platform projesine ihtiyacınız var. Proje oluşturmak için buradaki talimatları uygulayın.

1. Adım: Cloud AI Platform Models API'yi etkinleştirin

Cloud Console'un AI Platform Modelleri bölümüne gidin ve etkinleştirilmemişse Etkinleştir'i tıklayın.

d0d38662851c6af3.png

2. Adım: Compute Engine API'yi etkinleştirin

Compute Engine'e gidin ve zaten etkinleştirilmemişse Etkinleştir'i seçin. Not defteri örneğinizi oluşturmak için buna ihtiyacınız olacaktır.

3. Adım: AI Platform Notebooks örneği oluşturun

Cloud Console'un AI Platform Notebooks bölümüne gidin ve New Instance'ı (Yeni Örnek) tıklayın. Ardından en son PyTorch örnek türünü seçin (GPU'lar olmadan):

892b7588f940d145.png

Varsayılan seçenekleri kullanın veya isterseniz özel bir ad verin ve ardından Oluştur'u tıklayın. Örnek oluşturulduktan sonra JupyterLab'i aç'ı seçin:

63d2cf44801c2df5.png

Ardından, başlatıcıdan bir Python 3 Notebook örneği açın:

de4c86c6c7f9438f.png

Başlamaya hazırsınız!

5. Adım: Python paketlerini içe aktarın

Not defterinizin ilk hücresine aşağıdaki içe aktarma işlemlerini ekleyin ve hücreyi çalıştırın. Üst menüde sağ ok tuşuna veya Command-Enter tuşuna basarak çalıştırabilirsiniz:

import datetime
import numpy as np
import os
import pandas as pd
import time

PyTorch'u burada içe aktarmadığımızı göreceksiniz. Bunun nedeni, eğitim işini Notebook örneğimizden değil, AI Platform Eğitim'de çalıştırmamızdır.

3. Eğitim işi için bir paket oluşturma

AI Platform Training'de eğitim işimizi çalıştırmak için Notebooks örneğimizde yerel olarak paketlenmiş eğitim kodumuza ve işimiz için öğeleri depolayacak bir Cloud Storage paketine ihtiyacımız olacak. İlk olarak bir depolama paketi oluşturacağız. Zaten lisansınız varsa bu adımı atlayabilirsiniz.

1. Adım: Modelimiz için bir Cloud Storage paketi oluşturun

Öncelikle codelab'in geri kalanında kullanacağımız bazı ortam değişkenlerini tanımlayalım. Aşağıdaki değerleri Google Cloud projenizin ve oluşturmak istediğiniz bulut depolama paketinin adıyla girin (genel olarak benzersiz olmalıdır):

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

Şimdi, eğitim işimizi başlatırken işaret edeceğimiz bir depolama paketi oluşturmaya hazırız.

Paket oluşturmak için not defterinizde şu gsutil komutunu çalıştırın:

!gsutil mb $BUCKET_URL

2. Adım: Python paketimiz için ilk dosyaları oluşturun

AI Platform'da bir eğitim işi çalıştırmak için kodumuzu Python paketi olarak yapılandırmamız gerekir. Bu dosya, kök dizinimizde harici paket bağımlılıklarını belirten bir setup.py dosyasından, paketimizin adını taşıyan bir alt dizinden (burada trainer/ adını vereceğiz) ve bu alt dizin içinde boş bir __init__.py dosyasından oluşur.

İlk olarak setup.py dosyamızı yazalım. Dosyayı örneğimize kaydetmek için iPython %%Writefile sihirlerini kullanıyoruz. Eğitim kodumuzda kullanacağımız 3 harici kütüphaneyi burada açıkladık: PyTorch, Scikit-learn ve 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.'
)

Şimdi, Trainer/ dizinimizi ve içinde boş init.py dosyasını oluşturalım. Python, bunun bir paket olduğunu tanımak için bu dosyayı kullanır:

!mkdir trainer
!touch trainer/__init__.py

Artık eğitim işimizi oluşturmaya hazırız.

4. Veri kümesini önizleme

Bu laboratuvarın odak noktası, buradaki modelleri eğitmek için kullanılan araçlardır. Şimdi, modelimizi anlayacak şekilde eğitmek için kullanacağımız veri kümesine göz atalım. BigQuery'de bulunan doğum veri kümesini kullanacağız. Bu veriler, birkaç on yıl boyunca ABD'den elde edilen doğum verilerini içerir. Bebeğin doğum ağırlığını tahmin etmek için veri kümesindeki birkaç sütunu kullanacağız. Orijinal veri kümesi oldukça büyük. Sizin için Cloud Storage paketinde sunduğumuz bir alt veri kümesini kullanacağız.

1. Adım: BigQuery doğum oranı veri kümesini indirme

Cloud Storage'da sizin için kullanıma sunduğumuz veri kümesinin sürümünü bir Pandas DataFrame'e indirip önizleyelim.

natality = pd.read_csv('https://storage.googleapis.com/ml-design-patterns/natality.csv')
natality.head()

Bu veri kümesinde 100.000'in biraz altında satır var. Bir bebeğin doğum ağırlığını tahmin etmek için 5 özellik kullanacağız: anne ve baba yaşı, gebelik hafta sayısı, annenin kilogram cinsinden kilo alımı ve bebeğin cinsiyeti boole olarak temsil edilecek.

5. Eğitim işini hiperparametre ayarıyla tanımlama

Eğitim komut dosyamızı, daha önce oluşturduğumuz eğitmen/ alt dizinindeki model.py adlı bir dosyaya yazacağız. Eğitim işimiz AI Platform Training'de çalışacak ve Bayes optimizasyonunu kullanan modelimiz için optimum hiperparametreleri bulmak amacıyla AI Platform'un hiperparametre ayarlama hizmetinden de yararlanacaktır.

1. Adım: Eğitim komut dosyasını oluşturun

Öncelikle eğitim komut dosyamızla Python dosyasını oluşturalım. Daha sonra, neler olduğunu inceleyeceğiz. Bu %%Writefile komutunu çalıştırdığınızda model kodu, yerel bir Python dosyasına yazılır:

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

Eğitim işi, işin büyük kısmının gerçekleştiği iki işlevden oluşur.

  • get_args(): Bu işlem, eğitim işimizi oluştururken ileteceğimiz komut satırı bağımsız değişkenlerini ve AI Platform'un optimize etmesini istediğimiz hiperparametreleri ayrıştırır. Bu örnekteki bağımsız değişkenler listemiz yalnızca optimize edeceğimiz hiperparametreleri (modelimizin öğrenme hızı, momentumu ve gizli katmanımızdaki nöron sayısı) içerir.
  • train_model(): Burada verileri bir Pandas DataFrame'e indirir, normalleştirir, PyTorch Tensor'a dönüştürür ve ardından modelimizi tanımlarız. Modelimizi oluşturmak için PyTorch nn.Sequential API'sini kullanıyoruz. Bu API, modelimizi bir katman yığını olarak tanımlamamıza olanak tanır:
model = nn.Sequential(nn.Linear(len(train_x[0]), args.hidden_layer_size),
                      nn.ReLU(),
                      nn.Linear(args.hidden_layer_size, 1))

Modelimizin gizli katmanının boyutunu koda gömmek yerine, AI Platform'un bizim için ayarlayacağı bir hiperparametre yaptığımıza dikkat edin. Bu konuda daha fazla bilgiyi bir sonraki bölümde bulabilirsiniz.

2. Adım: AI Platform'un hiperparametre ayarı hizmetini kullanma

Farklı hiperparametre değerlerini manuel olarak denemek ve modelimizi her seferinde yeniden eğitmek yerine, Cloud AI Platform'un hiperparametre optimizasyon hizmetini kullanacağız. Eğitim işimizi hiperparametre bağımsız değişkenleriyle oluşturursak AI Platform, belirttiğimiz hiperparametreler için ideal değerleri bulmak amacıyla Bayes optimizasyonunu kullanır.

Hiperparametre ayarında tek bir deneme, modelimizin hiperparametre değerlerinin belirli bir kombinasyonuna sahip bir eğitim çalıştırmasından oluşur. AI Platform, çalıştırdığımız deneme sayısına bağlı olarak, tamamlanan denemelerin sonuçlarını kullanarak gelecekteki denemeler için seçtiği hiperparametreleri optimize eder. Hiperparametre ayarını yapılandırmak için, eğitim işimizi başlatırken optimize ettiğimiz hiperparametrelerin her biriyle ilgili bazı verileri içeren bir yapılandırma dosyası iletmemiz gerekir.

Daha sonra, yapılandırma dosyasını yerel olarak oluşturun:

%%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

Her hiperparametre için türü, aramak istediğimiz değer aralığını ve farklı denemelerde değerin yükseltileceği ölçeği belirtiriz.

İşin başında, optimizasyonu yaptığımız metriği de belirtiriz. Yukarıdaki train_model() işlevimizin sonunda, deneme her tamamlandığında bu metriği AI Platform'a bildirdiğimize dikkat edin. Burada modelimizin ortalama karesel hatasını en aza indiriyoruz ve bu nedenle modelimiz için en düşük ortalama karesel hataya yol açan hiperparametreleri kullanmak istiyoruz. Bu metriğin adı (val_mse), denemenin sonunda report_hyperparameter_tuning_metric() işlevini çağırdığımızda raporu raporlamak için kullandığımız adla eşleşir.

6. AI Platform'da eğitim işi çalıştırma

Bu bölümde, model eğitimi işimizi AI Platform'da hiperparametre ayarı ile başlatacağız.

1. Adım: Bazı ortam değişkenlerini tanımlayın

Öncelikle eğitim işimizi başlatmak için kullanacağımız bazı ortam değişkenlerini tanımlayalım. İşinizi farklı bir bölgede çalıştırmak istiyorsanız aşağıdaki REGION değişkenini güncelleyin:

MAIN_TRAINER_MODULE = "trainer.model"
TRAIN_DIR = os.getcwd() + '/trainer'
JOB_DIR = BUCKET_URL + '/output'
REGION = "us-central1"

AI Platform'daki her eğitim işinin benzersiz bir adı olmalıdır. Bir zaman damgası kullanarak işinizin adı için bir değişken tanımlamak üzere aşağıdaki komutu çalıştırın:

timestamp = str(datetime.datetime.now().time())
JOB_NAME = 'caip_training_' + str(int(time.time()))

2. Adım: Eğitim işini başlatın

Eğitim işimizi Google Cloud KSA'yı kullanarak oluşturacağız. Bu komutu, yukarıda tanımladığımız değişkenleri referans alarak doğrudan not defterimizde çalıştırabiliriz:

!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

İşiniz doğru şekilde oluşturulduysa günlükleri izlemek için AI Platform konsolunuzun İşler bölümüne gidin.

3. Adım: İşinizi izleyin

Konsolun İşler bölümüne geldiğinizde ayrıntılarını görüntülemek için yeni başladığınız işi tıklayın:

c184167641bb7ed7.png

Denemelerinizin ilk turu başladığında, her bir deneme için seçilen hiperparametre değerlerini görebilirsiniz:

787c053ef9110e6b.png

Denemeler tamamlandıkça optimizasyon metriğinizin ortaya çıkan değeri (bu durumda val_mse) buraya kaydedilir. İşin çalışması 15-20 dakika sürer ve iş tamamlandığında kontrol paneli aşağıdaki gibi görünür (tam değerler değişiklik gösterir):

47ef6b9b4ecb532c.png

Olası sorunları ayıklamak ve işinizi daha ayrıntılı olarak izlemek için iş ayrıntıları sayfasında Günlükleri Görüntüle'yi tıklayın:

18c32dcd36351930.png

Model eğitim kodunuzdaki her print() ifadesi burada gösterilir. Sorunlarla karşılaşıyorsanız daha fazla yazdırma ifadesi eklemeyi ve yeni bir eğitim işi başlatmayı deneyin.

Eğitim işiniz tamamlandıktan sonra en düşük val_mse değerini sağlayan hiperparametreleri bulun. Bunları modelinizin son sürümünü eğitmek ve dışa aktarmak için kullanabilir veya ek hiperparametre ayarlama denemeleriyle başka bir eğitim işi başlatmak için yol gösterici olarak kullanabilirsiniz.

7. Temizleme

Bu not defterini kullanmaya devam etmek istiyorsanız, kullanılmadığında devre dışı bırakmanız önerilir. Cloud Console'daki Not Defteri kullanıcı arayüzünden not defterini ve ardından Durdur'u seçin:

879147427150b6c7.png

Bu laboratuvarda oluşturduğunuz tüm kaynakları silmek istiyorsanız not defteri örneğini durdurmak yerine silin.

Cloud Console'daki gezinme menüsünü kullanarak Storage'a gidin ve model öğelerinizi depolamak için oluşturduğunuz her iki paketi de silin.