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'da eksiksiz bir makine öğrenimi eğitimi iş akışını inceleyeceksiniz. Cloud AI Platform Notebooks ortamında, hiperparametre ince ayarı ile AI Platform Training'de çalıştırmak üzere eğitim işinizi nasıl paketleyeceğinizi öğreneceksiniz.

Öğrenecekleriniz

Öğrenecekleriniz:

  • AI Platform Notebooks örneği oluşturma
  • PyTorch modeli oluşturma
  • Modelinizi AI Platform Training'de hiperparametre ince ayarı ile 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 vardır. Proje oluşturmak için buradaki talimatları uygulayın.

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

Cloud Console'unuzun AI Platform Modelleri bölümüne gidin ve henüz 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 henüz etkinleştirilmemişse Etkinleştir'i seçin. Not defteri örneğinizi oluşturmak için bu bilgiye ihtiyacınız vardır.

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

Cloud Console'unuzun 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ü (GPU'suz) seçin:

892b7588f940d145.png

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

63d2cf44801c2df5.png

Ardından, başlatıcıdan bir Python 3 not defteri ö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. Bu işlemi, üst menüdeki sağ ok düğmesine veya command-enter tuşlarına basarak çalıştırabilirsiniz:

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

Burada PyTorch'u içe aktarmadığımızı fark edeceksiniz. Bunun nedeni, eğitim işini not defteri örneğimizden değil, AI Platform Training'de çalıştırmamızdır.

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

Eğitim işimizi AI Platform Training'de çalıştırmak için eğitim kodumuzun Notebooks örneğimizde yerel olarak paketlenmesi ve işimiz için öğeleri depolayacağımız bir Cloud Storage paketi gerekir. Öncelikle bir Storage paketi oluşturacağız. Daha önce oluşturduysanız bu adımı atlayabilirsiniz.

1. adım: Modelimiz için 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 adı ve oluşturmak istediğiniz Cloud Storage paketinin adıyla (global olarak benzersiz olmalıdır) doldurun:

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

Artık eğitim işimizi başlattığımızda işaret edeceğimiz bir depolama paketi oluşturmaya hazırız.

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

!gsutil mb $BUCKET_URL

2. adım: Python paketimiz için başlangıç dosyalarını 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, kök dizinimizdeki harici paket bağımlılıklarını belirten bir setup.py dosyası, paketimizin adını taşıyan bir alt dizin (burada trainer/ olarak adlandıracağız) ve bu alt dizindeki boş bir __init__.py dosyasından oluşur.

Öncelikle setup.py dosyamızı yazalım. Dosyayı örneğimize kaydetmek için iPython %%writefile sihirli komutlarını kullanıyoruz. Burada, eğitim kodumuzda kullanacağımız 3 harici kitaplığı (PyTorch, Scikit-learn ve Pandas) belirttik:

%%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.'
)

Ardından, eğitmenimizi/ dizinimizi ve içindeki boş init.py dosyasını oluşturalım. Python, bunun bir paket olduğunu anlamak için bu dosyayı kullanır:

!mkdir trainer
!touch trainer/__init__.py

Artık eğitim işimizi oluşturmaya başlayabiliriz.

4. Veri kümesini önizleme

Bu laboratuvarda modelleri eğitmek için kullanılan araçlara odaklanacağız. Ancak modelimizi eğitmek için kullanacağımız veri kümesine hızlıca göz atarak ne yapacağımızı anlayalım. BigQuery'de bulunan doğum veri kümesini kullanacağız. Bu veri kümesi, ABD'deki 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 olduğundan, Cloud Storage paketinde sizin için kullanıma sunduğumuz bir alt kümeyi 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ü 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'den biraz daha az satır var. Bebeğin doğum ağırlığını tahmin etmek için 5 özellik kullanacağız: anne ve baba yaşı, gebelik hafta sayısı, annenin kilo alımı (libre cinsinden) ve bebeğin cinsiyeti (boolean olarak gösterilir).

5. Hiperparametre ayarlama ile eğitim işini tanımlama

Eğitim komut dosyamızı, daha önce oluşturduğumuz trainer/ alt dizinindeki model.py adlı bir dosyaya yazacağız. Eğitim işimiz AI Platform Training'de çalışacak ve Bayesian optimizasyonunu kullanarak modelimiz için optimum hiperparametreleri bulmak üzere AI Platform'un hiperparametre ince ayar hizmetinden de yararlanacak.

1. adım: Eğitim senaryosunu oluşturun

İlk olarak, eğitim komut dosyamızı içeren Python dosyasını oluşturalım. Ardından, bu videoda neler olduğunu inceleyeceğiz. Bu %%writefile komutunu çalıştırmak, model kodunu yerel bir Python dosyasına yazar:

%%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 yapıldığı iki işlevden oluşur.

  • get_args(): Bu, 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 örnekte, bağımsız değişkenler listemizde yalnızca optimize edeceğimiz hiperparametreler (modelimizin öğrenme hızı, momentumu ve gizli katmanımızdaki nöron sayısı) yer alıyor.
  • train_model(): Burada verileri bir Pandas DataFrame'e indirip normalleştiriyor, PyTorch Tensörlerine dönüştürüyor ve ardından modelimizi tanımlıyoruz. 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 sabit kodlamak yerine, AI Platform'un bizim için ayarlayacağı bir hiperparametre haline getirdiğimizi unutmayın. Bu konuyla ilgili daha fazla bilgiyi sonraki bölümde bulabilirsiniz.

2. adım: AI Platform'un hiperparametre ayarlama hizmetini kullanma

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

Hiperparametre ayarlamada tek bir deneme, modelimizin belirli bir hiperparametre değeri kombinasyonuyla tek bir eğitim çalıştırmasından oluşur. AI Platform, kaç deneme yaptığımıza bağlı olarak tamamlanan denemelerin sonuçlarını kullanarak gelecekteki denemeler için seçtiği hiperparametreleri optimize eder. Hiperparametre ayarlamayı yapılandırmak için, optimize ettiğimiz hiperparametrelerin her biriyle ilgili bazı verilerle eğitim işimizi başlattığımızda bir yapılandırma dosyası iletmemiz gerekir.

Ardından, 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ğeri artıracağımız ölçeği belirtiriz.

İşin başında, optimizasyon yaptığımız metriği de belirtiriz. Yukarıdaki train_model() işlevimizin sonunda, bu metriği her deneme tamamlandığında AI Platform'a bildirdiğimizi unutmayın. Burada modelimizin ortalama karesel hatasını en aza indiriyoruz. Bu nedenle, modelimiz için en düşük ortalama karesel hatayı veren hiperparametreleri kullanmak istiyoruz. Bu metriğin adı (val_mse), deneme süresinin sonunda report_hyperparameter_tuning_metric() işlevini çağırdığımızda 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, AI Platform'da hiperparametre ince ayarı ile model eğitimi işimizi 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. Zaman damgası kullanarak işinizin adı için bir değişken tanımlamak üzere aşağıdakileri ç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 olan gcloud'u kullanarak oluşturacağız. Bu komutu doğrudan not defterimizde çalıştırabiliriz. Yukarıda tanımladığımız değişkenlere referans verebiliriz:

!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 girdikten sonra ayrıntıları görüntülemek için yeni başlattığınız işi tıklayın:

c184167641bb7ed7.png

İlk deneme turunuz başladığında her deneme için seçilen hiperparametre değerlerini görebilirsiniz:

787c053ef9110e6b.png

Denemeler tamamlandıkça optimizasyon metriğinizin (bu örnekte val_mse) sonuç değeri 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ı bir şekilde izlemek için iş ayrıntıları sayfasında Günlükleri Görüntüle'yi tıklayın:

18c32dcd36351930.png

Model eğitimi kodunuzdaki her print() ifadesi burada gösterilir. Sorun yaşı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 veren hiperparametreleri bulun. Bunları modelinizin son sürümünü eğitip dışa aktarmak için kullanabilir veya ek hiperparametre ayarlama denemeleriyle başka bir eğitim işi başlatmak için kılavuz olarak kullanabilirsiniz.

7. Temizleme

Bu not defterini kullanmaya devam etmek istiyorsanız kullanmadığınız zamanlarda kapatmanız önerilir. Cloud Console'unuzdaki Notebooks kullanıcı arayüzünde 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 silmeniz yeterlidir.

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