LoginSignup
1
2

More than 3 years have passed since last update.

optunaで探索変数を増やす際に探索済みの結果で初期化する

Last updated at Posted at 2021-02-20

optunaを用いてハイパーパラメータの探索をした際、ある程度探索が進んでから「どうもこっちの変数も探索しておいた方が良かったのではないか?」などと気付いてしまうことがあると思います。
そんなとき、これまで頑張って探索した結果は活用したいものです。

ちなみに変数の探索範囲を変えたいだけであれば、以下の記事のようにもっと簡単にできるようです。

[Qiita] Optunaで特定の初期値から最適化を開始する

注意: この記事で紹介している方法はoptuna v2.0.0で実験的に追加された関数を利用しているため、今後の仕様変更で使えなくなっているかもしれません。

TL;DR

  • Study.add_trial(trial) (document) 関数を使って探索済みのtrialを新しいstudyに追加する。
    • この際trialのparams, distributions辞書に新しい変数の値を追加する。
    • 新しい変数のdistributionは新しいstudyでのものに合わせる必要がある

変数の増やしかた

この章では具体例として、以前の探索で値を0.8に固定していたcls_weightという変数も追加で探索するように修正していく手順をメモしていきます。

新規変数の設定

まず最初に新たに探索することにした変数に関する以下の情報を用意します:

  • これまで固定していた変数値
  • これまでの探索でのdistribution

このとき、distributionは新しいstudyでのものとクラスが一致している必要があるようです。

つまり今回のケースでcls_weightsuggest_loguniformで探索するときはLogUniformDistributionを選ぶ必要があります。
対応するdistributionはドキュメントを参照しつつ選んでみてください。

なお異なるクラスのdistributionを設定すると

ValueError: Cannot set different distribution kind to the same parameter name.

のようなエラーが発生しました。

今回のケースでは以下のようになります。

import optuna

# 以前の探索では固定していたパラメータ
append_params = {"cls_weight": 0.8}
# パラメータの分布
append_distributions = {
    "cls_weight": optuna.distributions.LogUniformDistribution(0.8, 0.8)
}

初期化のためのtrialを用意する

探索済みのtrialはstudy.get_trials()関数を用いて読み込むことができます。
しかし今回は探索対象の変数が増えているため、このtrialをそのまま新しいstudyに追加することはできません。

そこで以下のようにtrialのparamsdistributions属性に前の節で用意しておいた新しい変数の情報を追加したうえで、optuna.create_trial() (document) 関数により新しくtrialを作り直します。

今回は行っていませんが、この際に得られた目的関数の値(value)も変更することができます。そのため、この方法を応用すればoptuna以外で目的関数を評価した際の結果で初期化することも可能(なはず)です。

# 以前の探索のtrialを読み込み
old_study = optuna.load_study(study_name="metric_learning", storage="sqlite:///cls_res152.sqlite")
old_trials = old_study.get_trials()

new_trials = []
for trial in old_trials:
    # stateがCOMPLETEであるtrialのみ保持する
    if trial.state == optuna.trial.TrialState.COMPLETE:
        distributions = trial.distributions
        distributions.update(append_distributions)
        params = trial.params
        params.update(append_params)
        new_trial = optuna.create_trial(
            state=optuna.trial.TrialState.COMPLETE,
            value=trial.value,
            params=params,
            distributions=distributions
        )
        new_trials.append(new_trial)
    else:
        continue

新しいstudyの作成と初期化

これまでの節で初期化のためのtrialが得られているので、残るは以下のように新しく作成したstudyにStudy.add_trial()関数を用いて追加していくだけです。

studyを作成する際のstorage, study_name, directionなどは必要に応じて修正してください。

new_study = optuna.create_study(storage="sqlite:///cls_res152_new.sqlite", study_name="metric_learning", direction="maximize", load_if_exists=True)

for new_trial in new_trials:
    print(f"Add: {new_trial}")
    new_study.add_trial(new_trial)
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2