BayesSearchCV で XGBoost の early stopping 機能を使う

BayesSearchCV で XGBoost の early stopping 機能を使う

先日の BayesSearchCV イントロダクションの続きです。

XGBoost には early stopping という、

学習データとは別に、テストデータの Validation error が少なくとも <early_stopping_rounds> 回数連続して減少しないと、学習を停止する。

という機能があります。

early stopping は過学習を防ぐ学習方法として XGBoost だけでなく DeepNeuralNetwork でもよく使われる手法です。 端的にいうと、学習データだけではなくテストデータの Validation Error もモニタリングし、学習エラー(bias)と検証エラー(variance)のトレードオフが起きるところで学習を早期に終了させ、過学習を防ぐというものです。

注意すべきは、これは学習実行時のパラメータであり、いわゆるハイパーパラメータではないというところです。

というところで、sklearn では学習実行時のパラメータは fit_params という形で estimator.fit(X, y, **fit_params) の引数として学習実行時に指定されます。 (対してハイパーパラメータは GridSearch の search_param に引き渡されます)

BayesSearchCV でも学習実行時のパラメータを指定できますが、fit の引数ではなく、コンストラクタにて search_param と同様に引数で fit_params を与えます。

サンプルコードになります。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
import numpy as np
import scipy as sp
import pandas as pd
from skopt import BayesSearchCV
from skopt.space import Real, Categorical, Integer
from sklearn.model_selection import train_test_split
import xgboost as xgb


# データセットを読み込み
from sklearn.datasets import load_breast_cancer
X, y = load_breast_cancer(return_X_y=True)

X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.75, random_state=0)

estimator = xgb.XGBClassifier(
    booster='gbtree',
    silent=True,
    objective='binary:logistic',
    base_score=0.5,
    eval_metric='auc',
    n_jobs=-1
)

# Early Stopping のパラメータ設定
# eval_set に モニタリングするテストデータ・セットを設定
# early_stopping_rounds 回数メトリクスが減少(増加)しなければ学習を早期終了する
# eval_metric モニタリングする指標 - 最小化(RMSE, log loss, etc.) あるいは最大化(MAP, NDCG, AUC)は自動的に選ばれる
fit_params =  {
    'early_stopping_rounds': 5,
    'eval_metric':'error',
    'verbose':1,
    'eval_set':[[X_test, y_test]]
}

# パラメータ探索範囲設定
from skopt.space import Real, Categorical, Integer
param_grid = {
    'n_estimators': Integer(1, 4),
    'learning_rate': Real(0.01, 0.5, 'log-uniform'),
    'max_depth': Integer(0, 3)
}

clf = BayesSearchCV(
    estimator=estimator,
    search_spaces=param_grid,
    scoring='roc_auc',
    cv=3,
    n_jobs=-1,
    n_iter=10,
    verbose=1,
    refit=True,
    fit_params=fit_params # コンストラクタで設定すると estimator のフィッティング実行時に渡されます
)
def status_print(optim_result):
    '''
    ベイズ最適化のイテレーションで呼ばれるコールバック
    '''
    results    = pd.DataFrame(clf.cv_results_)
    new_params = results.tail(1).params.values[0]
    new_score  = results.tail(1).mean_test_score
    print('Model #%d/%d : ROC-AUC(newest/best) = %.4f / %.4f' % (
        len(results),
        clf.n_iter,
        new_score,
        clf.best_score_
    ))

# BayesSearchCV は sklearn の他の交差検証サーチ系クラス(RandomSearchCVなど)と同じAPIを持っています
clf.fit(X, y, callback=status_print)

print(pd.DataFrame(clf.cv_results_))

# 検証データのパフォーマンス
print(clf.score(X_test, y_test))

以上、Tips でした。