hyperoptでハイパーパラメータをチューニングしてみた

Kaggleとかやってる人に人気のあるアレです。

github.com

インストール

ここ数ヶ月の間,開発が停滞していて,Python3の互換性の問題を修正するプルリクエストが取り込まれていない状況です。

不幸にもPython3に関する問題に追突してしまった場合には,修正してあるforkを探してきて,それを使ったほうが良いでしょう。

私の場合は,試行したパラメータの履歴を保存する hyperopt.Trials を使った際に問題が起こったので,次のようにして修正の入ったコミットをインストールしました。

$ pip3 install -U git+https://github.com/vilcenzo/hyperopt.git@8b37bb4a1ac0d03fc14ec95ea0b73ec6019c2ad7

2017/01/16追記

開発が再開されたので本家のリポジトリのものをインストールすればOKです。

使い方

公式のドキュメントはほとんど以下のチュートリアルしかありません。

使用する際に利用者が定義しなければならないのは以下の2点です。

  1. 最小化するための評価関数
  2. 探索空間(hyperopt.hp 以下の関数を使う)

この2つだけ定義すれば,あとはTree of Parzen Estimatorsなるアルゴリズムがよろしくやってくれます。

パラメータ探索の例1

MNISTを対象に,多項式カーネルを使ったSVMで次元数dとペナルティパラメータCを変えてみました。

import scipy

import sklearn.svm
import sklearn.cross_validation
import sklearn.externals
import sklearn.datasets

import hyperopt
from hyperopt import hp


def load():
    digits = sklearn.datasets.load_digits()
    return digits.data, digits.target


class Objective:

    def __init__(self, X, y):
        self.X = X
        self.y = y

    def __call__(self, space):
        svc = sklearn.svm.SVC(**space['SVC'])
        # Kohavi, R.: A Study of Cross-Validation and Bootstrap for Accuracy Estimation and Model Selection, IJCAI (1995).
        accuracy = sklearn.cross_validation.cross_val_score(
            svc, self.X, self.y,
            scoring='accuracy', cv=10, n_jobs=-1)
        accuracy = scipy.mean(accuracy)
        print(accuracy, space)
        # accuracyを最大化したいので
        return -accuracy


def main():
    X, y = load()

    space = {
        'SVC': {
            # libsvmの設定をパクった
            # https://github.com/cjlin1/libsvm/blob/master/tools/grid.py
            'C': 2 ** hp.uniform('C', -5, 15),
            'kernel': 'poly',
            'degree': hp.quniform('degree', 1, 10, q=1),
        }
    }

    objective = Objective(X, y)
    trials = hyperopt.Trials()
    best = hyperopt.fmin(objective, space,
                         algo=hyperopt.tpe.suggest, max_evals=1000, trials=trials)

    best = hyperopt.space_eval(space, best)
    print(best)
    print(objective(best))
    sklearn.externals.joblib.dump(trials.trials, 'trials.pkl')


if __name__ == '__main__':
    main()

次元数dの探索頻度は以下の通りです。最終的に d=3, C=13.7 というパラメータで正解率が最大となったのですが,d=3付近をよく探索しているようです。

f:id:kujira16:20160528173822p:plain

d=3の場合におけるペナルティパラメータCの探索頻度は以下の通りです。

f:id:kujira16:20160528173828p:plain

パラメータ探索の例2

適当に多峰性の関数を作って探索させました。hyperopt movie · GitHub

その他

可視化のためのモジュールが用意されているっぽいのですが,使い方がよくわかりません…

参考

districtdatalabs.silvrback.com fastml.com