CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: Optuna で決められた時間内で最適化する

今回は Optuna の便利な使い方について。 現行の Optuna (v0.19.0) には決められた時間内で可能な限り最適化したい、というニーズを満たす API が実装されている。

使った環境は次の通り。

$ sw_vers 
ProductName:    Mac OS X
ProductVersion: 10.14.6
BuildVersion:   18G1012
$ python -V          
Python 3.7.5
$ pip list | grep -i optuna
optuna            0.19.0

下準備

まずは Optuna と Scikit-learn をインストールしておく。

$ pip install optuna scikit-learn

決められた時間内で最適化するサンプルコード

以下が決められた時間内で可能な限り最適化するサンプルコード。 実現するには Study#optimize()n_trials の代わりに timeout オプションを指定する。 渡す値は最適化に使う秒数になっており、以下では 60 秒を指定している。 サンプルコードでは、RandomForest で乳がんデータセットを 5-Fold Stratified CV するときのハイパーパラメータを探索している。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import optuna
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_validate
from sklearn import datasets


class Objective:
    """目的関数に相当するクラス"""

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

    def __call__(self, trial):
        """オブジェクトが呼び出されたときに呼ばれる特殊メソッド"""
        # RandomForest のパラメータを最適化してみる
        params = {
            'n_estimators': 100,
            'max_depth': trial.suggest_int('max_depth', 2, 32),
            'min_samples_leaf': trial.suggest_int('min_samples_leaf', 1, 16),
        }
        model = RandomForestClassifier(**params)
        # 5-Fold Stratified CV
        kf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
        scores = cross_validate(model,
                                X=self.X, y=self.y,
                                cv=kf,
                                # メトリックは符号を反転したロジスティック損失
                                scoring='neg_log_loss',
                                n_jobs=-1)
        return scores['test_score'].mean()


def main():
    dataset = datasets.load_breast_cancer()
    X, y = dataset.data, dataset.target
    objective = Objective(X, y)
    # 関数を最大化するように最適化する
    study = optuna.create_study(direction='maximize')
    # 試行回数ではなく特定の時間内で最適化する
    study.optimize(objective, timeout=60)  # この例では 60 秒
    print('params:', study.best_params)


if __name__ == '__main__':
    main()

実行すると、次のようになる。

$ python optimeout.py
[I 2019-12-02 18:45:41,029] Finished trial#0 resulted in value: -0.1420495901047513. Current best value is -0.1420495901047513 with parameters: {'max_depth': 28, 'min_samples_leaf': 9}.
...
[I 2019-12-02 18:46:39,488] Finished trial#25 resulted in value: -0.11825965818535904. Current best value is -0.11397258384370261 with parameters: {'max_depth': 6, 'min_samples_leaf': 1}.
params: {'max_depth': 6, 'min_samples_leaf': 1}

上記を見ると、約 1 分で最適化が終了していることがわかる。

ぶっちゃけやってみるまで 1 回の試行にどれだけ時間がかかるかなんてわからないし、試行回数を指定するより便利だと思う。

Kaggleで勝つデータ分析の技術

Kaggleで勝つデータ分析の技術

  • 作者: 門脇大輔,阪田隆司,保坂桂佑,平松雄司
  • 出版社/メーカー: 技術評論社
  • 発売日: 2019/10/09
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る