LightGBMでOptunaを使用するときの再現性確保について
Optunaとはハイパーパラメータチューニングを自動で実施してくれる大変便利なフレームワークで、LightGBMを使う人は良く使うんじゃないかなと思います。今回はそんなOptunaを使用するときの再現性の確保方法についてまとめます。私が使用しているパッケージのバージョンは以下の通りです。
- lightgbm 2.3.1
- optuna 2.8.0
1.概要
主なポイントは以下です。
- lightgbm.train()ではなく、lightgbm.LightGBMTuner()を使用して訓練する。
- 以下のパラメータを使用する。
- deterministic
- force_row_wiseまたはforce_col_wise
- optuna_seed
- 乱数シードを固定する(numpy.random.seedおよびrandom.seed)。
上記を1つずつ解説します。てっとり早くソース全文を確認したい方は本稿末尾をご参照ください。sklearnのirisデータ(アヤメデータ)を使用したサンプルコードを掲載しています。
2.解説
2.1.訓練用の関数としてLightGBMTunerを使用する
LightGBMを使用するときに、多くの人は以下のような実装をするのではないかな思います。
import optuna.integration.lightgbm as lgb ''' データの前処理等を実施(省略) ''' # 訓練実施 lgb.train(params, lgb_train, lgb_eval)
上記のlightgbm.train()をlightgbm.LightGBMTuner()に変更します。そうすることで、後述するパラメータが使えるようになります。
注意点ですが、lightgbm.LightGBMTuner()を使用すると、訓練の実施やモデルの取得等を明示的に定義する必要があります。実装は以下の通りです。
# 訓練方法の定義 booster = lgb.LightGBMTuner( params = params, train_set = lgb_train, valid_sets=lgb_eval, optuna_seed=123, ) # 訓練の実施 booster.run() # 訓練で得た最良のパラメータを表示 booster.best_params # 訓練で得た最良のモデル(Boosterオブジェクト)を取得する best_booster = booster.get_best_booster()
2.2.再現性確保用のパラメータの使用
以下のようにパラメータを使用します。
params = { 'objective': 'multiclass ', 'num_class':3, 'metric': 'multi_logloss', 'verbosity': -1, 'boosting_type': 'gbdt', 'deterministic':True, #再現性確保用のパラメータ 'force_row_wise':True #再現性確保用のパラメータ } booster = lgb.LightGBMTuner( params = params, train_set = lgb_train, valid_sets=lgb_eval, optuna_seed=123, #再現性確保用のパラメータ )
2.3.乱数シードの固定
numpy等で使用する乱数シードを固定する。実装は以下の通りです。
import numpy as np import random as rn np.random.seed(123) rn.seed(123)
参考:sklearnのirisデータを使用したサンプルコード
# 乱数シードの固定 import numpy as np import random as rn np.random.seed(123) rn.seed(123) # ライブラリのインポート from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.metrics import confusion_matrix import pandas as pd from optuna.integration import lightgbm as lgb # iris(アヤメ)データインポート iris = load_iris() # 訓練用データとテストデータに分割 x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.3,random_state=123) #LGB用のデータに変形 lgb_train = lgb.Dataset(x_train, y_train) lgb_eval = lgb.Dataset(x_test, y_test) # 訓練方法の定義 params = { 'objective': 'multiclass ', 'num_class':3, 'metric': 'multi_logloss', 'verbosity': -1, 'boosting_type': 'gbdt', 'deterministic':True, #再現性確保用のパラメータ 'force_row_wise':True #再現性確保用のパラメータ } booster = lgb.LightGBMTuner( params = params, train_set = lgb_train, valid_sets=lgb_eval, optuna_seed=123, #再現性確保用のパラメータ ) # 訓練の実施 booster.run() # 訓練で得た最良のパラメータを表示 booster.best_params # 訓練で得た最良のモデル(Boosterオブジェクト)を取得する best_booster = booster.get_best_booster() # テストデータに対して予測を実施 pred = best_booster.predict(x_test) pred = np.argmax(pred, axis=1) # 混同行列(Confusion Matrix)の表示 cm = confusion_matrix(y_test, pred) print(cm)
私の環境では、上記を実行することで、ハイパーパラメータが以下の通り固定されました。もしかしたら、環境によって結果は変わるかもしれませんが、同一環境であれば同一の結果になると思います。