パラメータはモデルの学習実行後に得られる値で、重みとも呼ばれます。
対してハイパーパラメータは各アルゴリズムに付随して、アルゴリズムの挙動を制御するための値です。
ハイパーパラメータを調整することで、っモデルの性能向上や過学習の抑制、効率の良い学習などが期待できます。
1. K-分割交差検証 (K-fold cross-validation)
与えられたデータセットを「学習用データセット」「テスト用データセット」に2分割することをホールドアウト法と呼びます。
ホールドアウト法では、ハイパーパラメータの調整に使うデータがありませんので、ハイパーパラメータを調整するためには「検証用データセット」を用意する必要があります。
しかし、3分割するほどデータ量がないこともあります。
その時に使うのが、**K-分割交差検証 (K-fold cross-validation)**です。
【手順】
1.データセットをK個に分割
2.分割したデータの1個を検証用データセットとし、残りK-1個を学習用データセットとして学習を実行
→ 1 回で学習を終わらせず、計K回の学習を行います。その際、既に検証用データセットに使ったデータを次は学習用データセットとして使用し、新たに検証用データセットを選択します。
3.各検証の結果を平均して最終的な検証結果とする
2. ハイパーパラメータの調整方法
ハイパーパラメータの調整するには、以下のような方法があります。
1.手動での調整
2.グリッドサーチ (Grid Search)
3.ランダムサーチ (Random Search)
4.ベイズ最適化 (Bayesian Optimization)
2-1. 手動での調整
DecisionTreeClassifier
で決定木の実装を行う場合を考えます。
from sklearn.tree import DecisionTreeClassifier
# ハイパーパラメータ調整なし
dtree = DecisionTreeClassifier(random_state=0)
# ハイパーパラメータ調整あり
dtree2 = DecisionTreeClassifier(max_depth=10, min_samples_split=30, random_state=0)
このように、max_depth
やmin_samples_split
について、自分で適当に値を入れて、数値を変えるたびに予測精度を確認するという方法が、手動での調整です。
2-2. グリッドサーチ (Grid Search)
グリッドサーチはまず、ハイパーパラメータを探索する範囲を決めます。
例えば上記のように決定木のmax_depth
とmin_samples_split
の値を調整したい場合、5、10、15、20、25 のように範囲をそれぞれ決めます(範囲の指定に特に決まりはありません)。
この場合のハイパーパラメータの組み合わせは 5x5=25 個になります。
この25個のハイパーパラメータの組み合わせ全てを使用して、学習・検証を行います。
そして、その結果から予測精度が最も高いハイパーパラメータを採用します。
グリッドサーチには以下の3つを準備する必要があります。
- estimator : 学習に使用するモデル
- param_grid : ハイパーパラメータを探索する範囲
- cv : K-分割交差検証のKの値
# GridSearchCV クラスのインポート
from sklearn.model_selection import GridSearchCV
# 学習に使用するアルゴリズムの定義
estimator = DecisionTreeClassifier(random_state=0)
# 探索するハイパーパラメータと範囲の定義
param_grid = [{
'max_depth': [3, 20, 50],
'min_samples_split': [3, 20, 30]
}]
# データセット分割数を定義
cv = 5
# GridSearchCV クラスを用いたモデルの定義
tuned_model = GridSearchCV(estimator=estimator,
param_grid=param_grid,
cv=cv, return_train_score=False)
# モデルの学習&検証
tuned_model.fit(x_train_val, t_train_val)
# 検証結果の確認
pd.DataFrame(tuned_model.cv_results_).T
ここまで入力すると、それぞれのハイパーパラメータの値に対する予測精度などが表になって出力されます。
mean_test_score
の値を見ると、モデルの予測精度がわかります。
その後、結果を参照して先ほどより狭い範囲でハイパーパラメータを調整します。
これを何度か繰り返すことで徐々に予測精度が高くなるハイパーパラメータへと近づけて行きます。
# 最も予測精度の高かったハイパーパラメータの確認
tuned_model.best_params_
# 最も予測精度の高かったモデルの引き継ぎ
best_model = tuned_model.best_estimator_
# モデルの検証
print(best_model.score(x_train_val, t_train_val))
print(best_model.score(x_test, t_test))
これで、最も予測精度が高かったハイパーパラメータのモデルで検証することができます。
2-3. ランダムサーチ (Random Search)
ランダムサーチは指定した範囲のハイパーパラメータをランダムに抽出し、学習・検証を行います。
グリッドサーチに比べて、より広い範囲を探索することができるので、効率的と言われています。
しかし、全てのハイパーパラメータを探索するわけではないので、本当に最適か判断が難しいと言えます。
ランダムサーチで大体のあたりをつけてから、グリッドサーチで細かく見ていくやり方だと双方のメリットが活かせます。
# RandomizedSearchCV クラスのインポート
from sklearn.model_selection import RandomizedSearchCV
# 学習に使用するアルゴリズム
estimator = DecisionTreeClassifier(random_state=0)
# ハイパーパラメータを探索する範囲の指定 range(開始値, 終了値, ステップ)
# 例えば range(1, 10, 2) の場合、1から10までの値を2刻みで獲得できる。その値をlist()でリスト化。
param_distributions = {
'max_depth': list(range(5, 100, 2)),
'min_samples_split': list(range(2, 50, 1))
}
# 試行回数の指定
n_iter = 100
# Kの値を指定
cv = 5
# モデルの定義
tuned_model = RandomizedSearchCV(
estimator=estimator,
param_distributions=param_distributions,
n_iter=n_iter, cv=cv,
random_state=0, return_train_score=False
)
# モデルの学習&検証
tuned_model.fit(x_train_val, t_train_val)
# 学習結果の確認(スコアの高い順に表示)
pd.DataFrame(tuned_model.cv_results_).sort_values('rank_test_score').T
ここまで入力すると、それぞれのハイパーパラメータの値に対する予測精度などが表になって出力されます。
# 最も予測精度の高かったハイパーパラメータの確認
tuned_model.best_params_
# 最も予測精度の高かったモデルの引き継ぎ
best_model = tuned_model.best_estimator_
# モデルの検証
print(best_model.score(x_train_val, t_train_val))
print(best_model.score(x_test, t_test))
2-4. ベイズ最適化 (Bayesian Optimization)
数学的背景の理解が難しいのですが、ベイズ最適化では探索(この辺かな〜?と適当に入力してみる)や活用(結果をもとに、さらにこの辺かな〜?と値を更新する)で得られた情報を元にハイパーパラメータを調整していくため、予測精度が高くなるハイパーパラメータを見つけやすいそうです。
日本の Prefferd Networks 社が開発している Optuna というフレームワークを使用するときの方法を記述します。
# optuna のインストール
!pip install optuna
import optuna
Optunaでは最初に関数objective
を定義して内部に以下の要素を関数として順に定義します。
- 1.ハイパーパラメータごとに探索範囲を指定
- 2.学習に使用するアルゴリズムを指定
- 3.学習の実行、検証結果の表示
探索範囲の指定にはデフォルトで準備されているtrial
クラスを使用します。
3では学習・検証を繰り返してハイパーパラメータの調整を行うのですが、その際にreturn
で取得した検証結果を最小化(最大化)するように調整が進みます。
また、3でK-分割交差検証を使用するにはcross_val_score
が必要です。
from sklearn.model_selection import cross_val_score
def objective(trial, x, t, cv):
# 1. ハイパーパラメータごとに探索範囲を指定
max_depth = trial.suggest_int('max_depth', 2, 100)
min_samples_split = trial.suggest_int('min_samples_split', 2, 100)
# 2. 学習に使用するアルゴリズムを指定
estimator = DecisionTreeClassifier(
max_depth = max_depth,
min_samples_split = min_samples_split
)
# 3. 学習の実行、検証結果の表示
print('Current_params : ', trial.params)
accuracy = cross_val_score(estimator, x, t, cv=cv).mean()
return accuracy
正解率の最大化を目的とする場合には、direction='maximize' を指定します。
# studyオブジェクトの作成(最大化)
study = optuna.create_study(direction='maximize')
# K分割交差検証の K
cv = 5
# 目的関数の最適化
study.optimize(lambda trial: objective(trial, x_train_val, t_train_val, cv), n_trials=10)
print(study.best_trial)
学習が終了したので、最も予測精度の高かったハイパーパラメータを確認するためにstudy.best_params
を実行します。
# 最も予測精度の高かったハイパーパラメータの確認
study.best_params
# 最適なハイパーパラメータを設定したモデルの定義
best_model = DecisionTreeClassifier(**study.best_params)
# モデルの学習
best_model.fit(x_train_val, t_train_val)
# モデルの検証
print(best_model.score(x_train_val, t_train_val))
print(best_model.score(x_test, t_test))