Kaggleで学ぶ機械学習(分類)-ハイパーパラメータチューニング-

Kaggle
黒猫さん
黒猫さん

モデルの精度を上げるにはどうすればいいのかしら。

機械学習モデルの精度向上には特徴量エンジニアリングによる入力データの加工のほかに、
ハイパーパラメータチューニングによる精度改善が期待できます。

今回はハイパーパラメータチューニングによる精度改善をKaggleを通じて学んでいきましょう!

この記事は続編です。前編は以下のURLからご覧ください。

対象コンペ

前回に引き続き“Home Credit Default Risk”コンペになります。

Home Credit Default Risk | Kaggle
Can you predict how capable each applicant is of repaying a loan?

簡単に説明すると…

お金をその人に貸したとき、
  その人がしっかりと返せる人なのか貸し倒れする人なのかを判別するコンペになります。

ハイパーパラメータチューニング

ハイパーパラメータチューニングとは、LigthtGBMのようなアルゴリズムに設定するハイパーパラメータをチューニングすることです。

このハイパーパラメータを調整して最適化をしていくことでモデルとしての予測精度を向上させることができます。

パラメータチューニングの種類

ハイパーパラメータチューニングの種類は大きく分けて以下の2種類があります。

  • 手動チューニング
  • 自動チューニング

手動チューニングは分析者の経験値や勘を頼りにしてハイパーパラメータを手動で調節する方法です。

一方、自動チューニングは専用のライブラリを用いて自動的に適切なパラメータを探索する方法です。

手動チューニングは一回の学習時間が長い場合に有効です。自動チューニングはベストなハイパーパラメータを追及できるため、どんな人にも使えるのがメリットになります。

場合に応じてこれらを使い分ける必要がありそうですが、今回は自動チューニングで最適なパラメータを探索します。

自動チューニングの種類

便利な自動チューニングにも2種類のアプローチが存在します。

  • 値のパターンを指定するアプローチ
  • 値の範囲を指定するアプローチ

値のパターンを指定するアプローチでは、事前に項目ごとにパターンを設定し、その組み合わせの範囲内で探索を行います。全組み合わせを順々に探索するグリッドサーチとランダムに組み合わせを選ぶランダムサーチがあります。

一方、値の範囲を指定するアプローチでは範囲を指定して、その中で最適な値を探索します。ベイズ最適化を活用することで効率的に探索を行えます。

どちらのアプローチもメリットとデメリットが存在します。時と場合に応じて使い分ける必要があります。

今回用いるLightBGMのような勾配ブースティングではハイパーパラメータの数が多く探索範囲が広いため、値の範囲を指定するアプローチであるベイズ最適化が有効です。今回はそのベイズ最適化で探索することができる「Optuna」を用いていきます。

取り扱うデータ

前回に引き続き“application_train.csv”を使用していきます。

# ファイルの読み込み・データ確認
application_train = pd.read_csv("../input/home-credit-default-risk/application_train.csv")
print(application_train.shape)
application_train.head()

optunaによる自動チューニングの実行

ハイパーパラメータの自動チューニングのため、学習用データを準備します。

また、optunaをimportしていない場合はimportします。

import optuna

#学習用のデータセット作成
x_train = df_train.drop(columns=["TARGET", "SK_ID_CURR"])
y_train = df_train["TARGET"]
id_train = df_train[["SK_ID_CURR"]]

for col in x_train.columns:
    if x_train[col].dtype=="O":
        x_train[col] = x_train[col].astype("category")

次に目的関数の定義を行います。ここでは、探索しないハイパーパラメータと探索するハイパーパラメータを設定し、これらを用いてモデル学習して評価値を算出する処理を書きます。先にも書いた通り、値を範囲を指定するアプローチであるため、探索するハイパーパラメータの箇所に値の範囲を指定を記述します。

また、今回は処理高速化のために1つめのfoldのみとします。

#目的関数の定義
# 探索しないハイパーパラメータ
params_base = {
    "boosting_type": "gbdt",
    "objective": "binary",
    "metric": "auc",
    "verbosity": -1,
    "learning_rate": 0.05,
    "n_estimators": 100000,
    "bagging_freq": 1,
    "random_state": 123,
}

# 目的関数の定義
def objective(trial):
    # 探索するハイパーパラメータ
    params_tuning = {
        "num_leaves": trial.suggest_int("num_leaves", 8, 256),
        "min_child_samples": trial.suggest_int("min_child_samples", 5, 200),
        "min_sum_hessian_in_leaf": trial.suggest_float("min_sum_hessian_in_leaf", 1e-5, 1e-2, log=True),
        "feature_fraction": trial.suggest_float("feature_fraction", 0.5, 1.0),
        "bagging_fraction": trial.suggest_float("bagging_fraction", 0.5, 1.0),
        "lambda_l1": trial.suggest_float("lambda_l1", 1e-2, 1e+2, log=True),
        "lambda_l2": trial.suggest_float("lambda_l2", 1e-2, 1e+2, log=True),
    }
    params_tuning.update(params_base)
    
    # モデル学習・評価
    list_metrics = []
    cv = list(StratifiedKFold(n_splits=5, shuffle=True, random_state=123).split(x_train, y_train))
    list_fold = [0]  # 処理高速化のために1つめのfoldのみとする。
    for nfold in list_fold:
        idx_tr, idx_va = cv[nfold][0], cv[nfold][1]
        x_tr, y_tr = x_train.loc[idx_tr, :], y_train[idx_tr]
        x_va, y_va = x_train.loc[idx_va, :], y_train[idx_va]
        model = lgb.LGBMClassifier(**params_tuning)
        model.fit(x_tr,
                  y_tr,
                  eval_set=[(x_tr,y_tr), (x_va,y_va)],
                  early_stopping_rounds=100,
                  verbose=0,
                 )
        y_va_pred = model.predict_proba(x_va)[:,1]
        metric_va = roc_auc_score(y_va, y_va_pred) # 評価指標をAUCにする
        list_metrics.append(metric_va)
    
    # 評価指標の算出
    metrics = np.mean(list_metrics)
    
    return metrics

それでは実際にハイパーパラメータを探索してみましょう。

Kaggle notebook環境でそこそこ時間がかかったので気長に探索が終わるまで待ちましょう。

#最適化処理(探索の実行)
sampler = optuna.samplers.TPESampler(seed=123)
study = optuna.create_study(sampler=sampler, direction="maximize")
study.optimize(objective, n_trials=50, n_jobs=5)

探索したパラメータの確認

自動チューニングが無事に終わったら探索結果を確認してみましょう。

#探索結果の確認
trial = study.best_trial
print("acc(best)={:.4f}".format(trial.value))
display(trial.params)
acc(best)=0.7750
{'num_leaves': 12,
 'min_child_samples': 106,
 'min_sum_hessian_in_leaf': 8.623253649320915e-05,
 'feature_fraction': 0.633612863123612,
 'bagging_fraction': 0.8056982211623093,
 'lambda_l1': 0.04043314263083684,
 'lambda_l2': 6.59894543540371}

 最適なハイパーパラメータが探索できたようです。

おわりに

今回は自動チューニングを試してみましたが、次は手動チューニングで精度向上をしてみたいですね。

タイトルとURLをコピーしました