Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

trustbo-gp

TRust-BO 第2段階用の 小型・高性能 Gaussian Process Optimizer(pure Rust)。

BLAS / LAPACK / OpenBLAS に依存せず、rand / rand_distr / thiserror のみで動作します。 行列計算はすべて自前の Cholesky 分解 + 前進/後退代入で行い、逆行列は一切作りません

このGPの役割

TRust-BO は2段構成の Bayesian Optimization エンジンです。

段階 担当 空間
第1段階 MLP アンサンブル + Trust Region + PyO3 Rust core 100D〜200D+ の全空間
第2段階 本クレート(GP valley refiner) 第1段階が発見した谷の内部(2D〜50D)

第1段階は 100D 問題で真の最適値 0.0 に対し y ≈ 8 前後の谷まで到達できます。 本クレートの役割は、その谷の中で局所構造を精密に学習し、y ≈ 8 から y ≈ 0 近傍まで詰めることです。 ベンチマークの quadratic-basin-20d / quadratic-basin-50d はまさにこのハンドオフ (初期点 y ≈ 8 をシードし、そこから 0 へ精密化)を再現したものです。

なぜ100D全体を直接GPしないのか

  • 厳密GPは学習点数 n に対して O(n³)、予測 O(n²)。高次元で必要になるサンプル数では計算が破綻する。
  • 距離ベースのカーネルは高次元で距離が集中(concentration of measure)し、ARD lengthscale の 推定が不可能になる。100D を直接張る GP は「どこも等しく遠い」事前に退化する。
  • 一方、谷の内部は実効次元が低く滑らかなので、低次元GPの得意領域。大域探索は スケールする第1段階(MLP + TR)に任せ、GP は局所精密化に専念する方が両者とも性能が出る。

なぜ 2D〜20D を主戦場にするのか

2D〜20D は、数十〜数百評価で ARD lengthscale・outputscale・noise を周辺尤度から安定推定でき、 BoTorch の SingleTaskGP + LogEI / TuRBO と同等の挙動を狙える領域です。本クレートの 性能目標(BoTorch級)はこの範囲で設定しています。

30D〜50D はどう扱うのか

動作可能・実用可能だが性能保証は弱いという位置づけです。具体的には:

  • ハイパーパラメータ最適化は 12D 超で勾配スタート数と反復数を自動縮退 (有限差分勾配のコストが次元に比例するため)。
  • 獲得関数最適化は coordinate search + CEM の組合せで 50D でも確実に動作。
  • GP の学習点数は max_gp_points(デフォルト256)で打ち切り、Trust Region 中心の 最近傍点のみでモデルを張る。
  • 設計上限は 50D。それ以上は第1段階の担当。

使い方

use trustbo_gp::{GpConfig, GpOptimizer};

// 入力は [0,1]^d を想定(実領域への写像は呼び出し側が所有)。目的は最小化。
let mut opt = GpOptimizer::new(6, GpConfig::default(), 42);

// 第1段階からのハンドオフ: 既知の評価点を事前に tell してよい
// (init_design_size() 個以上 tell すると初期サンプリングをスキップ)。
for _ in 0..100 {
    let x = opt.ask()?;          // 次に評価すべき点
    let y = objective(&x);       // ユーザー側で評価
    opt.tell(x, y)?;             // 観測を登録
}
let (best_x, best_y) = opt.best().unwrap();

// バッチ提案(constant-liar fantasizing)
let batch = opt.ask_batch(4)?;

// GP 単体での利用も可能
use trustbo_gp::GpModel;
let model = GpModel::fit(&xs, &ys, &GpConfig::default())?;
let (mu, var) = model.predict(&x)?;
let cov = model.posterior_covariance(&queries)?;
let lml = model.log_marginal_likelihood();

デフォルト設定: Matern 5/2 ARD カーネル + LogEI + TuRBO 型 Trust Region (L_init=0.8, L_min=1e-3, L_max=1.6, success_tol=3, failure_tol=max(4,dim))。 カーネル(Matern52/Matern32/RBF)と獲得関数(EI/LogEI/PI/LCB/UCB/Thompson)は GpConfig で切り替えられます。

ハイパーパラメータ最適化

negative log marginal likelihood を、log空間 bounds (lengthscale [1e-3,10] / outputscale [1e-6,1e6] / noise [1e-10,1e-1])内で最小化します。 単純ランダム探索ではなく:

  1. multi-start(16スタート、推奨初期値 + warm start)を NLL でランク付け
  2. 上位スタートを projected L-BFGS(中央差分勾配 + Armijo line search) で最適化
  3. random search fallback(勾配が全滅した場合はフル予算)
  4. 座標方向の local refinement で仕上げ

勾配計算は nll_grad 相当の1関数に隔離してあり、将来解析勾配へ差し替え可能です。

数値安定性

  • Cholesky は jitter 1e-10 から10倍ずつ 1e-2 まで escalation、失敗時は GpError::CholeskyFailed
  • 入力の NaN/inf は全公開APIで検出して GpError::NonFiniteInput
  • 予測分散は 1e-12 で clamp
  • LogEI は z « 0 の領域で漸近展開に切替え、EI がアンダーフローする領域でも有限値を維持

ベンチマーク実行方法

cargo run --release                 # 全ベンチマーク
cargo run --release -- branin       # 名前でフィルタ
cargo run --release -- --seed 7 -v  # シード変更 + 進捗表示
cargo test                          # テストスイート

スイート: Branin 2D / Hartmann 3D / Hartmann 6D / Rosenbrock 4D / Ackley 5D / Levy 5D / Sphere 10D / shifted Sphere 10D / quadratic basin 20D / quadratic basin 50D。 出力には best value, regret, best x, 経過時間, カーネル, 獲得関数, TR length, ハイパーパラメータ, restart 回数が含まれます。

参考結果(デフォルト設定 Matern52 + LogEI、seed 42、シングルスレッド):

benchmark dim evals best regret 備考
branin-2d 2 80 0.397887 0.000000 真の最適値に6桁一致
hartmann-3d 3 80 -3.862780 0.000000
hartmann-6d 6 120 -3.322368 0.000002
rosenbrock-4d 4 120 0.001898 0.001898
ackley-5d 5 150 0.009725 0.009725 領域 [-5,10]^5(TuRBO論文準拠)
levy-5d 5 150 2.356455 2.356455 多峰性、restart 2回
sphere-10d 10 120 0.000025 0.000025
shifted-sphere-10d 10 120 0.000007 0.000007
quadratic-basin-20d 20 120 0.019307 0.019307 初期 y≈5.8 → 0.019
quadratic-basin-50d 50 200 1.435275 1.435275 初期 y≈6.2 → 1.44(設計上限域)

basin 問題は第1段階ハンドオフの再現で、f≈8 のシェル上の点 40 個を tell でシードしてから 最適化を開始します(40点の最小値が初期 best)。全スイートの実行時間は約3.5分です。

今後 PyO3 に接続する予定のAPI

ask/tell インターフェースは PyO3 バインディングを想定して、引数・戻り値を Vec<f64> / f64 / Result のみで構成しています。接続予定の表面:

GpOptimizer::new(dim: usize, config: GpConfig, seed: u64) -> Self
GpOptimizer::ask(&mut self) -> Result<Vec<f64>, GpError>
GpOptimizer::ask_batch(&mut self, batch_size: usize) -> Result<Vec<Vec<f64>>, GpError>
GpOptimizer::tell(&mut self, x: Vec<f64>, y: f64) -> Result<(), GpError>
GpOptimizer::best(&self) -> Option<(Vec<f64>, f64)>
GpOptimizer::fit_model(&mut self) -> Result<(), GpError>

GpModel::fit / predict / predict_batch / posterior_covariance / log_marginal_likelihood

GpErrorthiserror 製で Display を実装済みのため、PyErr への変換は文字列経由で機械的に行えます。 --features serde で全 Config が serde 対応になり、Python 側から JSON で設定を渡せます。

モジュール構成

src/
  lib.rs          公開API・クレートドキュメント
  config.rs       GpConfig / KernelType / AcquisitionType / 各サブ設定
  error.rs        GpError(thiserror)
  linalg.rs       Cholesky(+adaptive jitter)/前進後退代入/統計ヘルパ
  kernel.rs       Matern52 / Matern32 / RBF(すべてARD、log空間パラメータ)
  gp.rs           GpModel(fit / predict / posterior_covariance / LML)
  hyperopt.rs     multi-start + projected L-BFGS + fallback + local refinement
  acquisition.rs  EI / LogEI(安定版)/ PI / LCB / UCB / Thompson近似
  candidate.rs    LHS / uniform / CEM / coordinate search / multi-start局所探索
  trust_region.rs TuRBO型 Trust Region(成功・失敗カウンタ、restart)
  optimizer.rs    GpOptimizer(ask / tell / ask_batch / restart制御)
  benchmarks.rs   ベンチマーク問題とランナー(GP本体とは ask/tell 経由で疎結合)
  main.rs         cargo run --release エントリポイント
tests/
  gp_tests.rs / kernel_tests.rs / optimizer_tests.rs

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages