---
title: Local Search Region Bayesian Optimization
jupyter: python3
---
In this notebook the Branin benchmark from paper about local search region BO (https://www.merl.com/publications/docs/TR2023-057.pdf) is reproduced. Note that we use here by purpose `qEI` as acquisition function to reproduce the paper.
## Imports and helper methods
```{python}
#| papermill: {duration: 2.95335, end_time: '2024-10-10T20:35:31.877904', exception: false, start_time: '2024-10-10T20:35:28.924554', status: completed}
#| tags: []
import os
import warnings
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import bofire.strategies.api as strategies
from bofire.benchmarks.api import Branin
from bofire.data_models.acquisition_functions.api import qEI
from bofire.data_models.domain.api import Domain
from bofire.data_models.strategies.api import (
LSRBO,
BotorchOptimizer,
RandomStrategy,
SoboStrategy,
)
from bofire.runners.api import run
warnings.filterwarnings("ignore")
bench = Branin(locality_factor=0.5)
def sample(domain):
sampled = domain.inputs.sample(10)
return sampled
# sampled = bench.f(sampled, return_complete = True)
# sampled = sampled.sort_values(by="y", ascending=False, ignore_index=True)
# return sampled[bench.domain.inputs.get_keys()].copy()
def best(domain: Domain, experiments: pd.DataFrame) -> float:
return experiments.y.min()
SMOKE_TEST = os.environ.get("SMOKE_TEST")
```
## Random Optimization
Here random sampling is performed without any local search region constraints applied.
```{python}
#| papermill: {duration: 0.252447, end_time: '2024-10-10T20:35:32.134765', exception: true, start_time: '2024-10-10T20:35:31.882318', status: failed}
#| tags: []
random_results = [
run(
Branin(locality_factor=0.5),
strategy_factory=lambda domain: strategies.map(RandomStrategy(domain=domain)),
n_iterations=80 if not SMOKE_TEST else 1,
metric=best,
initial_sampler=sample,
n_runs=1,
n_procs=1,
)
for _ in range(5 if not SMOKE_TEST else 1)
]
```
## SOBO Optimization
Here standard bayesian optimization is performed without any local search region constraints applied using the qEI acquistion function.
```{python}
#| papermill: {duration: null, end_time: null, exception: null, start_time: null, status: pending}
#| tags: []
sobo_results = [
run(
Branin(locality_factor=0.5),
strategy_factory=lambda domain: strategies.map(
SoboStrategy(domain=domain, acquisition_function=qEI()),
),
n_iterations=80 if not SMOKE_TEST else 1,
metric=best,
initial_sampler=sample,
n_runs=1,
n_procs=1,
)
for _ in range(5 if not SMOKE_TEST else 1)
]
```
## Local SOBO Optimization
Here bayesian optimization is performed with setting `gamma` parameter of the LSR-BO method to 0 which results in a pure local optimization with respect to the last random sample.
```{python}
#| papermill: {duration: null, end_time: null, exception: null, start_time: null, status: pending}
#| tags: []
local_results = [
run(
Branin(locality_factor=0.5),
strategy_factory=lambda domain: strategies.map(
SoboStrategy(
domain=domain,
acquisition_function=qEI(),
acquisition_optimizer=BotorchOptimizer(
local_search_config=LSRBO(gamma=0)
),
),
),
n_iterations=80 if not SMOKE_TEST else 1,
metric=best,
initial_sampler=sample,
n_runs=1,
n_procs=1,
)
for _ in range(5 if not SMOKE_TEST else 1)
]
```
## Global SOBO Optimization (Projection)
Here bayesian optimization is performed with setting `gamma` parameter of the LSR-BO method to 500 which results in taking always the biggest step in the direction of the global candidate. In the original paper, this is called "Projection".
```{python}
#| papermill: {duration: null, end_time: null, exception: null, start_time: null, status: pending}
#| tags: []
global_results = [
run(
Branin(locality_factor=0.5),
strategy_factory=lambda domain: strategies.map(
SoboStrategy(
domain=domain,
acquisition_function=qEI(),
acquisition_optimizer=BotorchOptimizer(
local_search_config=LSRBO(gamma=500)
),
),
),
n_iterations=80 if not SMOKE_TEST else 1,
metric=best,
initial_sampler=sample,
n_runs=1,
n_procs=1,
)
for _ in range(5 if not SMOKE_TEST else 1)
]
```
## LSR-BO
Here the actual method from the paper is performed with setting `gamma` to 0.1.
```{python}
#| papermill: {duration: null, end_time: null, exception: null, start_time: null, status: pending}
#| tags: []
lsr_results = [
run(
Branin(locality_factor=0.5),
strategy_factory=lambda domain: strategies.map(
SoboStrategy(
domain=domain,
acquisition_function=qEI(),
acquisition_optimizer=BotorchOptimizer(
local_search_config=LSRBO(gamma=0.1)
),
),
),
n_iterations=80 if not SMOKE_TEST else 1,
metric=best,
initial_sampler=sample,
n_runs=1,
n_procs=1,
)
for _ in range(5 if not SMOKE_TEST else 1)
]
```
## Plot the results
```{python}
#| papermill: {duration: null, end_time: null, exception: null, start_time: null, status: pending}
#| tags: []
if not SMOKE_TEST:
fig, ax = plt.subplots()
best_random = np.array(
[random_results[i][0][1] for i in range(len(random_results))]
)
ax.plot(range(80), best_random.mean(axis=0), color="gray", label="Random")
ax.fill_between(
range(80),
(best_random.mean(0) - best_random.std(0)),
(best_random.mean(0) + best_random.std(0)),
alpha=0.3,
color="gray",
)
best_global = np.log10(
np.array([global_results[i][0][1] for i in range(len(global_results))])
- 0.397887,
)
ax.plot(range(80), best_global.mean(axis=0), color="orange", label="Projection")
ax.fill_between(
range(80),
(best_global.mean(0) - best_global.std(0)),
(best_global.mean(0) + best_global.std(0)),
alpha=0.3,
color="orange",
)
best_local = np.log10(
np.array([local_results[i][0][1] for i in range(len(global_results))])
- 0.397887,
)
ax.plot(range(80), best_local.mean(axis=0), color="green", label="Local")
ax.fill_between(
range(80),
(best_local.mean(0) - best_local.std(0)),
(best_local.mean(0) + best_local.std(0)),
alpha=0.3,
color="green",
)
best_lsr = np.log10(
np.array([lsr_results[i][0][1] for i in range(len(lsr_results))]) - 0.397887,
)
ax.plot(range(80), best_lsr.mean(axis=0), color="blue", label="LSR")
ax.fill_between(
range(80),
(best_lsr.mean(0) - best_lsr.std(0)),
(best_lsr.mean(0) + best_lsr.std(0)),
alpha=0.3,
color="blue",
)
best_unconstrained = np.log10(
np.array([sobo_results[i][0][1] for i in range(len(sobo_results))]) - 0.397887,
)
ax.plot(
range(80), best_unconstrained.mean(axis=0), color="red", label="Unconstrained"
)
ax.fill_between(
range(80),
(best_unconstrained.mean(0) - best_unconstrained.std(0)),
(best_unconstrained.mean(0) + best_unconstrained.std(0)),
alpha=0.3,
color="red",
)
ax.set_xlabel("Iteration")
ax.set_ylabel("Log10(SimpleRegret)")
ax.legend()
plt.show()
```