
以前の記事にParameter gridを利用したパラメータチューニングについてご紹介しましたが、そもそも各Parameterのrangeはどう試した方が良いの?という疑問になるかと思います。
今回はParameter rangeをBaselineとなる基本モデル(全てデフォルトのパラメータ)を作成し、それから探索していく方法についてご紹介します。パラメータチューニングには主にManual search、Grid search、Random search、Bayesian optimizationなどの方法があります。
- Manual search
- 経験や直感・知られている知識などで直接検証する方法
- 短時間で検証ができるというメリットがありますが、直感に依存してしまうというリスクあり
- 試す範囲は広くないため、実際に最適であるかという疑問に保証はできない - Grid search
- Manual searchより広範囲の均等な探索が可能
- 全ての組み合わせの中でcross-validation結果がよかった方を選ぶ方法
- 決めた探索区間から性能を評価し、最適な区間を探しますが、区間の設定には人手が必要
- パラメータの組み合わせが多いほど膨大な時間がかかる - Random search
- Grid searchとは類似していますが、探索区間のParameter rangeをrandom samplingで選定するのが違いです
- Grid searchより早い探索ができるメリットがありますが、rangeのrandomな観測のため、確率的な探索であります - Bayesian optimization
- input(x)から未知の目的関数(f(x))を想定し、最適な値を探すことが目的
- 順次的なparameterのアップデート・評価を行いながら最適なパラメータの組み合わせを探索
- parameter rangeの設定には人手が必要
上記のような手法がありますが、経験豊富な人が直感で最適化するManual searchが効率が良い場合があれば、Random searchが良い場合があるなど、何がベストと決めることは難しいと思うため、それぞれ試しながら特徴をキャッチした上で活用してみることをおすすめします。以前の記事でGrid searchの入門編はありましたが、今回は人手が必要となるParameter rangeの探索方法をご紹介します。
パラメータチューニングでは単一もしくは複数パラメータの入力したrangeから組み合わせの探索が行われますが、そもそもrangeに何を入力すれば良いの?と思いますよね。広すぎるrangeを試そうとすると時間がかかりすぎるため、事前にbaselineからある程度探索する方法をご紹介します。
単一パラメータのみの場合は最適なrangeを探すのは判断しやすいと言えますが、実は複数のパラメータを最適化する場合が多いため、なるべく幅をもって組み合わせを試す必要があります。何も知らない状態では手が出せないため、何も変更のないデフォルトparameterのbaselineモデルからの探索は最初の幅の選定で役に立つと思います。
サンプルのGradientBoostingモデルでのParameterのrangeを決めてみる例で流れを確認してみましょう。GradientBoostingClassifier()のbaselineで、ある予測を行う際のscoreを評価してみます。今回はn_estimators、max_depth、learning_rateの3つのパラメータについて探索してみます。
サンプルコード
from numpy import mean
from numpy import std
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import GradientBoostingClassifier
from matplotlib import pyplot
import pandas as pd
from pytd import pandas_td as td
# pytdの必要な情報
# td_api_key: TD apikey入力
# end_point: TD環境に合わせてhttps://api.treasuredata.co.jp or https://api.treasuredata.comを入力
# dbname: DB名入力
con = td.Client(apikey=td_api_key, endpoint=end_point)
presto = td.create_engine('presto:{}'.format(dbname), con=con)
database = dbname
# TDからデータロード
model_sample = td.read_td_query('''
SELECT * FROM sample_dataset
''', engine=presto)
# modelとparameterごと試すrange設定
# max_depth
def get_max_depth():
models = dict()
# 以下で幅を設定。3から10, NoneはMax
depths = [int(x) for x in np.linspace(3, 10, num = 8)] + [None]
for n in depths:
models[str(n)] = GradientBoostingClassifier(max_depth=n)
return models
# n_estimators
def get_n_estimators():
models = dict()
# 以下で幅を設定。10~500の範囲で10個
n_est = [int(x) for x in np.linspace(10, 500, num = 10)]
for n in n_est:
models[str(n)] = GradientBoostingClassifier(n_estimators=n)
return models
#learning_rate
def get_learning_rate():
rates = dict()
# 以下で幅を設定。0.01~0.3
depths = [float(x) for x in [0.01,0.05,0.1,0.15,0.2,0.25,0.3]]
for n in rates:
models[str(n)] = GradientBoostingClassifier(learning_rate=n)
return models
# cross-validationを使ってモデルの評価
def evaluate_model(model, X, y):
# 評価の結果をreturn
scores = cross_val_score(model, X, y, scoring='accuracy', cv=3, n_jobs=-1)
return scores
# sampleデータ
# モデルで試したいデータで以下のX,yを指定(Cross-validationあり)
X, y = model_sample.iloc[:,2:-1].values, model_sample.iloc[:,-1].values
############ 以下から実行部分、notebookなどで試しながら実行することをおすすめします####
# 上記の関数を修正することで他のパラメータも試せます。
models = get_n_estimators()
#models = get_max_depth()
#models = get_learning_rate()
# CV込みで評価実施、scoreの格納
results, names = list(), list()
for name, model in models.items():
# モデル評価
scores = evaluate_model(model, X, y)
# 結果保存
results.append(scores)
names.append(name)
# 評価結果の出力
print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores)))
#可視化
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()
n_estimators
weak learnerの数です。数が多いほど一定レベルまでの性能が上がったりしますが、多いと処理時間が長くなってしまいます。
とりあえず、10から500まで10個のrangeで試しました。精度に大きな差はありませんが、50から150に絞ってもう一度確認してみるのが良さそうですね。
50から150で確認した結果となります。これでn_estimatorsは[50,100]を候補にします。デフォルト[100]でも問題なさそうですね。
max_depth
個別estimatorの深さです、デフォルトは3です。データによって適切な調整とパフォーマンスは比例します。
None(Max)より指定した方が良さそうですね。精度に大きな差はないため、3から6までなどを候補にしてみるのもいいと思います。
learning_rate
学習率で0~1までの値でデフォルトは0.1です。小さすぎると最適な値を探す前に学習が終わる可能性があります。n_estimatorsとtrade-offであるため、適切に調整することをおすすめします。
0.05から0.2のrangeで候補にしてみるのはいいと思います。n_estimatorsと相互影響しているため、それも考慮した広めのrangeが良いと思います。
以上を目安で次のステップの組み合わせを試してみてください。最後に、各パラメータ要素はtrade-offなど相互影響している場合などがあるため、何が正解とはありませんが、最初のステップの目安として今回の方法を活用してみてください!
