Blog
本記事はPFNでアルバイトをされている馬場凱渡さんによる寄稿です。
はじめに
Optuna v4.2 では GPSampler を制約付き最適化に対応できるよう拡張しました。本記事ではこの機能について説明します。
GPSampler
は、Optuna v3.6 で導入されたガウス過程に基づくベイズ最適化の sampler です。v3.5 以前の Optuna ではOptuna IntegrationにあるBoTorchSampler
によってのみガウス過程に基づくベイズ最適化を使用することができました。BoTorch は、非常に柔軟なフレームワークであるため,最先端のガウス過程に基づくベイズ最適化アルゴリズムも利用することができます。一方で,Optuna Integrationでは BoTorch の機能のごく一部しか必要としないため、ガウス過程に基づくベイズ最適化の Optuna 独自の実装に至りました。GPSampler
のリリース記事でも述べたように、trial 毎の suggest 呼出速度向上や独自実装による外部ライブラリ依存削減 により、より多くの環境で の利用が実現されました。
しかし、この時点では GPSampler
の機能は単目的最適化のみの対応にとどまり、多目的最適化、制約付き最適化、バッチ最適化など、多くの機能がまだ不足していました。Optuna v4.2 では機能拡張の第一弾として制約付き最適化対応を行いました。
制約付き最適化を利用することで、最適化したい目的関数とともに制約条件を考慮することができます。例えば、機械学習アルゴリズムをデプロイする際、メモリ容量や推論時間などの制約が実環境で課されることがしばしばあります。今回の新機能により、これらの制約を満たしつつ高性能なモデルを見つけることが可能になりました。
Optuna での GPSampler の使用方法
GPSampler
を利用するには、Optuna と依存関係のインストールが必要です:
$ pip install optuna==4.2.0 # GPSampler には scipy と torch も必要となります. $ pip install scipy $ pip install torch --index-url https://download.pytorch.org/whl/cpu
全ての依存関係が正常にインストールされたら、GPSampler
のインスタンスを optuna.create_study
に渡すことで、簡単に使用することができます:
import numpy as np import optuna def objective(trial: optuna.Trial) -> float: x = trial.suggest_float("x", 0.0, 2 * np.pi) y = trial.suggest_float("y", 0.0, 2 * np.pi) return float(np.sin(x) + y) sampler = optuna.samplers.GPSampler() study = optuna.create_study(sampler=sampler) study.optimize(objective, n_trials=100)
GPSampler を用いた制約付き最適化
この実装は J. Gardner ら [1] および M. Gelbart ら [2] の手法に基づいています。ここでは、制約関数にもガウス過程を用いることで、制約条件を満たした下で目的関数を最適化します。ただし、制約関数の数だけガウス過程の計算が必要となるため、その分 suggest の呼出時間が増加する点に注意が必要です。詳細については、以下の PR を参照してください。
- #5715: Enable
GPSampler
to support constraint functions.
GPSampler
を用いた制約付き最適化は、float の tuple を返す制約関数を作成し、それを GPSampler
のインスタンス化時に渡すことで簡単に利用できます。なお、制約関数の返した制約値がすべて 0 以下の場合、その試行は実行可能と見なされます。以下にサンプルコードを示します:
import numpy as np import optuna def objective(trial: optuna.Trial) -> float: x = trial.suggest_float("x", 0.0, 2 * np.pi) y = trial.suggest_float("y", 0.0, 2 * np.pi) c = float(np.sin(x) * np.sin(y) + 0.95) trial.set_user_attr("c", c) return float(np.sin(x) + y) def constraints(trial: optuna.trial.FrozenTrial) -> tuple[float]: c = trial.user_attrs["c"] return (c, ) sampler = optuna.samplers.GPSampler(constraints_func=constraints) study = optuna.create_study(sampler=sampler) study.optimize(objective, n_trials=100)
ベンチマーク結果
制約付き GPSampler
の性能を評価するために、以下の sampler と比較しました:
- TPESampler: 制約付き最適化をサポートしている Optuna の標準 sampler
- BoTorchSampler: Optuna Integration で利用可能な、
BoTorch
を用いたガウス過程を利用したベイズ最適化 sampler
実験では実行可能であった trial における各時点での最良の目的関数値と、各 trial 終了時の経過時間を比較しました。また,実験では以下の関数を使用しました (図1参照):
- 目的関数: sin x + y
- 制約関数: sin x sin y ≤ −0.95

図1. 実験で使用した目的関数のランドスケープ。この図は J. Gardner ら [1] の図2から引用したものです。目的関数の値は、等高線の色が青くなるほど良くなります。実行不可能な領域は白くマスキングされており、図中の左上および右下の楕円領域のみが実行可能な領域となっています。
結果は図2および図3に示されています。これらの図から、GPSampler
や BoTorchSampler
といったガウス過程に基づく sampler は、サンプリング時間が長くなるものの、TPESampler
よりも高い性能を発揮することが分かります。この実験において GPSampler
の方が優れた性能を示しました。これは、TPESampler
が図1に示される一方の実行可能領域に陥りやすい一方で、GPSmapler
は表現力の高いsurrogate モデルを用いることで両方の実行可能領域を探索できるためと考えられます。また、GPSampler
とBoTorchSampler
は最適化の初期段階を除いてほぼ同等の結果を得ましたが、各試行のサンプリング時間は、GPSampler
の方がはるかに短くなっています。

図2: 各 sampler の性能比較。Multivariate TPE は multivariate=True の TPESampler を指し、TPE は標準の TPESampler を指します。x 軸は trial 数、y 軸は実行可能な試行におけるその時点での最良の目的関数値を表します。実線は性能の中央値を示し、薄い色の帯は四分位範囲を示します。なお、これらの統計量はそれぞれ異なる乱数シードを用いた10回の試行結果をもとに計算されています。

図3: 各 sampler の各 trial 終了時点までの経過時間。x 軸は trial 数、y 軸は study の開始からの経過時間を表します。実線は平均経過時間を示し、薄い色の帯は標準誤差を示します。なお、これらの統計量はそれぞれ異なる乱数シードを用いた10回の試行結果をもとに計算されています。
おわりに
本記事では、不等式制約付き最適化問題への GPSampler
の拡張について紹介しました。今回の実験では、制約付き GPSampler
が TPESampler
よりも優れた性能を示した上で、BoTorchSampler
よりも短い suggest 呼出時間で動作することを確認しました。制約付きの GPSampler
をぜひお試しください!
参考文献
[1] Gardner, J., Kusner, M., Zhixiang, W., Weinberger, K., and Cunningham, J. Bayesian optimization with inequality constraints. In Proceedings of the 31st International Conference on Machine Learning, 2014.
[2] Gelbart, M. A., Snoek, J., and Adams, R. P. Bayesian optimization with unknown constraints. In Proceedings of the 30th Conference on Uncertainty in Artificial Intelligence, 2014.
Tag