Skip to content

Commit 2dce548

Browse files
authored
Hotfix/random proposals until valid evals (#118)
* fix sampling of random specs until enough valid evals reported * simplify num_initial_random check --------- Signed-off-by: Grossberger Lukas (CR/AIR2.2) <Lukas.Grossberger@de.bosch.com>
1 parent 36cd141 commit 2dce548

File tree

2 files changed

+58
-4
lines changed

2 files changed

+58
-4
lines changed

blackboxopt/optimizers/botorch_base.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ def __init__(
173173
num_initial_random_samples: Size of the initial space-filling design that
174174
is used before starting BO. The points are sampled randomly in the
175175
search space. If no random sampling is required, set it to 0.
176+
When random sampling is enabled, but evaluations with missing objective
177+
values are reported, more specifications are sampled until
178+
`num_initial_random_samples` many valid evaluations were reported.
176179
max_pending_evaluations: Maximum number of parallel evaluations. For
177180
sequential BO use the default value of 1. If no limit is required,
178181
set it to None.
@@ -275,17 +278,18 @@ def generate_evaluation_specification(self) -> EvaluationSpecification:
275278
):
276279
raise OptimizerNotReady
277280

281+
# Generate random samples until there are enough samples where at least one of
282+
# the objective values is available
278283
if self.num_initial_random > 0 and (
279-
self.X.size(-2) < self.num_initial_random
280-
or torch.nonzero(~torch.any(self.losses.isnan(), dim=1)).numel() == 0
284+
sum(~torch.any(self.losses.isnan(), dim=1)) < self.num_initial_random
281285
):
282-
# We keep generating random samples until there are enough samples, and
283-
# at least one of them has a valid objective
284286
eval_spec = EvaluationSpecification(
285287
configuration=self.search_space.sample(),
288+
optimizer_info={"model_based_pick": False},
286289
)
287290
else:
288291
eval_spec = self._generate_evaluation_specification()
292+
eval_spec.optimizer_info["model_based_pick"] = True
289293

290294
eval_id = self.X.size(-2) + len(self.pending_specifications)
291295
eval_spec.optimizer_info["evaluation_id"] = eval_id

tests/optimizers/botorch_base_test.py

+50
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,56 @@ def test_find_optimum_in_1d_discrete_space(seed):
170170
assert opt.objective.name in best.objectives
171171

172172

173+
def test_propose_random_until_enough_evaluations_without_missing_objective_values(seed):
174+
space = ps.ParameterSpace()
175+
space.add(ps.IntegerParameter("integ", (0, 2)))
176+
batch_shape = torch.Size()
177+
178+
opt = SingleObjectiveBOTorchOptimizer(
179+
search_space=space,
180+
objective=Objective("loss", greater_is_better=False),
181+
model=SingleTaskGP(
182+
torch.empty((*batch_shape, 0, len(space)), dtype=torch.float64),
183+
torch.empty((*batch_shape, 0, 1), dtype=torch.float64),
184+
),
185+
acquisition_function_factory=partial(
186+
UpperConfidenceBound, beta=1.0, maximize=False
187+
),
188+
num_initial_random_samples=2,
189+
max_pending_evaluations=1,
190+
seed=seed,
191+
)
192+
193+
es = opt.generate_evaluation_specification()
194+
assert not es.optimizer_info[
195+
"model_based_pick"
196+
], "No evaluation reported, 0 < 2 initial random samples"
197+
opt.report(
198+
es.create_evaluation(objectives={"loss": es.configuration["integ"] ** 2}),
199+
)
200+
201+
es = opt.generate_evaluation_specification()
202+
assert not es.optimizer_info[
203+
"model_based_pick"
204+
], "One evaluation reported, 1 < 2 initial random samples"
205+
opt.report(
206+
es.create_evaluation(objectives={"loss": None}),
207+
)
208+
209+
es = opt.generate_evaluation_specification()
210+
assert not es.optimizer_info[
211+
"model_based_pick"
212+
], "One valid evaluation reported, 1 < 2 initial random samples"
213+
opt.report(
214+
es.create_evaluation(objectives={"loss": es.configuration["integ"] ** 2}),
215+
)
216+
217+
es = opt.generate_evaluation_specification()
218+
assert es.optimizer_info[
219+
"model_based_pick"
220+
], "Two valid evaluations reported, 2 >= 2 initial random samples"
221+
222+
173223
def test_get_numerical_points_from_discrete_space():
174224
p0l, p0h = -5, 10
175225
p1 = ("small", "medium", "large")

0 commit comments

Comments
 (0)