hyperparameter optimization untuk data science

5 Teknik Hyperparameter Optimization Untuk Data Science

Algoritma Hyperparameter Optimization untul Machine Learning (ML) adalah bagian penting dalam membangun model ML untuk meningkatkan performa model. Menyetel model pembelajaran mesin secara manual bisa menjadi tugas yang sangat memakan waktu.

Selain itu, kita tidak pernah dapat menjelajahi berbagai pilihan hyperparameter secara manual. Oleh karena itu, kita perlu mengambil bantuan teknik hyperparameter optimization untuk mendapatkan output yang optimal dari model ML. Pada artikel ini, saya akan membahas lima teknik hyperparameter optimization berikut dengan contoh kode python.

  • GridSearchCV
  • RandomSearchCV
  • Bayesian Optimization
  • HyperOpt
  • Optuna

Untuk kode python, saya menggunakan dataset Iris yang tersedia dalam paket Scikit-learn. Dataset tersebut adalah kumpulan data yang sangat kecil (hanya 150 baris) dengan masalah klasifikasi multikelas. mari kita memuat dataset dan membaginya menjadi fitur independen dan fitur target.

#importing library
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris

#Loading iris dataset from sklearn
iris = load_iris()

#Creating independent features
X = iris.data

#Creating traget features
y = iris.target

Karena kita sebagian besar berfokus pada hyperparameter tuning, jadi kita belum melakukan EDA (analisis data eksplorasi) atau bagian rekayasa fitur dan langsung masuk ke pembuatan model. Disini kita akan menggunakan algoritma XGBoostClssifier untuk pembuatan model untuk mengklasifikasikan variabel target.

#Importing XGBoost
from xgboost import XGBClassifier

#Defining XGB classification model
clf = XGBClassifier()

GridSearchCV

GridSearchCV adalah fungsi yang datang dalam paket model_selection Scikit-learn (atau SKlearn). Kemudian, kita meneruskan nilai yang telah ditentukan sebelumnya untuk hyperparameter ke fungsi GridSearchCV. Kita dapat mengatur validasi coss untuk pengujian dalam fungsi ini.

Fungsi GridSearchCV mengeksplorasi setiap kemungkinan kombinasi nilai yang disajikan dalam kumpulan parameter yang disediakan (disajikan dalam kamus) untuk mengoptimalkan akurasi model. Berikut adalah kode python untuk menggunakan GridSearchCV.

#Importing packages from sklearn
from sklearn import preprocessing
from sklearn import model_selection
from sklearn import metrics

#defining a set of values as a dictionary for hyperparameters
param_grid = {

    "n_estimators":[100,200,300,400],

    "max_depth":[1,3,5,7],

    "reg_lambda":[.01,.1,.5]    

}

#declaring GridSearchCV model
model = model_selection.GridSearchCV(
    estimator = clf,
    param_grid = param_grid,
    scoring = 'accuracy',
    verbose = 10,
    n_jobs = 1,
    cv = 5    
)

#fitting values to the gridsearchcv model
model.fit(X,y)

#printing the best possible values to enhance accuracy
print(model.best_params_)
print()
print(model.best_estimator_)

#printing the best score
print(model.best_score_)

Tampaknya hyperparameter optimization kita bekerja dengan baik dan model kami bekerja dengan akurasi 96,67%. Namun, karena GridSearchCV mengeksplorasi setiap kemungkinan kombinasi hyperparameter untuk kumpulan data yang disediakan, ini dapat memakan waktu.

Pada code di atas tidak memakan waktu lama karena menggunakan kumpulan data yang sangat kecil. Butuh 10,3 detik untuk mencoba semua 240 kombinasi. Jika kita memiliki kumpulan data yang besar, maka GridSearchCV harus dihindari.

RandomizedSearchCV

RandomizedSearchCV adalah fungsi lain yang hadir dalam paket model_selection Scikit-learn untuk Penyetelan Hyperparameter. Untuk menggunakan fungsi RandomizedSearchCV, kita kembali mendefinisikan kamus di mana kita menyebutkan hyperparameter tertentu bersama dengan nilai yang dapat diambil (sama seperti GridSearchCV). Kemudian, kita akan meneruskan nilai yang telah ditentukan sebelumnya untuk hyperparameter ke fungsi GridSearchCV.

Namun, perbedaan utama antara GridSearchCV dan RandomizedSearchCV adalah bahwa dalam RandomizedSearchCV kita dapat menetapkan jumlah iterasi yang tetap. Fungsi RandomizedSearchCV akan secara acak memilih parameter dari set parameter yang disediakan dan menghasilkan kombinasi hyperparameter terbaik dari jumlah percobaan yang disediakan.

#defining a set of values as a dictionary for hyperparameters
param_grid = {
    "n_estimators":[100,200,300,400],
    "max_depth":[1,3,5,7],
    "reg_lambda":[.01,.1,.5]    
}

#declaring RandomizedSearchCV model
model = model_selection.RandomizedSearchCV(
    estimator = clf,
    param_distributions = param_grid,
    scoring = 'accuracy',
    verbose = 10,
    n_jobs = 1,
    cv = 5,
    n_iter=10
)

#fitting values to the RandomizedSearchCV model
model.fit(X,y)

#printing the best possible values to enhance accuracy
print(model.best_params_)
print(model.best_estimator_)

#printing the best score
print(model.best_score_)

Disini kita akan menggunakan n_iter=10(10 percobaan). RandomizedSearchCV mengambil 10 kombinasi dari daftar hyperparameter yang disediakan dan menghasilkan kombinasi hyperparameter terbaik untuk mengoptimalkan akurasi model.

Pada kode di atas, RandomizedSearchCV menghasilkan akurasi 0,96 dan butuh waktu 2,1 detik untuk menyelesaikannya (untuk GridSearCV adalah 10,3 detik). Kita tidak dapat melihat banyak perbedaan waktu karena ini adalah kumpulan data yang sangat kecil. Namun, untuk kumpulan data yang besar, perbedaan waktu terlihat jelas.

Bayesian Optimization

Bayesian Optimization, seperti namanya bekerja pada Prinsip Bayes. Prinsip Bayes pada dasarnya mengatakan bahwa distribusi probabilitas posterior berbanding lurus dengan priornya (distribusi probabilitas sebelumnya) dan fungsi kemungkinannya.

bayesian optimization

Bayesian Optimization adalah metode optimasi global untuk noisy black-box functions. Teknik ini diterapkan pada pengoptimalan hyperparameter untuk model ML. Optimalisasi Bayesian membangun model probabilistik dari pemetaan fungsi dari nilai hyperparameter ke tujuan yang dievaluasi pada set validasi. Tanpa membahas teori secara mendetail, mari kita lihat kode python untuk metode pengoptimalan Bayesian.

#importing packages 
from functools import partial
from skopt import space
from skopt import gp_minimize

#defining a method that will perfrom a 5 split cross validation over
#dataset and and will produce the optimum value of the accuracy
def optimize(params, param_names, x,y):
    params = dict(zip(param_names,params))

    model = XGBClassifier(**params)
    kf = model_selection.StratifiedKFold(n_splits=5)

    accuracies = []

    for idx in kf.split(X=x,y=y):
        train_idx,test_idx = idx[0],idx[1]

        xtrain = x[train_idx]
        ytrain = y[train_idx]

        xtest = x[test_idx]
        ytest = y[test_idx]

        model.fit(xtrain,ytrain)

        preds =  model.predict(xtest)

        fold_acc = metrics.accuracy_score(ytest,preds)

        accuracies.append(fold_acc)

    return -1.0 * np.mean(accuracies)

#defining a set of values as space for hyperparameters
param_space = [
    space.Integer(3,15, name = "max_depth"),
    space.Integer(100,600, name = "n_estimators"),
    space.Real(0.01,1,prior='uniform', name="reg_lambda"),
    space.Real(0.01,1,prior='uniform', name="max_features")
]

#Defining the parameter names
param_names = [
    "max_depth",
    "n_estimators",
    "reg_lambda",
    "max_features"
]

#defiing optimization_fuction as partial and calling optimize within it
optimization_fuction = partial(optimize, param_names = param_names,x = X, y = y) 

#Getting the optimum values for hyperparameters
result = gp_minimize(
    optimization_fuction,
    dimensions=param_space,
    n_calls = 15,
    n_random_starts= 10,
    verbose= 10
)

#Printing the best hyperparemeter set
print(dict(zip(param_names,result.x)))

Di sini kita membuat satu fungsi bernama optimize. Fungsi ini mengambil parameter tuning hyperparameter, dataset independen, dan fitur target sebagai parameter input. Fungsi ini akan mengembalikan nilai optimal sesuai dengan ukuran kinerja yang ditentukan (untuk fungsi di atas, itu adalah akurasi). Nilai hyperparameter disediakan dalam modul space dari paket skopt.

Lalu, ada fungsi lain optimization_fuction (sebagai parsial) dan kita panggil fungsi optimize dari dalam optimization_fuction.

Terakhir, kita mengoptimalkan nilai parameter dengan memanggil skopt.gp_minimize.

Kode di atas melakukan pengoptimalan dalam 0,77 detik dan dengan akurasi 0,97%.

Sejauh ini, teknik optimasi ini menunjukkan hasil yang lebih baik dari dua model sebelumnya.

Di sini kita menggunakan StratifiedKFold untuk validasi silang pada kode di atas karena ini adalah masalah klasifikasi. Dalam kasus masalah regresi, itu tidak akan berhasil. Dalam hal ini, kita harus menggunakan KFold saja.

HyperOpt

HyperOpt adalah library python yang bersifat open-source yang digunakan untuk pengoptimalan hyperparameter untuk model ML. Seperti metode pengoptimalan lainnya yang disebutkan di atas, HyperOpt mencari melalui ruang hyperparameter. berikut adalah kode python untuk implementasi HyperOpt. Kalian dapat melihat dokumentasi paket ini untuk mendapatkan gambaran mendetail tentang parameter.

#importing packages 
from hyperopt import hp,fmin, tpe, Trials
from hyperopt.pyll.base import scope
from functools import partial
from skopt import space
from skopt import gp_minimize

#defining a method that will perfrom a 5 split cross validation over
#dataset and and will produce the optimum value of the accuracy
def optimize(params, x,y):

    clf = XGBClassifier(**params)

    kf = model_selection.StratifiedKFold(n_splits=5)

    accuracies = []

    for idx in kf.split(X=x,y=y):
        train_idx,test_idx = idx[0],idx[1]

        xtrain = x[train_idx]
        ytrain = y[train_idx]

        xtest = x[test_idx]
        ytest = y[test_idx]

        clf.fit(xtrain,ytrain)

        preds =  clf.predict(xtest)

        fold_acc = metrics.accuracy_score(ytest,preds)

        accuracies.append(fold_acc)

    return -1.0 * np.mean(accuracies)

#defining a set of values as hp for hyperparameters
param_space = {
    "max_depth" : scope.int(hp.quniform("max_depth",3,20, 1)) ,
    "min_child_weight" : scope.int(hp.quniform("min_child_weight",1,8, 1)),
    "n_estimators": scope.int(hp.quniform("n_estimators",100,1500,1)),
    'learning_rate': hp.uniform("learning_rate",0.01,1),
    'reg_lambda': hp.uniform("reg_lambda",0.01,1),
    'gamma': hp.uniform("gamma",0.01,1),
    'subsample': hp.uniform("subsample",0.01,1)
    }

#defiing optimization_fuction as partial and calling optimize within it
optimization_fuction = partial(optimize,x = X, y = y) 
trials = Trials()

#Getting the optimum values for hyperparameters
result = fmin(
    fn = optimization_fuction,
    space = param_space,
    algo = tpe.suggest,
    max_evals = 15,
    trials = trials
)

#Printing the best hyperparemeter set
print(result)

Kode untuk HyperOpt mirip dengan teknik Bayesian Optimization. Konstruksi fungsi optimize() hampir mirip. Meskipun, di sini kita tidak perlu mengirimkan param_name di parameter fungsi. Selain itu, cara kita mendefinisikan param_space juga berbeda.

Kode di atas membutuhkan waktu 0,12 detik untuk dieksekusi dan mengembalikan akurasi 0,96%. Ini juga tampaknya menjadi pilihan yang baik untuk kode kita.

Optuna

Optuna adalah pustaka python sumber terbuka lainnya yang digunakan untuk pengoptimalan hyperparameter untuk model ML. berikut adalah kode python untuk implementasi HyperOpt.

#importing packages
import optuna
from functools import partial

#defining a method that will perfrom a 5 split cross validation over
#dataset and and will produce the optimum value of the accuracy
def optimize(trial, x,y):

    #parameter set is declare within function
    reg_lambda = trial.suggest_uniform('reg_lambda',0.01,1)

    n_estimators = trial.suggest_int('n_estimators',100,1500)

    max_depth = trial.suggest_int('max_depth',3,15)
    max_features = trial.suggest_uniform('max_features',0.01,1)

    clf = XGBClassifier(

    n_estimators= n_estimators,

    reg_lambda=reg_lambda,

    max_depth=max_depth,
    max_features= max_features)

    kf = model_selection.StratifiedKFold(n_splits=5)

    accuracies = []

    for idx in kf.split(X=x,y=y):
        train_idx,test_idx = idx[0],idx[1]

        xtrain = x[train_idx]
        ytrain = y[train_idx]

        xtest = x[test_idx]
        ytest = y[test_idx]

        clf.fit(xtrain,ytrain)

        preds =  clf.predict(xtest)

        fold_acc = metrics.accuracy_score(ytest,preds)

        accuracies.append(fold_acc)

    return -1.0 * np.mean(accuracies)

#defiing optimization_fuction as partial and calling optimize within it
optimization_fuction = partial(optimize,x = X, y = y) 
study = optuna.create_study(direction='minimize')

#Printing the best hyperparemeter set
study.optimize(optimization_fuction, n_trials=15)

Untuk Optuna sedikit berbeda dari Hyperopt. Di sini, kita tidak perlu mendeklarasikan set parameter apa pun secara terpisah. Kita menyediakan kumpulan nilai hyperparameter dalam fungsi optimize itu sendiri. Kode lainnya mirip dengan kode untuk Hyperopt. Pada kode di atas membutuhkan waktu 0,11 detik untuk dieksekusi dan menghasilkan akurasi 0,97%.

Waktu eksekusi untuk teknik hyperparameter optimization yang disebutkan di atas dapat bervariasi tergantung pada ukuran dataset yang disediakan. Kalian dapat memilih teknik apapun yang kalian suka. Namun, untuk algoritma kompleks (misalnya: boosting ones), saya telah mengamati bahwa tiga teknik pengoptimalan sebelumnya (Bayesian Optimization, Hyperopt, Optuna) bekerja lebih baik.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top