🐲

Hydraでハイパーパラメータを一元管理

2024/09/25に公開

Hydra について

Hydra は、研究や複雑なアプリケーションの開発で使用されるPythonのフレームワークです。パラメータや設定を簡単に管理できる特徴があります。
今回は機械学習で使用する際を想定し、ログの保存や複数実行する方法などについてまとめました。

インストール

terminal
> pip install hydra-core

基本的な使い方

初めに以下のようなディレクトリ構成を想定します。

ディレクトリ構成
conf
└ config.yaml
main.py

設定ファイル config.yaml で管理したいパラメータを以下のように記述します。

config.yaml
hyper_parameter:
  learning_rate : 1e-5

必要なライブラリとデコレータ、適切な引数を使用することで設定ファイルのパラメータに簡単にアクセスできます。

main.py
import hydra
from omegaconf import DictConfig

@hydra.main(version_base=None, config_path="conf", config_name="config")
def main(cfg: DictConfig) -> None:
    print(cfg.hyper_parameter.learning_rate)

if __name__ == "__main__":
    main()
実行結果
> Python main.py
1e-05
  • デコレータ @hydra.main() を使って関数に定義された処理を修飾します。
  • 修飾された関数の引数を cfg: DictConfig にすることでYAML形式で定義された設定ファイルのパラメータが格納されたオブジェクトを利用できます。
  • 定義したパラメータは cfg 経由で参照できます。
  • デコレータ @hydra.main() の引数は次を指定します。
    • version_base:Hydraのバージョン(None の場合は最新のマイナーバージョンのデフォルトを使用します。Hydra 1.2以降は省略すると1.1が使用され、指定を求める警告が表示されます。)
    • config_path:設定ファイルの配置されているディレクトリ
    • config_name:拡張子を除いたYAML形式の設定ファイル名

実行プログラム内の変数から取得するパラメータを選択

次のように文字列を格納した変数から取得するパラメータを選択することもできます。

main.py
(前略)
def main(cfg: DictConfig) -> None:
    strings = "learning_rate"
    print(cfg.hyper_parameter[strings])
(後略)
実行結果
> Python main.py
1e-05

実行時パラメータ指定

実行時にパラメータを指定できます。その場合には設定ファイルのパラメータより実行時に指定したパラメータが優先されます。

実行結果
> Python main.py hyper_parameter.learning_rate=1e-6
1e-06

ハイパーパラメータの履歴・ログを管理

通常、実行後には以下のようなディレクトリとファイルが生成されます。
config.yaml は実行時に自動的にコピーされます。

ディレクトリ構成
output
└ [実行日(%Y-%m-%d)]
    └ [実行時刻(%H-%M-%S)]
        ├ .hydra
        │   └ config.yaml
        │   └ hydra.yaml
        │   └ overrides.yaml
        └ main.log
  • config.yaml:ユーザが指定したYAML形式の設定ファイルのコピー(実行時にパラメータを指定した場合はそのパラメータが上書きされます。)
  • hydra.yaml:Hydraの構成
  • overrides.yaml:実行時に指定されたパラメータ
  • main.log:実行ファイルのログを保存したログファイル

自動生成されるディレクトリの位置や名称を変更

自動生成ファイルの位置やディレクトリ名を変更する場合は hydra.run.dir を変更して実行します。変更する方法は2種類あります。

  • config.yaml で以下を追記する。
config.yaml
hydra:
    run:
        dir: outputs/${now:%Y-%m-%d_%H-%M-%S}
  • 実行時引数で指定する。
Terminal
> python main.py hydra.run.dir=outputs/${now:%Y-%m-%d_%H-%M-%S}

どちらの場合でも以下のようなディレクトリ構成が生成されます。

ディレクトリ構成
output
└ [実行時刻(%Y-%m-%d_%H-%M-%S)]
    ├ .hydra
    │  (以下略)

ユーザが設定したパラメータをディレクトリ名に組み込む

ユーザーが設定した変数をディレクトリ名に含めることもできます。
config.yaml で次のように設定したとします。

config.yaml
hydra:
    run:
        dir: outputs/lr_${hyper_parameter.learning_rate}

この場合、以下のようなディレクトリ構成が生成されます。

ディレクトリ構成
output
└ lr_1e-05
    ├ .hydra
    │  (以下略)

ログを生成・保存

ログはPythonのロギング機能を同時に利用することで簡単に管理できます。
次のような実行ファイルを想定します。

main.py
import hydra
from omegaconf import DictConfig
import logging

log = logging.getLogger(__name__)

@hydra.main(version_base=None, config_path="conf", config_name="config")
def main(cfg: DictConfig) -> None:
    log.info("---Process Start!---")
    log.info("info level message")
    log.debug("debug level message")
    log.info(f"Learning rate: {cfg.hyper_parameter.learning_rate}")
    log.info("---Process End!---")

if __name__ == "__main__":
    main()

この場合の main.log およびコンソールの出力は以下のようになります。
Hydraは通常、コンソールとログファイルに INFO レベルでログを記録します。

main.log
[2024-09-24 14:40:12,337][__main__][INFO] - ---Process Start!---
[2024-09-24 14:40:12,337][__main__][INFO] - info level message
[2024-09-24 14:40:12,337][__main__][INFO] - Learning rate: 1e-05
[2024-09-24 14:40:12,337][__main__][INFO] - ---Process End!---

DEBUG レベルで記録したい場合は以下の2種のどちらかで実行します。

  • config.yaml で以下を追記する。
config.yaml
hydra:
    verbose: __main__
  • hydra.verbose=__main__ をつけて実行する。
terminal
> python main.py hydra.verbose=__main__

この場合の main.log およびコンソールの出力は以下のようになります。
DEBUG レベルのログも保存されていることが確認できます。

main.log
[2024-09-24 14:30:16,970][__main__][INFO] - ---Process Start!---
[2024-09-24 14:30:16,970][__main__][INFO] - info level message
[2024-09-24 14:30:16,970][__main__][DEBUG] - debug level message
[2024-09-24 14:30:16,970][__main__][INFO] - Learning rate: 1e-05
[2024-09-24 14:30:16,970][__main__][INFO] - ---Process End!---

※注:ロギング機能によって制御されない print 文などは保存されません。

.log ファイル / .hydra ディレクトリを生成したくない場合

以下の2種のどちらかを実行します。
常時生成したくない場合は config.yaml を変更、一時的に生成したくない場合には実行時引数で指定することを推奨します。

  • config.yaml で以下を追記する。
config.yaml
hydra:
    output_subdir: null                         # .hydra 以下ファイルの生成停止
defaults:
    - override hydra/hydra_logging: disabled   # .hydra 以下ファイルの生成停止
    - override hydra/job_logging: disabled      # ログ出力・記録停止
  • 実行時に以下のような引数を指定する。
terminal
> python main.py hydra.output_subdir=null hydra/hydra_logging=disabled hydra/job_logging=disabled

補足

  • .hydra ディレクトリとそれ以下ファイルの生成を停止する場合は output_subdirhydra/hydra_logging の両方を変更してください。
  • ログファイルの停止は hydra/job_logging を変更してください。

outputsディレクトリを生成したくない場合

そもそも outputs ディレクトリを生成したくない場合は上記の設定に加えて、設定ファイル config.yaml または 実行時引数で hydra.run.dir./ に変更します。

  • config.yamlで以下を追記する
config.yaml
hydra:
    run:
        dir: ./
        (以下略)
  • 実行時引数を追加する
terminal
> python main.py hydra.run.dir=./ hydra.output_subdir=null hydra/hydra_logging=disabled hydra/job_logging=disabled

複数実行

ハイパーパラメータを指定した候補(要素)からそれぞれのパターンで実行する multirun を利用すると比較・検証に便利です。
2つ以上のパラメータで2つ以上の候補を用意してもすべての組み合わせで実行されます。

以下はコマンドラインから実行する場合の例です。
※注:要素間に空白を入れないこと

terminal
> python main.py -m hyper_parameter.learning_rate=1e-5,1e-4

上を実行した場合、通常、以下のようなディレクトリ構成になります。

ディレクトリ構成
multirun
└ [実行日(%Y-%m-%d)]
    └ [実行時刻(%H-%M-%S)]
        ├ 0 (以下略)
        └ 1 (以下略)

ジョブ番号の下に通常実行時と同様の .hydra ディレクトリやログファイルが配置されます。
この場合、config.yaml からパラメータの値を毎回確認する必要があります。

自動生成されるディレクトリの位置や名称を変更

生成されるディレクトリ名にパラメータを含める場合は config.yaml${hydra.job.override_dirname} を使用して次のように変更します。

config.yaml
hydra:
  sweep:
    dir: multirun_${now:%Y-%m-%d_%H-%M-%S}
    subdir: ${hydra.job.override_dirname}

同様に実行した場合、以下のようなディレクトリ構成になります。

ディレクトリ構成
multirun_[実行時刻(%Y-%m-%d_%H-%M-%S)]
    ├ hyper_parameter.learning_rate=0.0001  (以下略)
    └ hyper_parameter.learning_rate=1e-05   (以下略)

補足

  • .hydraディレクトリやログファイルが保存されるディレクトリはhydra.core.hydra_config.HydraConfig.get().runtime.output_dirで取得可能です。
  • hydra1.1以前ではカレントディレクトリがデフォルトで(hydra.job.chdir=Trueが指定されており)変更されるため注意が必要です。
  • 今回は1ファイルで一元管理する前提で述べています。詳しくは述べませんが、2ファイル以上で管理する方法もあります。
    (config.yamlでデフォルトで使用するyamlファイルを設定し、config.yamlと同じ階層に新たなディレクトリを作成、その配下に使用するデータベースやモデルごとにyamlファイルを作成・使用することで2ファイル以上で管理できます。)
  • 参考:Getting started | Hydra

終わりに

Hydraの使い方を簡単に、特に知っておくと便利だった仕様を中心にまとめてみました。何か間違っているところなどあれば、コメントなどで優しく指摘いただけると幸いです。ハイパーパラメータの管理で困っている方、Hydraを使い始める方の一助になれば幸いです。ここまでお読みいただき、ありがとうございました。

Discussion