Add LogExpectedImprovementPerCost acquisition function#3304
Add LogExpectedImprovementPerCost acquisition function#3304wgst wants to merge 1 commit intometa-pytorch:mainfrom
Conversation
|
Hi @wgst! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at [email protected]. Thanks! |
There was a problem hiding this comment.
Pull request overview
Adds a new cost-aware analytic acquisition function to botorch_community implementing log expected improvement per (spatially varying) evaluation cost, intended to support cost-aware stopping / selection rules.
Changes:
- Introduces
LogExpectedImprovementPerCost(analytic) computingLogEI(x) - alpha * log(c(x)). - Adds unit tests covering constant cost, varying
alpha, maximize/minimize, and batch shapes. - Exports the new acquisition function from
botorch_community.acquisition.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
botorch_community/acquisition/log_expected_improvement_per_cost.py |
New analytic acquisition function implementing cost-adjusted LogEI. |
test_community/acquisition/test_log_expected_improvement_per_cost.py |
New unit tests validating behavior against LogExpectedImprovement. |
botorch_community/acquisition/__init__.py |
Re-exports LogExpectedImprovementPerCost in the community acquisition package. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| log_ei = (_log_ei_helper(u) + sigma.log()).squeeze(-1) | ||
|
|
||
| # X has shape (..., 1, d); squeeze the q-dim before passing to cost_callable. | ||
| costs = self.cost_callable(X.squeeze(-2)) |
| # t_batch_mode_transform adds a batch dim (1,1)->(1,1,1), so the cost | ||
| # callable sees (1,d) and returns (1,), while the mock gives log_ei | ||
| # shape () — squeeze to compare scalar values. | ||
| self.assertAllClose(leic(X).squeeze(), lei(X) - math.log(2.0), atol=1e-5) | ||
|
|
| # alpha=2: LogEIC = LogEI - 2*log(c) | ||
| leic_alpha2 = LogExpectedImprovementPerCost( | ||
| model=mm, best_f=0.0, cost_callable=cost_fn, alpha=2.0 | ||
| ) | ||
| self.assertAllClose( | ||
| leic_alpha2(X).squeeze(), lei(X) - 2.0 * math.log(2.0), atol=1e-5 | ||
| ) |
| # maximize=True (explicit) | ||
| lei_max = LogExpectedImprovement(model=mm, best_f=0.0, maximize=True) | ||
| leic_max = LogExpectedImprovementPerCost( | ||
| model=mm, best_f=0.0, cost_callable=cost_fn, maximize=True | ||
| ) | ||
| self.assertAllClose( | ||
| leic_max(X).squeeze(), lei_max(X) - math.log(2.0), atol=1e-5 | ||
| ) | ||
|
|
||
| # maximize=False | ||
| lei_min = LogExpectedImprovement(model=mm, best_f=0.0, maximize=False) | ||
| leic_min = LogExpectedImprovementPerCost( | ||
| model=mm, best_f=0.0, cost_callable=cost_fn, maximize=False | ||
| ) | ||
| self.assertAllClose( | ||
| leic_min(X).squeeze(), lei_min(X) - math.log(2.0), atol=1e-5 | ||
| ) |
| model=mm, best_f=0.0, cost_callable=cost_fn2 | ||
| ) | ||
| X_zero = torch.zeros(1, 1, dtype=dtype) | ||
| self.assertAllClose(leic_xdep(X_zero).squeeze(), lei(X_zero), atol=1e-5) |
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
Hi all,
I'm working on implementation for BO termination conditions methods in BoFire, and to implement one of them (by Xie et al., arXiv:2507.12453, 2025), we need this cost-aware logEI acquisition function (logEIC).
logEIC is analytic single-outcome acquisition function computing LogEI(x) - alpha * log(c(x)), supporting spatially varying costs.
Motivation
Cost-aware Bayesian optimization is important when function evaluations have heterogeneous costs (e.g. reaction time, compute budget, experimental reagent cost). This PR adds
LogExpectedImprovementPerCosttobotorch_community, which computes:where$c(x)$ is a user-supplied cost callable and $\alpha$ controls the cost influence.
Have you read the Contributing Guidelines on pull requests?
Yes.
Test Plan
Unit tests are added in
test_community/acquisition/test_log_expected_improvement_per_cost.py.