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