グリッドサーチ・ランダムサーチによるパラメータチューニング



前回の記事では、ロジスティック回帰のハイパーパラメータをいくつか紹介しました。
しかし、これら全てのハイパーパラメータを都度変えて、結果を確認するのは時間と手間がかかります。これはロジスティック回帰に関わらず、どの機械学習モデルでも同じです。

https://qiita.com/setowatson/items/8f0536f70fe22fb1664a


今回はハイパーパラメータの範囲を指定して、
精度の良いハイパーパラメータセットを計算機に見つけてもらうという方法を使います。 
方法は、「グリッドサーチ」と「ランダムサーチ」の2つがあります。

以下で実装していきます。
使用するモデル、データセットは以下の通りです。

- モデル
    - サポートベクターマシーン（SVC）
- データセット
    - Digits 0~9の手書き数字画像（正確には画像ではなく数値の配列）
    - レコード数1797件
    - 説明変数64個


## 1. グリッドサーチ

グリッドサーチは、
「調整したいハイパーパラメータの値の候補を、明示的に複数指定すること」で、
ハイパーパラメーターセットを作成します。
モデルの評価を繰り返すことにより、最適なハイパーパラメータセットを作成するのですね。

グリッドサーチは、特に「文字列や整数のような、数学的に連続ではない値をとるハイパーパラメータの探索」に向いています。
ただし、ハイパーパラメータの候補を網羅するようにセットを作成するため、多数のハイパーパラメータを同時にチューニングすることには不向きです。

コードは以下のようになります。 

```ruby:グリッドサーチの使用.py
#ライブラリのインポート
import scipy.stats
from sklearn.datasets import load_digits
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# データセットdigitsを使用
data = load_digits()
train_X, test_X, train_y, test_y = train_test_split(data.data, data.target, random_state=42)

# モデルにはSVCを使用
# 今回サーチするパラメータは"kernel","C","decision_function_shape"の３種類
# ハイパーパラメータの値の"候補"を設定
model_param_set_grid = {SVC(): {"kernel": ["linear", "poly", "rbf", "sigmoid"],
                                "C": [10 ** i for i in range(-5, 5)],
                                "decision_function_shape": ["ovr", "ovo"],
                                "random_state": [42]}}
              
max_score = 0
best_param = None

# グリッドサーチでハイパーパラメータのセットを探索
for model, param in model_param_set_grid.items():
    clf = GridSearchCV(model, param)
    clf.fit(train_X, train_y)
    pred_y = clf.predict(test_X)
    score = accuracy_score(test_y, pred_y)
    if max_score < score:
        max_score = score
        best_param = clf.best_params_
                        
print("ハイパーパラメータ:{}".format(best_param))
print("ベストスコア:",max_score)
svm = SVC()
svm.fit(train_X, train_y)
print()
print('調整なし')
print(svm.score(test_X, test_y))

>>> 出力結果

ハイパーパラメーター:{'C': 10, 'decision_function_shape': 'ovr', 'kernel': 'rbf', 'random_state': 42}
ベストスコア: 0.9888888888888889
調整なし
0.9866666666666667

```


## 2. ランダムサーチ

グリッドサーチは値の候補を指定して、その上でハイパーパラメーターを調整しました。

ランダムサーチは、
ハイパーパラメーターが取りうる値の"範囲"を指定し、
確率で決定されたハイパーパラメーターセットを用いてモデルの評価を行うことを繰り返すことで、最適なハイパーパラメーターセットを探す方法です。

値の範囲は、ハイパーパラメーターの確率関数を指定します。 
ハイパーパラメーターの確率関数として、scipy.statsモジュールがよく用いられます。

コードは以下の通りです。

```ruby:ランダムサーチの使用.py

#ライブラリとデータセットのインポートまでは上記グリッドサーチと同じ

# モデルにはSVCを使用
# 今回サーチするパラメータは"kernel","C","decision_function_shape"の３種類
# ハイパーパラメーターの値の"範囲"を設定
model_param_set_random =  {SVC(): {
        "kernel": ["linear", "poly", "rbf", "sigmoid"],
        "C": scipy.stats.uniform(0.00001, 1000),
        "decision_function_shape": ["ovr", "ovo"],
        "random_state": [42]}}

max_score = 0
best_param = None

# ランダムサーチでハイパーパラメーターを探索
for model, param in model_param_set_random.items():
    clf = RandomizedSearchCV(model, param)
    clf.fit(train_X, train_y)
    pred_y = clf.predict(test_X)
    score = accuracy_score(test_y, pred_y)
    if max_score < score:
        max_score = score
        best_param = clf.best_params_
        
print("ハイパーパラメーター:{}".format(best_param))
print("ベストスコア:",max_score)
svm = SVC()
svm.fit(train_X, train_y)
print()
print('調整なし')
print(svm.score(test_X, test_y))

>>> 出力結果

ハイパーパラメーター:{'C': 54.92474589653124, 'decision_function_shape': 'ovo', 'kernel': 'rbf', 'random_state': 42}
ベストスコア: 0.9888888888888889
調整なし
0.9866666666666667

```

## 3.ベイズ最適化（ガウス関数）

ベイズ最適化は、ある関数の最小値または最大値を「回帰モデルであるガウス過程回帰を利用して求める手法」です。
このベイズ最適化が、ハイパーパラメータの探索アルゴリズムに利用されることもあります。

ハイパーパラメータの探索で利用される場合、最初の探索ではパラメータ候補をランダムに指定しその精度を求めます。
次に、ランダムに指定して求めた精度をもとに、より精度が高くなる可能性のある組み合わせ候補を見つけてその精度を計算します。

いくつか調べてコードも書こうと思ってのですが、
今の私の知識では、とてもではないですが難しい内容でしたので、今回は省略したいと思います。
わかりやすく説明されている記事もございましたので、こちらの共有のみ。


https://qiita.com/meltyyyyy/items/5a058ecc81e010876a39

https://qiita.com/yotapoon/items/294b258648facb285780