機械学習などの数理モデルには、通常幾つかのハイパーパラメータがあり、そのハイパーパラメータの設定次第で大きく精度が変わります。
このハイパーパラメータを調整し最適な設定を探すタスクを、ハイパーパラメータチューニングと言います。
前回は、「Optuna のちょっとした使い方」についてお話ししました。
Python の ハイパーパラメータ自動最適化ライブラリー Optuna その1 – Optuna のちょっとした使い方 –
今回は、「Optunaを使うとき最低限覚えておきたい探索範囲の指定方法」についてお話しします。
Contents
主なハイパーパラメータの探索範囲などの指定方法
以下、主なハイパーパラメータの探索範囲などの指定方法です。
- 指定範囲の実数から選ぶ(suggest_float)
- 指定範囲の整数から選ぶ(suggest_int)
- 指定範囲の離散値から選ぶ(suggest_discrete_uniform)
- 指定範囲のカテゴリーから選ぶ(suggest_categorical)
基本、ハイパーパラメータがカテゴリーなのか、実数なのか、整数ないのかで選択すればいいでしょう。
実数や整数などのハイパーパラメータでも、離散値として指定することもできます。
「指定範囲のカテゴリーから選ぶ」方法で一番出番がありそうなのが、複数の数理モデルを検討するときです。この場合のカテゴリーとは、数理モデル名になります。
前回利用した簡単な例を使って説明していきます。
先ずは手順の復習です。
Optuna の手順の復習
Optunaは、目的関数(objective function)を設定し最適化を目指すことでより良いハイパーパラメータの組み合わせを探索します。
以下、ざっくり手順です。
- ステップ1:目的関数を設定する
- 各モデルのハイパーパラメータの集合を定義する
- 良し悪しを判断するメトリクスを定義する
- ステップ2:目的関数の最適化を実行する
- ステップ3:最適解を利用する
ステップ4で試行回数(n_trials)を設定し実行します。試行回数が多いほど時間が掛かりますが、より良い解になる可能性が高くなります。
簡単な例
前回登場した2次関数の最小値を求める例で説明します。
先ず、ライブラリーを読み込みます。
以下、コードです。
# ライブラリーの読み込み import optuna
簡単な例|suggest_float 利用
前回登場した2次関数の最小値を求める例では、実数から選ぶsuggest_float関数を使って、ハイパーパラメータの探索方法を指定しています。
以下、コードです。
# 2次関数 def f(x): return ((x - 3) ** 2) # 目的関数の設定(ステップ1) def objective(trial): x = trial.suggest_float('x', -7, 13) #ハイパーパラメータの集合を定義する return f(x) #良し悪しを判断するメトリクスを返す # 目的関数の最適化を実行する(ステップ2) study = optuna.create_study(direction="minimize") 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}")
以下、実行結果です。
suggest_float('x', -7, 13)
について、簡単に説明します。
suggest_float('x', -7, 13)
は……
-7から13の範囲の
実数から探索する
……ということです。
簡単な例|suggest_int 利用
実数から選ぶsuggest_float関数の代わりに、整数から選ぶsuggest_int関数を使ってみます。
以下、コードです。
# 2次関数 def f(x): return ((x - 3) ** 2) # 目的関数の設定(ステップ1) def objective(trial): x = trial.suggest_int('x', -7, 13) #ハイパーパラメータの集合を定義する return f(x) #良し悪しを判断するメトリクスを返す # 目的関数の最適化を実行する(ステップ2) study = optuna.create_study(direction="minimize") 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}")
以下、実行結果です。
suggest_int('x', -7, 13)
について、簡単に説明します。
suggest_int('x', -7, 13)
は……
-7から13の範囲の
整数から探索する
……ということです。
簡単な例|suggest_discrete_uniform 利用
離散値から選ぶsuggest_discrete_uniform関数を使ってみます。
以下、コードです。
# 2次関数 def f(x): return ((x - 3) ** 2) # 目的関数の設定(ステップ1) def objective(trial): x = trial.suggest_discrete_uniform('x', -5,5,0.1) #ハイパーパラメータの集合を定義する return f(x) #良し悪しを判断するメトリクスを返す # 目的関数の最適化を実行する(ステップ5) study = optuna.create_study(direction="minimize") 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}")
以下、実行結果です。
suggest_discrete_uniform(‘x’,-5,5,0.1)
について、簡単に説明します。
suggest_discrete_uniform(‘x’,-5,5,0.1)
は……
-5から5の範囲の
0.1刻みの離散値の中から探索する
……ということです。
-5から5の範囲の0.1刻みの離散値とは……
-5, -4.9, -4.8, …, 4.9, 5
……です。
簡単な例|suggest_categorical 利用
カテゴリーから選ぶsuggest_categorical関数を使ってみます。
以下、コードです。
# 2次関数 def f(x): return ((x - 3) ** 2) # 目的関数の設定(ステップ1) def objective(trial): x = trial.suggest_categorical('x', [-5,-3,-1,1,3,5]) #ハイパーパラメータの集合を定義する return f(x) #良し悪しを判断するメトリクスを返す # 目的関数の最適化を実行する(ステップ5) study = optuna.create_study(direction="minimize") 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}")
以下、実行結果です。
suggest_categorical(‘x’,[-5,-3,-1,1,3,5])
について、簡単に説明します。
suggest_categorical(‘x’,[-5,-3,-1,1,3,5])
は……
指定した[-5,-3,-1,1,3,5]
の中から探索する
……ということです。
分類問題(乳がんデータ)
前回利用した分類問題(乳がんデータ)の例で、どのように設定したのかを説明します。
以下、前回のコードです。
# 目的関数の設定(ステップ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}")
以下、実行結果です。
構築するモデルを複数設定するために、カテゴリーから選ぶsuggest_categorical関数を使っています。
suggest_categorical("classifier",["LogReg","SVC","RandomForest"])
について、簡単に説明します。
suggest_categorical("classifier",["LogReg","SVC","RandomForest"])
は……
指定した[“LogReg”,”SVC”,”RandomForest”] の中から探索する
……ということです。
以下が、ここで登場している数理モデルです。
- LogReg:ロジスティック回帰
- SVC:サポートベクターマシン
- RandomForest:ランダムフォレスト
それぞれのモデルで実施した、ハイパーパラメータの探索範囲の指定を簡単に説明します。
分類問題(乳がんデータ)|LogReg:ロジスティック回帰
探索指定したハイパーパラメータは以下です。
- logreg_c:正則化の強さの逆数(デフォルトは1)
構築するモデルの正則化の強さを探索するために、実数から選ぶsuggest_float関数を使っています。
suggest_float("logreg_c",1e-10, 1e10,log=True)
について、簡単に説明します。
suggest_float("logreg_c",1e-10, 1e10,log=True)
は……
1e-10から1e10の対数変換された範囲の
実数から探索する
……ということです。
logはデフォルトではlog=Falseです。デフォルト(log=False)では、指定した範囲の中で一様分布に従って探索されます。log=Trueとすると、対数変換された空間で一様分布に従って探索されます。
分類問題(乳がんデータ)|SVC:サポートベクターマシン
探索指定したハイパーパラメータは以下です。
- svc_c:正則化の強さの逆数(デフォルトは1)
先程説明したlogreg_cと、svc_cは基本的に同じです。
suggest_float("svc_c ",1e-10, 1e10,log=True)
は……
1e-10から1e10の対数変換された範囲の
実数から探索する
……ということです。
分類問題(乳がんデータ)|RandomForest:ランダムフォレスト
探索指定したハイパーパラメータは以下です。
- rf_n_estimators:決定木の個数(デフォルトは100)
- rf_max_depth:決定木の深さの最大値(デフォルトはNone)
先ず、rf_n_estimatorsです。
構築するモデルの決定木の個数を選ぶために、整数から選ぶsuggest_int関数を使っています。
suggest_int("rf_n_estimators",10,1000)
について、簡単に説明します。
suggest_int("rf_n_estimators",10,1000)
は……
10から1000の範囲の
整数から探索する
……ということです。
次に、rf_max_depthです。
構築するモデルの決定木の深さの最大値を探索するために、整数から選ぶsuggest_int関数を使っています。
suggest_int("rf_max_depth",2,50,log=True)
について、簡単に説明します。
suggest_int("rf_max_depth",2,50,log=True)
は……
2から50の対数変換された範囲の
整数から探索する
……ということです。
まとめ
今回は、「Optunaを使うとき最低限覚えておきたい探索範囲の指定方法」についてお話ししました。
以下、主なハイパーパラメータの探索範囲などの指定方法です。
- 指定範囲の実数から選ぶ(suggest_float)
- 指定範囲の整数から選ぶ(suggest_int)
- 指定範囲の離散値から選ぶ(suggest_discrete_uniform)
- 指定範囲のカテゴリーから選ぶ(suggest_categorical)
基本、ハイパーパラメータがカテゴリーなのか、実数なのか、整数ないのかで選択すればいいでしょう。
実数や整数などのハイパーパラメータでも、離散値として指定することもできます。
「指定範囲のカテゴリーから選ぶ」方法で一番出番がありそうなのが、複数の数理モデルを検討するときです。この場合のカテゴリーとは、数理モデル名になります。
Python のハイパーパラメータ自動最適化ライブラリー Optunaを使いとき、参考にして頂ければと思います。
Python のハイパーパラメータ自動最適化ライブラリー Optuna その3– scikit-learnのモデルをOptunaでCV(クロスバリデーション)を実施する方法 –