🍷
【9日目】Optunaによるハイパーパラメーターチューニングをやってみる【2021アドベントカレンダー】
2021年1人アドベントカレンダー(機械学習)、9日目の記事になります。
テーマは Optuna によるハイパーパラメーターチューニング になります。
Colab のコードはこちら
optuna.integration.lightgbm によるハイパーパラメーターチューニング
lightGBM の場合は、
import lightgbm as lgb
を
import optuna.integration.lightgbm as lgb
にするだけでハイパーパラメーターチューニングできるのですごく便利です。
import optuna.integration.lightgbm as opt_lgb
ラベルエンコーディング等は割愛、詳細はColab参照。
y_train = y_train.reset_index(drop=True)
gkf = GroupKFold(n_splits=5)
groups = X_train_ce["Genre"]
params = {
'task': 'train', # タスクを訓練に設定
'boosting_type': 'gbdt', # GBDTを指定
'objective': 'regression', # 回帰を指定
'metric': 'rmse', # 回帰の損失(誤差)
'learning_rate': 0.1, # 学習率
'seed': SEED # シード値
}
best_params, history = {}, []
cv_result_opt = []
for fold, (train_index, test_index) in enumerate(gkf.split(X_train_ce, y_train, groups)):
X_train_gkf, X_test_gkf = X_train_ce.iloc[train_index], X_train_ce.iloc[test_index]
y_train_gkf, y_test_gkf = y_train.iloc[train_index], y_train.iloc[test_index]
# 学習、推論
lgb_train = opt_lgb.Dataset(X_train_gkf, y_train_gkf)
lgb_test = opt_lgb.Dataset(X_test_gkf, y_test_gkf, reference=lgb_train)
lgb_results = {} # 学習の履歴を入れる入物
model = opt_lgb.train(
params, # ハイパーパラメータをセット
lgb_train, # 訓練データを訓練用にセット
valid_sets=[lgb_train, lgb_test], # 訓練データとテストデータをセット
valid_names=['Train', 'Test'], # データセットの名前をそれぞれ設定
num_boost_round=100, # 計算回数
early_stopping_rounds=50, # アーリーストッピング設定
evals_result=lgb_results,
verbose_eval=-1, # ログを最後の1つだけ表示
)
best_params = model.params
# 損失推移を表示
loss_train = lgb_results['Train']['rmse']
loss_test = lgb_results['Test']['rmse']
fig = plt.figure()
plt.xlabel('Iteration')
plt.ylabel('logloss')
plt.title(f"fold:{fold}")
plt.plot(loss_train, label='train loss')
plt.plot(loss_test, label='test loss')
plt.legend()
plt.show()
# 推論
y_pred = model.predict(X_test_gkf, num_iteration=model.best_iteration)
# 評価
rmse = mean_squared_error(y_test_gkf, y_pred, squared=False)
cv_result_opt.append(rmse)
print("RMSE:", cv_result_opt)
print("RMSE:", np.mean(cv_result_opt))
すごく便利ではあるのですが、通常の LightGBM で使えるカスタムメトリクスが使えないようです。
Optuna によるハイパーパラメーターチューニング
そこで、コード量は増えますが、応用の効く通常のOptunaでのハイパーパラメーターチューニングを試します。
import optuna
ハイパーパラメーターチューニング用の関数を作る必要があります。
返り値を最小化するよう調整するようです。
回帰であることを踏まえ、返り値に RMSE を設定します。
パラメーターに trial.sugest_xxx を設定することで、引数に設定した値やデータを探索してくれるようです。
def objective(trial):
learning_rate = trial.suggest_uniform('learning_rate', 0.1, 1.0)
num_leaves = trial.suggest_int("num_leaves", 5, 50)
tree_learner = trial.suggest_categorical('tree_learner', ["serial", "feature", "data", "voting"])
params = {
'task': 'train', # タスクを訓練に設定
'boosting_type': 'gbdt', # GBDTを指定
'objective': 'regression', # 回帰を指定
'metric': {'rmse'}, # 回帰の損失(誤差)
'learning_rate': learning_rate, # 学習率
'num_leaves': num_leaves,
'tree_learner': tree_learner,
'seed': SEED # シード値
}
model = lgb.train(
params=params, # ハイパーパラメータをセット
train_set=lgb_train, # 訓練データを訓練用にセット
valid_sets=[lgb_train, lgb_test], # 訓練データとテストデータをセット
valid_names=['Train', 'Test'], # データセットの名前をそれぞれ設定
num_boost_round=100, # 計算回数
early_stopping_rounds=50, # アーリーストッピング設定
evals_result=lgb_results,
verbose_eval=-1, # ログを最後の1つだけ表示
)
# 推論
y_pred = model.predict(X_test_gkf)
# 評価
rmse = mean_squared_error(y_test_gkf, y_pred, squared=False)
return rmse
下記コードでハイパーパラメーターを実行します。
study = optuna.create_study()
study.optimize(objective, n_trials=100)
study.best_params で最も良かったハイパーパラメーター結果を辞書型で得ることができます。
ただし metric や objective の情報は失われてしまうようなので、study.best_params を変数に代入し、metric や objective を update で追加してやりました。
y_train = y_train.reset_index(drop=True)
gkf = GroupKFold(n_splits=5)
groups = X_train_ce["Genre"]
params = {
'task': 'train', # タスクを訓練に設定
'boosting_type': 'gbdt', # GBDTを指定
'objective': 'regression', # 回帰を指定
'metric': 'rmse', # 回帰の損失(誤差)
'learning_rate': 0.1, # 学習率
'seed': SEED # シード値
}
cv_result_opt2 = []
for fold, (train_index, test_index) in enumerate(gkf.split(X_train_ce, y_train, groups)):
X_train_gkf, X_test_gkf = X_train_ce.iloc[train_index], X_train_ce.iloc[test_index]
y_train_gkf, y_test_gkf = y_train.iloc[train_index], y_train.iloc[test_index]
# 学習、推論
lgb_train = lgb.Dataset(X_train_gkf, y_train_gkf)
lgb_test = lgb.Dataset(X_test_gkf, y_test_gkf, reference=lgb_train)
lgb_results = {} # 学習の履歴を入れる入物
study = optuna.create_study()
study.optimize(objective, n_trials=100)
print(study.best_params)
best_params = study.best_params
add_params = {
'objective':'regression',
'metric': 'rmse',
'task': 'train',
'seed': SEED
}
best_params.update(add_params)
print(best_params)
model = lgb.train(
params=best_params, # ハイパーパラメータをセット
train_set=lgb_train, # 訓練データを訓練用にセット
valid_sets=[lgb_train, lgb_test], # 訓練データとテストデータをセット
valid_names=['Train', 'Test'], # データセットの名前をそれぞれ設定
num_boost_round=100, # 計算回数
early_stopping_rounds=50, # アーリーストッピング設定
evals_result=lgb_results,
verbose_eval=-1, # ログを最後の1つだけ表示
)
# 損失推移を表示
loss_train = lgb_results['Train']['rmse']
loss_test = lgb_results['Test']['rmse']
fig = plt.figure()
plt.xlabel('Iteration')
plt.ylabel('logloss')
plt.title(f"fold:{fold}")
plt.plot(loss_train, label='train loss')
plt.plot(loss_test, label='test loss')
plt.legend()
plt.show()
# 推論
y_pred = model.predict(X_test_gkf)
# 評価
rmse = mean_squared_error(y_test_gkf, y_pred, squared=False)
cv_result_opt2.append(rmse)
print("RMSE:", cv_result_opt2)
print("RMSE:", np.mean(cv_result_opt2))
項目 | 指標 | 結果 |
---|---|---|
ハイパラ調整なしのlightGBM | RMSE: | 0.199 |
optuna.integration.lightgbm によるハイパラ調整 |
RMSE: | 0.182 |
Optuna によるハイパラ調整 | RMSE: | 0.177 |
9日目は以上になります、最後までお読みいただきありがとうございました。
Discussion