Python のハイパーパラメータ自動最適化ライブラリー Optuna その3
– scikit-learnのモデルをOptunaでCV(クロスバリデーション)を実施する方法 –

Python のハイパーパラメータ自動最適化ライブラリー Optuna その3– scikit-learnのモデルをOptunaでCV(クロスバリデーション)を実施する方法 –

scikit-learnのモデルをOptunaCV(クロスバリデーション)を実施する方法は2種類あります。

  • 良し悪しを判断するメトリクスにscikit-learnのCVを指定する方法
  • OptunaのCV関数(OptunaSearchCV)を使う方法

前回乳がんの例では、実は「良し悪しを判断するメトリクスにscikit-learnのCVを指定する方法」で実施していました。

Python のハイパーパラメータ自動最適化ライブラリー Optuna その2 – Optunaを使うとき最低限覚えておきたい探索範囲の指定方法 –

最初に前回のコードを振り返り、その後にOptunaCV関数(OptunaSearchCV)を使う方法を紹介します。

先ずは手順の復習です。

Optuna の手順の復習

Optunaは、目的関数(objective function)を設定し最適化を目指すことでより良いハイパーパラメータの組み合わせを探索します。

以下、ざっくり手順です。

  • ステップ1:目的関数を設定する
    • 各モデルのハイパーパラメータの集合を定義する
    • 良し悪しを判断するメトリクスを定義する
  • ステップ2:目的関数の最適化を実行する
  • ステップ3:最適解を利用する

ステップ4で試行回数(n_trials)を設定し実行します。試行回数が多いほど時間が掛かりますが、より良い解になる可能性が高くなります

 

分類問題(乳がんデータ)

前回説明した分類問題(乳がんデータ)の例です。

良し悪しを判断するメトリクスを、どのように設定したのかを見てみます。Step 4のところです(色を変えています)。scikit-learnCV(クロスバリデーション)cross_val_score関数を使っています。

以下、前回のコードです。

# 目的関数の設定(ステップ1)
def objective(trial):

    #ハイパーパラメータの集合を定義する

    ##推定器の集合
    classifier_name = trial.suggest_categorical("classifier", 
                                                ["LogReg",
                                                 "SVC",
                                                 "RandomForest"
                                                ]
                                               )

    ##推定器ごとのハイパーパラメータの集合
    ###ロジ回(LogReg)
    if classifier_name == 'LogReg':
        logreg_c = trial.suggest_float("logreg_c",
                                       1e-10, 1e10, 
                                       log=True
                                      )
        classifier_obj = linear_model.LogisticRegression(C=logreg_c)
    ###サポートベクターマシン(SVC)
    elif classifier_name == "SVC":
        svc_c = trial.suggest_float("svc_c",
                                    1e-10, 1e10,
                                    log=True
                                   )
        classifier_obj = sklearn.svm.SVC(C=svc_c,
                                         gamma="auto"
                                        )
    ###ランダムフォレスト(RandomForest)
    else:
        rf_n_estimators = trial.suggest_int("rf_n_estimators",
                                            10, 1000
                                           )
        rf_max_depth = trial.suggest_int("rf_max_depth", 
                                         2, 50,
                                         log=True
                                        )
        classifier_obj = ensemble.RandomForestClassifier(
            max_depth=rf_max_depth,
            n_estimators=rf_n_estimators
        )

    #良し悪しを判断するメトリクスを定義する
    ##CVの実施
    score = model_selection.cross_val_score(classifier_obj,
                                            X,
                                            y,
                                            n_jobs=-1,
                                            cv=10
                                           )
    ##CVの結果の平均値
    accuracy = score.mean()
    return accuracy

# 目的関数の最適化を実行する(ステップ2)
study = optuna.create_study(direction="maximize")
study.optimize(objective, n_trials=100)

# 最適解の出力
print(f"The best value is : \n {study.best_value}")
print(f"The best parameters are : \n {study.best_params}")

 

以下、実行結果です。

 

最良なモデルランダムフォレストです。

 

次に、このランダムフォレストに対し、OptunaCV関数(OptunaSearchCV)を使い、CV(クロスバリデーション)を実施してみたいと思いますが……

……ただ、先程の例ではロジスティック回帰SVMランダムフォレスト3つのアルゴリズム(数理モデル)を対象にしているため、OptunaのCV関数(OptunaSearchCV)を使った例と見比べるとき、やや面倒です。

 

そのため、ランダムフォレストのみに対し、scikit-learnのCVの関数(model_selection.cross_val_score)を指定するコード例を示します。

以下、コードです。

# ライブラリーの読み込み
import optuna
import pandas as pd
import sklearn.svm
from sklearn import linear_model
from sklearn import ensemble
from sklearn import datasets
from sklearn import model_selection

# サンプルデータの読み込み(乳がんデータ)
X,y = datasets.load_breast_cancer(return_X_y=True, as_frame=True)

# 目的関数の設定(ステップ1)
def objective(trial):
    
    #ハイパーパラメータの集合を定義する
    model = ensemble.RandomForestClassifier()

    params = {"n_estimators":trial.suggest_int("n_estimators",
                                               10,1000
                                              ),
              "max_depth":trial.suggest_int("max_depth",
                                            2, 50,
                                            log=True
                                           )
             }
    classifier_obj = model.set_params(**params)

    #良し悪しを判断するメトリクスを定義する
    score = model_selection.cross_val_score(classifier_obj,
                                            X,
                                            y,
                                            n_jobs=-1,
                                            cv=10
                                           )
    accuracy = score.mean()
    return accuracy

# 目的関数の最適化を実行する(ステップ2)
study = optuna.create_study(direction="maximize")
study.optimize(objective, n_trials=100)

# 最適解の出力
print(f"The best value is : \n {study.best_value}")
print(f"The best parameters are : \n {study.best_params}")

 

以下、実行結果です。

 

OptunaのCV関数(OptunaSearchCV)を使う方法

Optunaで、scikit-learnのモデルをCV(クロスバリデーション)を実施するとき、OptunaSearchCVを使っても実施できます。

今回は、ランダムフォレストで実施してみます。

簡単な流れは以下です。

  1. モデル設定
  2. ハイパーパラメータ探索の設定
  3. CV(クロスバリデーション)の設定
  4. ハイパーパラメータの探索の実施
  5. 最適解の出力

 

先ず、モデルの設定です。ランダムフォレストです。

以下、コードです。

# ライブラリーの読み込み
import optuna
import pandas as pd

from sklearn import ensemble
from sklearn import datasets

# サンプルデータの読み込み(乳がんデータ)
X,y = datasets.load_breast_cancer(return_X_y=True, as_frame=True)

# モデル設定
model = ensemble.RandomForestClassifier()

 

次に、ハイパーパラメータ探索の設定です。

OptunaSearchCVでは、param_distributions引数を使用してハイパーパラメータの探索空間を定義します。

通常の設定時(前回)とは異なる関数を使って行いますが、やっていることはほぼ同じす。

  • optuna.distributions.FloatDistribution実数値の範囲を指定するための分布。一様分布や対数一様分布などを選択可能。
  • optuna.distributions.IntDistribution整数値の範囲を指定するための分布。
  • optuna.distributions.CategoricalDistribution:カテゴリ変数のサンプリング。

 

以下、コードです。

# ハイパーパラメータの探索の設定
params = {
    "n_estimators":optuna.distributions.IntDistribution(10,1000),
    "max_depth":optuna.distributions.IntDistribution(2,50,log=True)
}

 

CV(クロスバリデーション)の設定をします。

以下、コードです。

# CV(クロスバリデーション)の設定
optuna_search = optuna.integration.OptunaSearchCV(model,
                                                  params,
                                                  cv=10,
                                                  n_jobs=-1,
                                                  n_trials=100,
                                                  scoring='accuracy'
                                                 )

 

では、CVで評価しながらハイパーパラメータの探索を実施します。

以下、コードです。

# ハイパーパラメータの探索の実施
optuna_search.fit(X, y)

 

結果を見てみます。

以下、コードです。

# 最適解の出力
print(f"The best value is : \n {optuna_search.best_score_}")
print(f"The best parameters are : \n {optuna_search.best_params_}")

 

以下、実行結果です。

 

まとめ

scikit-learnのモデルをOptunaCV(クロスバリデーション)を実施する方法は2種類あります。

  • 良し悪しを判断するメトリクスにscikit-learnのCVを指定する方法
  • OptunaのCV関数(OptunaSearchCV)を使う方法

今回は、前回の乳がんの例の分類問題に対し、OptunaCV関数(OptunaSearchCV)を使う方法を紹介しました。

非常に手軽にできますので、興味ある方は一度チャレンジしてみてください。

Python のハイパーパラメータ自動最適化ライブラリー Optuna その4 – 時系列Facebook ProphetモデルをOptunaで自動最適化 –