Parameter Tuning Model Secara Otomatis dengan Optuna

Apa itu Tuning Parameter

Ketika kita membuat model machine learning, kita tidak akan terlepas dengan yang namanya parameter tuning, yakni proses menentukan nilai parameter-parameter model ktia. Hampir semua model machine learning punya beberapa parameter (atau variabel) yang harus kita definisikan terlebih dahulu nilainya sebelum proses training. Nilai yang kita berikan pada parameter-parameter tersebut nantinya akan menentukan proses pelatihan model kita.

Sebagai contoh di neural network, kita harus menentukan parameter-parameter arsitektur kita, yang bisa meliputi: banyak hidden layer, banyak neuron di setiap layer, jenis fungsi aktivasi dan lain-lain. Penentuan angka-angka tersebut akan menentukan kualitas model kita. Misalkan, untuk tiga parameter yang disebutkan tadi kita menggunakan neural network dengan 2 layer, masing-masingnya 100 neuron, dan menggunakan fungsi aktivasi sigmoid. Itu berarti kita telah memilih nilai untuk tiga parameter yang disebutkan di atas dari banyak kemungkinan nilai. kenapa kok tidak 1 layer? atau 3 layer? kenapa tidak 50 neuron? atau 10 neuron? kenapa tidak pakai fungsi aktivasi lain? dan sebagainya.

Tentu pemilihan parameter harusnya memiliki suatu “dasar”. Biasanya parameter-parameter tersebut dipilih setelah melalui beberapa eksperimen dan merupakan parameter yang menghasilkan model terbaik untuk kasus yang digunakan.

Parameter Tuning model Neural Network

Pada contoh ini kita akan coba membuat model neural network sekaligus melakukan parameter tuning untuk kasus binary classification menggunakan data Sonar. Data tersebut berisikan ~200 pola sinyal sonar yang mendeteksi antara batu (kode “R”) atau besi (kode “M”). Dataset yang telah di-split dapat didownload di sini, contoh code dapat dilihat di Google Colab di sini

Langkah pertama, kita perlu load package dan dataset lalu ubah kode kelas “R”/”M” menjadi 1 dan 0.

import pandas as pd
import numpy as np
from sklearn.neural_network import MLPClassifier
np.random.seed(11)

# load dataset and convert to numpy
train_df = pd.read_csv("sonar-train.csv").values
test_df = pd.read_csv("sonar-test.csv").values

# separate features
x_train = np.asarray(train_df[:,:-1], dtype="float32")
x_test = np.asarray(test_df[:,:-1], dtype="float32")

# separate labels and convert the value
y_train = [ 1 if label=="R" else 0 for label in train_df[:,-1] ]
y_test = [ 1 if label=="R" else 0 for label in test_df[:,-1] ]

Setelah data siap, kita akan mencoba menggunakan package scikit-learn MLPClassifier untuk membuat model neural network. Package ini sebelumnya pernah dibahas di artikel ini.

Manual Tuning

Kita siapkan model kita menggunakan perintah di bawah.

clf = MLPClassifier(random_state=11)

Jika diperhatikan model yang kita buat tidak menggunakan parameter apapun kecuali random_seed (yang digunakan untuk menstabilkan nilai random). Artinya model MLPClassifier yang kita buat menggunakan default parameter dari scikit-learn. Default parameter dapat dilihat di dokumentasi scikit-learn:

Dari gambar di atas, tampak ada banyak parameter yang bisa kita atur aslinya dari package MLPClassifier. Untuk nilai default tampak beberapa di antaranya adalah:

  1. 1 hidden layer dengan 100 neuron
  2. fungsi aktivasi yang digunakan ReLU
  3. algoritma optimizernya Adam
  4. learning rate awal sebesar 0.001
  5. banyak iterasi maksimal adalah 200
  6. n_iter_no_change = 10, yang artinya jika dalam 10 iterasi tidak ada peningkatan kualitas model maka proses pelatihan dihentikan

Setelah model siap, proses selanjutnya kita akan train model tersebut dengan data train lalu hitung akurasi model ke data test.

clf.fit(x_train, y_train)
print("accuracy",clf.score(x_test, y_test))

Hasilnya adalah 0.67857 atau 67.86% prediksi sudah benar. Hasil tersebut adalah hasil menggunakan parameter default dari scikit-learn. Jika beberapa parameter diubah nilainya, bisa jadi model akan menghasilkan akurasi yang berbeda pula.

Saya sudah sempat coba-coba ganti parameternya (ini yang disebut manual parameter tuning) untuk menemukan parameter model terbaik, dan parameter yang menghasilkan model terbaik setelah dicoba-coba adalah:

clf = MLPClassifier(random_state=11, hidden_layer_sizes=(100),
    max_iter=100, learning_rate_init=0.0001)
clf.fit(x_train, y_train)
print("accuracy",clf.score(x_test, y_test))

Hasilnya adalah 0.78571 atau 78.57% prediksi sudah benar.

Dapat terlihat, penentuan parameter yang baik dapat menghasilkan model yang baik. Sayangnya, proses pencarian parameter itu bisa jadi sangat lama apalagi jika ada banyak parameter yang dapat diubah-ubah pada model kita. Dulu pas zaman lagi skripsi/thesis proses pencarian parameter bisa dibilang makan waktu lebih dari 50% pengerjaan.

Bayangkan saja, setiap pengubahan parameter kita perlu melakukan train model lagi, jika satu kali train model makan waktu 60 menit, dan ada 100 kombinasi parameter saja maka total proses training model adalah 100 jam! itu belum termasuk proses training yang salah atau error 🙁 dan masih ada salah satu masalah lain dalam manual parameter tuning, yakni menentukan parameter yang mana yang perlu diubah dan diubah menjadi nilai berapa.

Catatan: Ini alasan saya menyarankan untuk memahami algoritma atau matematika dari model yang akan digunakan. Sehingga kita dapat mendapatkan “intuisi” parameter mana yang perlu diperbaiki dan berapa nilai yang seharusnya diberi.

Optuna

Optuna adalah library yang dapat membantu mengotomatiskan proses parameter tuning. Tidak hanya mengotomasi, Optuna memiliki algoritma pencarian yang baik sehingga proses pencarian menjadi lebih efektif.

Secara umum proses pemakaiannya cukup sederhana. Bisa dirangkum menjadi 4 tahap:

  1. Kita tentukan parameter mana yang akan dicari nilainya
  2. Optuna akan “meng-generate” nilai setiap parameternya
  3. Kita tentukan fungsi evaluasi yang mengukur seberapa baik model dengan parameter yang telah digenerate. Optuna akan berusaha meminimalkan (atau memaksimalkan) nilai yang dihasilkan fungsi evaluasi ini.
  4. jalankan proses pencarian dengan menentukan batasan kapan pencarian berhenti.

Sebagai contoh sederhana yang ada di web Optuna kita akan mencoba menggunakan Optuna menemukan nilai x sehingga fungsi $f(x)=(x-2)^2$ menghasilkan nilai minimal.

import optuna

def objective(trial):
    x = trial.suggest_uniform('x', -10, 10)
    return (x - 2) ** 2

study = optuna.create_study()
study.optimize(objective, n_trials=100)
study.best_params # E.g. {'x': 2.002108042}

Pada contoh di atas, terdapat fungsi `objective(trial)` yang merupakan fungsi utama pencarian parameter. Di dalam fungsi tersebut, kita definisikan parameter yang ingin dicari adalah “x” dan nilainya diperkirakan adalah bilangan pecahan di antara -10.0 sampai 10.0. Proses tersebut dilakukan menggunakan fungsi bawaan Optuna suggest_uniform. Optuna menyediakan beragam fungsi suggest_* yang dapat digunakan untuk menentukan/memilih suatu nilai pada rentangan (space) pencarian tertentu. Dengan fungsi tersebut, Optuna akan meng-generate nilai parameter “x” yang akan dievaluasi berdasarkan percobaan-percobaan yang telah dilakukan.

Nilai yang dikembalikan fungsi objective(trial), yakni $f(x)$, adalah nilai evaluasi yang mengukur seberapa baik model dengan parameter saat ini. Secara default Optuna dilatih untuk meminimalkan nilai ini.

Pada saat menjalankan study.optimize, Optuna akan mulai proses pencarian nilai x dengan rentangan nilai antara -10.0 sampai 10.0 dengan jumlah percobaan sebanyak 100 kali. Setelah selesai pencarian, kita bisa mengecek parameter terbaik menggunakan study.best_params, pada contoh outputnya adalah 2.002. Jika dihitung dari rumusnya langsung, kita juga sebenarnya bisa langsung menebak bahwa nilai x seharusnya adalah 2, karena $f(2) = (2-2)^2 = 0$.

Optuna di Scikit Learn

Kita akan coba gunakan Optuna untuk parameter tuning model neural network kita sebelumnya. Pertama-tama kita perlu tentukan terlebih dahulu parameter apa saja yang akan dicari dan berapa rentangan pencarianya:

Deskripsi ParameterKodeRentangan
Banyak layerlayer[1, 2]
Banyak neuron di hidden layer 1h1[10 … 500]
Banyak neuron di hidden layer 2 (jika 2 layer)h2[10 … 500]
Maximum iterationi[10 … 1000]
Initial learning ratelr[0.00001 … 0.1]
`n_iter_no_change`ni[10 .. 30]

Jika tabel itu diterjemahkan ke fungsi objective di Optuna, maka hasilnya sebagai berikut:

def objective(trial):
    layers = trial.suggest_categorical('layers',[1,2])
    h1 = trial.suggest_int('h1',10,500)
    i = trial.suggest_int('max_i',10,1000)
    lr = trial.suggest_uniform('lr',0.00001,0.1)
    ni = trial.suggest_int('noi',10,30)

    if layers==1:
        clf = MLPClassifier(random_state=11,
                hidden_layer_sizes=(h1),
                max_iter=i, learning_rate_init=lr,
                n_iter_no_change=ni)
    else:
        h2 = trial.suggest_int('h2',10,500)
        clf = MLPClassifier(random_state=11,
                hidden_layer_sizes=(h1,h2),
        max_iter=i, learning_rate_init=lr, n_iter_no_change=ni)
    
    clf.fit(x_train, y_train)

    return clf.score(x_test, y_test)

study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=500)
print(study.best_params)

Pada kode di atas, fungsi objective terlihat sedikit lebih kompleks. Pada 5 baris pertama kita mendefinisikan parameter-parameter yang ingin di tuning beserta dengan rentangan nilainya. Khusus parameter h2, parameter tersebut diletakkan dalam fungsi if karena hanya akan diinisialisasi jika parameter layer bernilai 2.

Karena fungsi objective() dijalankan dengan tujuan untuk coba-coba nilai parameter yang di-generate Optuna, proses inisialisasi dan training model juga dilakukan di dalam fungsi objective. Sedangkan score dilakukan untuk memperoleh nilai akurasi model sebagai evaluasi parameter tuning.

Saya coba jalankan fungsi tersebut dengan percobaan sebanyak 500x. Hasilnya ditemukan akurasi yang lebih baik dari sebelumnya, yakni 0.8035 atau 80.35% 🙂

Kesimpulan

Optuna bisa jadi sangat membantu untuk proses pencarian parameter, khususnya ketika model yang ingin dicari parameternya memiliki banyak pilihan parameter. Secara kode, Optuna juga mudah untuk dipelajari dan tidak rumit untuk diimplementasi ke model kita yang sudah ada. Optuna menyediakan banyak contoh penggunaannya di beragam library machine learning besar. Yang perlu diingat, sebenarnya Optuna hanya “membrute-force” pencarian parameter dengan cara yang lebih baik. Itu artinya, bisa jadi proses yang dilakukan untuk pencarian parameter sangatlah lama. Bayangkan untuk model deep learning sekali proses pelatihan makan waktu bisa sampai 1 jam, 500 trial optuna berarti akan makan waktu 500 jam!

Sebenarnya Optuna juga memiliki fitur Pruning. Secara ringkas, teknik Pruning ini memungkinkan optuna menghentikan proses evaluasi parameter ditengah-tengah training. Misalnya pada contoh sebelumnya, Optuna bisa jadi tidak melanjutkan proses pelatihan dan berhenti di tengah-tengah,misal pada menit ke 30, karena merasa nilai parameter yang sedang dijalankan tidaklah baik. Saya yakin untuk beberapa kasus, kadang pencarian parameter secara otomatis akan lebih hemat waktu dibanding secara manual. Semoga bermanfaat.

About the author

Rian Adam

Lecturer at Universitas Islam Indonesia; Machine Learning Enthusiast

View all posts

Leave a Reply