🦁

ハイパーパラメータのチューニング 【グリッドサーチの欠点とそれを補う手法を解説】

2020/11/03に公開

こんにちは。ヤギユキ(@yagiyuki06)です。

今回は、機械学習のハイパーパラメータのチューニング方法3つをサンプルコード付きで解説していきます。
機械学習のハイパーパラメータのチューニング方法の参考になれば幸いです。

ハイパーパラメータのチューニング方法の王道は?

ずばり、グリッドサーチです。
指定されたパラメーターの候補を網羅的に検索して、ベストな精度が出るパラメータを選択する手法になります。

例:3つのハイパーパラメータををチューニングする場合

ハイパーパラメータAの候補:1, 10
ハイパーパラメータBの候補:2, 4, 8, 16
ハイパーパラメータCの候補:256
全通りの組み合わせで探索して、最も精度が高い組み合わせを選択する。

ハイパーパラメータA ハイパーパラメータB ハイパーパラメータC
組み合わせ1 1 2 256
組み合わせ2 1 4 256
組み合わせ3 1 8 256
組み合わせ4 1 16 256
組み合わせ5 10 2 256
組み合わせ6 10 4 256
組み合わせ7 10 8 256
組み合わせ8 10 16 256

グリッドサーチによる探索

実際にグリッドサーチによるパラメータのサンプルを実装したうえで解説してきます。
検証ライブラリはscikit-learn、検証データはscikit-learnで提供されている癌の判定データを使います。

from sklearn.datasets import load_breast_cancer
import pandas as pd
from sklearn.model_selection import GridSearchCV
from sklearn.linear_model import LogisticRegression

# 検証データの取得(癌の判定データ)
data = load_breast_cancer()
dataX = pd.DataFrame(data=data.data,columns=data.feature_names)
dataY = pd.DataFrame(data=data.target)
dataY = dataY.rename(columns={0: 'class'})


# データの分割を行う(訓練用データ 0.8 評価用データ 0.2)
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(dataX, dataY, test_size=0.2)

# 探索対象のパラメータを指定
param_grid = {
    "penalty": ["l2",  "none"], 
    "C": [i / 10 for i in range(3, 20, 2)],  # out -> [0.3, 0.5, 0.7, 0.9, 1.1, 1.3, 1.5, 1.7, 1.9]
    "solver":["newton-cg", "sag", "saga", "lbfgs"],
    "max_iter": list(range(10, 101, 10)) # out -> [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
}

# グリッドサーチのインスタンスを作成
gscv = GridSearchCV(estimator=LogisticRegression(), param_grid=param_grid, cv=5)

# パラメータ探索
gscv.fit(X_train, y_train)

# 最も精度が高いパラメータで学習した分類器
b_estimator = gscv.best_estimator_

# 精度
print(b_estimator.score(X_test, y_test)) # out -> 0.9824561403508771 

param_gridで指定したハイパーパラメータの組み合わせを試していき、一番精度が高いハイパーパラメータの組み合わせで学習した分類器b_estimatorを出力します。
検証結果は、以下の通りです。

ランダムサーチによる探索

グリッドサーチは、指定したパラメータの組み合わせを網羅的に探索するので、最も高い精度が出るパラメータを確実に見つけ出すことができます。
反面、網羅的に探索する分、処理に時間がかかります。

探索時間を削減する1つの手法としてあげられるのが、ランダムサーチです。
グリッドサーチとの違いは、指定したパラメータの組み合わせの探索回数の有無です。

# ※ここより前の処理はグリッドサーチと同様

from sklearn.model_selection import RandomizedSearchCV

# ランダムサーチのインスタンスを作成 (探索回数は、30)
rscv = RandomizedSearchCV(estimator=LogisticRegression(), param_grid=param_grid, cv=5, n_iter=30)

# パラメータ探索
rscv.fit(X_train, y_train)

# 最も精度が高いパラメータで学習した分類器
b_estimator = gscv.best_estimator_

# 精度
print(b_estimator.score(X_test, y_test)) # out -> 0.9807017543859647

探索回数の指定がある分、探索時間が短くなります。
探索回数を小さくすればするほど、探索時間は短くなりますが、回数が減る分だけベストなパラメータを見つけられる確率が減ります。

探索回数を30で検証したところ、以下の通りになりました。

※ 探索速度・精度は、同じ条件での探索を10回実施した平均値を測定
若干精度がグリッドサーチより劣っていますが、探索時間はグリッドサーチより断然早くなりました。

ベイズ最適化による探索

ランダムサーチは、指定した最大回数の範囲でランダムにパラメータを選択して探索する手法でした。
それに対して、ベイズ最適化は、指定した最大回数の範囲でランダムにパラメータを選択するのではなく、どのパラメータが精度が出やすいかを自動で判断して選択してくれます。

# ※ここより前の処理はグリッドサーチと同様

from skopt import BayesSearchCV

# ベイズ最適化のインスタンスを作成 (探索回数は、30)
bscv = BayesSearchCV(estimator=LogisticRegression(), param_grid=param_grid, cv=5, n_iter=30)

# パラメータ探索
bscv.fit(X_train, y_train)

# 最も精度が高いパラメータで学習した分類器
b_estimator = gscv.best_estimator_

# 精度
print(b_estimator.score(X_test, y_test)) # out -> 0.9824561403508769

検証結果は、以下の通りです。

※ 探索速度・精度は、同じ条件での探索を10回実施した平均値を測定

探索時間はグリッドサーチの1/3程度で、精度もグリッドサーチと遜色ないレベルで出ています。

3つの手法のまとめ

ハイパーパラメータのチューニング方法として3つの手法を紹介しました。
検証結果をまとめると以下のようになりました。

グリッドサーチ

  • 探索時間: 2分13秒
  • 精度: 0.9824561403508771

ランダムサーチ

  • 探索時間: 5.3秒
  • 精度: 0.9807017543859647

ベイズ最適化

  • 探索時間: 44.2秒
  • 精度: 0.9824561403508769

結局、どれを使えばよいのか?

私個人としては、迷ったらグリッドサーチをおすすめします。
一番無難で確実な手法だからです。
ただし、アルゴリズムやパラメータの探索範囲によっては、探索に時間がかかり現実的ではない可能性があります。
その場合は、他の2つの手法を試してみるのがよいでしょう。
サンプルコードを見ればわかると思いますが、他の2つの手法のインタフェースはグリッドサーチと同じなので、グリッドサーチをマスターすればすぐに差し替え可能です。

以上になります。
パラメータチューニングの手法を選択する参考になれば幸いです。

Discussion