チューニングTips
ZenithTuneによる自動チューニングを強化する便利機能について説明します。
最大化問題に変更する
Tunerの初期化時にmaximize
引数にTrue
を設定することで最小化問題から最大化問題に変更できます。
例えば、学習スループットを最大化する場合などに役立ちます。
tuner = GeneralTuner(maximize=True)
tuner.optimize(objective, n_trials=10)
チューニングから試行を除外する
すべてのTunerに共通して、目的関数内でエラーや例外が生じた試行は自動的に除外されます。
例えば、コマンド実行時にOut of Memoryなどによってプログラムが異常終了してしまった場合についてもユーザが考慮する必要はありません。
一方で、コスト値の算出に失敗した場合や、何らかの制約を満たさなかった場合など試行を意図的に除外したい場合には、目的関数内でNone
を返すことで該当の試行を除外することができます。
def objective(trial, **kwargs):
x = trial.suggest_int("x", low=2, high=10)
y = trial.suggest_int("y", low=1, high=10)
if x % y != 0:
return None
return x**2 + y**2
既存のチューニング結果からの再開・分析
既存のチューニング結果(Optunaが出力するsqliteデータベース)のパスをTunerのdb_path
に指定することで、最後の試行からチューニングを再開します。
tuner = GeneralTuner(db_path="path/to/study.db")
tuner.optimize(objective, n_trials=10)
既存のチューニング結果の分析のみをしたい場合にも同様にdb_path
を指定することで実現できます。
tuner = GeneralTuner(db_path="path/to/study.db")
tuner.analyze()
チューニングパラメータに初期値を設定する
Tuner optimize関数のdefault_params
引数に、目的関数で定義したハイパーパラメータの値をdict形式で与えることで初期値を設定できます。
良い初期値を与えることで、悪いパラメータを試行する回数が減り、効率的にチューニングできる可能性が高まります。
また、ベースラインとなる初期値を設定することで、チューニングによる改善度合いの分析が容易になります。
def objective(trial, **kwargs):
x = trial.suggest_int("x", low=-10, high=10)
y = trial.suggest_int("y", low=-10, high=10)
return x**2 + y**2
tuner = GeneralTuner()
tuner.optimize(
objective,
n_trials=10,
default_params={
"x": 1,
"y": 2,
},
)
目的関数からメタデータを受け取る
目的関数のキーワード引数には、メタデータとして以下の値が提供されます。 必要に応じて参照してください。
trial_id
: 試行のインデックス(0-indexed)dist_info
: 分散実行情報を表す辞書データ。以下のキーバリューが含まれます。rank
: プロセスのランクlocal_rank
: プロセスのローカルランクworld_size
: プロセス数launcher
: 分散実行方法。"mpi"
,"torch"
,None
のいずれか
study_dir
: チューニングログ・結果が出力されるディレクトリ。作業ファイルを生成したい場合にも活用できます。
環境変数をチューニングする
目的関数で定義したハイパーパラメータを、os.environ
を介して環境変数に直接設定することで、環境変数をチューニングできます。
def command_generator(trial, **kwargs):
num_workers = trial.suggest_int("num_workers", low=1, high=10)
omp_num_threads = trial.suggest_categorical("omp_num_threads", [1, 2, 4, 8, 16, 32])
os.environ["OMP_NUM_THREADS"] = str(omp_num_threads)
command = f"python train.py --num-workers {num_workers}"
return command
CommandOutputTunerを使用している場合は、実行コマンドログファイルの冒頭に現在のコンテキストにおける環境変数が列挙されるため、適切に環境変数が設定されているか確認できます。
スクリプト・設定ファイルをチューニングする
ZenithTuneが提供するreplace_params_to_file
関数を使用することでスクリプトや設定ファイル内に記載されている値もチューニングすることができます。
事前準備として、チューニングしたいファイルのコピーを作成し、チューニングパラメータとして変更したい値に対してパラメータ名とその両端を{{ }}
で囲むことでプレースホルダ化します。
train:
batch_size: 4
learning_rate: 1e-5
↓
train:
batch_size: {{batch_size}}
learning_rate: 1e-5
そして、目的関数で対応するチューニングパラメータを定義し、replace_params_to_file
関数を使用してプレースホルダ化された値を上書きします。
replace_params_to_file
関数の引数には、プレースホルダが含まれる入力ファイルパス、出力ファイルパス、そして設定するパラメータとその値をdict形式で指定します。
def replace_params_to_file(
input_filepath: str,
output_filepath: str,
params: Dict[str, Any],
) -> None:
まとめると次のようになります。 目的関数からメタデータを受け取ることで、試行ごとのyamlファイルを個別に書き出しています。
from zenith_tune.utils import replace_params_to_file
def command_generator(trial, trial_id, study_dir, **kwargs):
num_workers = trial.suggest_int("num_workers", low=1, high=10)
batch_size = trial.suggest_int("batch_size", low=2, high=8)
tuning_yaml = os.path.join(study_dir, f"trial_{trial_id}.yaml")
replace_params_to_file(
"edited.yaml",
tuning_yaml,
{"batch_size": batch_size},
)
command = f"python train.py --num-workers {num_workers} --config {tuning_yaml}"
return command
このようにすることで、output_filepath
に出力したファイルをチューニング後もそのまま使用することができます。