Skip to content

Commit 9675832

Browse files
author
Sarah Krebs
committed
Changes required for considering multiple budgets
1 parent dbef496 commit 9675832

File tree

8 files changed

+56
-36
lines changed

8 files changed

+56
-36
lines changed

deepcave/evaluators/footprint.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def get_surface(
241241
Steps to create the meshgrid. By default 0.5.
242242
performance : bool, optional
243243
Whether to get the surface from the performance or the valid areas.
244-
Default is set to True.
244+
Default is set to True (i.e. from performance).
245245
246246
Returns
247247
-------

deepcave/plugins/budget/budget_correlation.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,17 +171,25 @@ def process(run: AbstractRun, inputs: Dict[str, int]) -> Dict[str, Any]:
171171
budget2 = run.get_budget(budget2_id)
172172
budget2_readable = run.get_budget(budget2_id, human=True)
173173

174-
costs1 = run.get_all_costs(budget1, statuses=[Status.SUCCESS])
175-
costs2 = run.get_all_costs(budget2, statuses=[Status.SUCCESS])
174+
config_ids1 = run.get_configs(budget1, statuses=[Status.SUCCESS]).keys()
175+
config_ids2 = run.get_configs(budget2, statuses=[Status.SUCCESS]).keys()
176176

177177
# Combine config ids
178178
# So it is guaranteed that there is the same number of configs for each budget
179-
config_ids = set(costs1.keys()) & set(costs2.keys())
179+
config_ids = set(config_ids1) & set(config_ids2)
180180

181181
c1, c2 = [], []
182182
for config_id in config_ids:
183-
c1 += [costs1[config_id][objective_id]]
184-
c2 += [costs2[config_id][objective_id]]
183+
c1 += [
184+
run.get_avg_costs(config_id, budget1, statuses=[Status.SUCCESS])[0][
185+
objective_id
186+
]
187+
]
188+
c2 += [
189+
run.get_avg_costs(config_id, budget2, statuses=[Status.SUCCESS])[0][
190+
objective_id
191+
]
192+
]
185193

186194
correlation = round(stats.spearmanr(c1, c2).correlation, 2)
187195
correlations_symmetric["Budget"][budget2_readable] = budget2_readable # type: ignore # noqa: E501

deepcave/plugins/summary/configurations.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from deepcave.constants import VALUE_RANGE
2525
from deepcave.plugins.dynamic import DynamicPlugin
2626
from deepcave.runs import AbstractRun
27+
from deepcave.runs.status import Status
2728
from deepcave.utils.compression import deserialize, serialize
2829
from deepcave.utils.layout import create_table, get_slider_marks
2930
from deepcave.utils.styled_plotty import (
@@ -214,9 +215,12 @@ def process(run, inputs) -> Dict[str, Any]: # type: ignore
214215
for seed in seeds:
215216
try:
216217
cost.append(
217-
run.get_costs(config_id=selected_config_id, budget=budget, seed=seed)[
218-
seed
219-
][objective_id]
218+
run.get_costs(
219+
config_id=selected_config_id,
220+
budget=budget,
221+
seed=seed,
222+
statuses=[Status.SUCCESS],
223+
)[seed][objective_id]
220224
)
221225
seeds_evaluated += 1
222226
except Exception:
@@ -234,7 +238,7 @@ def process(run, inputs) -> Dict[str, Any]: # type: ignore
234238
else:
235239
performances_table_data[objective.name] += [cost]
236240
else:
237-
performances[objective.name][budget] = None
241+
performances[objective.name][budget] = np.nan
238242
if len(seeds) > 1:
239243
performances_table_data[f"{objective.name}"] += ["No seed evaluated"]
240244
else:
@@ -358,13 +362,18 @@ def _get_objective_figure(
358362
"""
359363
objective_data = []
360364
for i, (metric, values) in enumerate(outputs["performances"].items()):
365+
mean_objective_values, std_objective_values = [], []
366+
for objective_values in values.values():
367+
mean_objective_values.append(np.nanmean(objective_values))
368+
std_objective_values.append(np.nanstd(objective_values))
369+
361370
trace_kwargs = {
362371
"x": list(values.keys()),
363-
"y": np.mean(np.array(list(values.values())), axis=1),
372+
"y": mean_objective_values,
364373
"error_y": dict(
365374
type="data",
366375
symmetric=True,
367-
array=np.std(np.array(list(values.values())), axis=1),
376+
array=std_objective_values,
368377
),
369378
"name": metric,
370379
"fill": "tozeroy",

deepcave/plugins/summary/overview.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -126,20 +126,17 @@ def load_outputs(run, *_: Any) -> List[Any]: # type: ignore
126126
A list of the created tables of the overview.
127127
"""
128128
# Get best cost across all objectives, highest budget
129-
incumbent, _ = run.get_incumbent()
129+
incumbent, _ = run.get_incumbent(statuses=[Status.SUCCESS])
130130
config_id = run.get_config_id(incumbent)
131131
objective_names = run.get_objective_names()
132132

133-
best_performance = {}
134-
135-
avg_costs = run.get_avg_costs(config_id)
136-
137-
for idx in range(len(objective_names)):
138-
best_performance[objective_names[idx]] = avg_costs[idx]
133+
avg_costs, std_costs = run.get_avg_costs(config_id)
139134

140135
best_performances = []
141-
for name, value in best_performance.items():
142-
best_performances += [f"{round(value, 2)} ({name})"]
136+
for idx in range(len(objective_names)):
137+
best_performances += [
138+
f"{round(avg_costs[idx], 2)} ± {round(std_costs[idx], 2)} ({objective_names[idx]})"
139+
]
143140

144141
optimizer = run.prefix
145142
if isinstance(run, Group):

deepcave/runs/__init__.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -823,9 +823,6 @@ def get_all_costs(
823823
else:
824824
history = self.history
825825
for trial in history:
826-
if trial.config_id not in results:
827-
results[trial.config_id] = {}
828-
829826
if statuses is not None:
830827
if isinstance(statuses, Status):
831828
statuses = [statuses]
@@ -844,12 +841,15 @@ def get_all_costs(
844841
latest_budget = highest_evaluated_budget[trial.config_id]
845842
# Only the highest budget is kept
846843
if trial.budget >= latest_budget:
844+
if trial.config_id not in results:
845+
results[trial.config_id] = {}
847846
results[trial.config_id][trial.seed] = trial.costs
848847
else:
849848
if trial.budget is not None:
850849
if trial.budget != budget:
851850
continue
852-
851+
if trial.config_id not in results:
852+
results[trial.config_id] = {}
853853
results[trial.config_id][trial.seed] = trial.costs
854854
return results
855855

@@ -939,19 +939,21 @@ def get_incumbent(
939939
min_cost = np.inf
940940
best_config_id = None
941941

942-
results = self.get_all_costs(budget, statuses, seed, selected_ids)
942+
results = self.get_all_costs(
943+
budget=budget, statuses=statuses, seed=seed, selected_ids=selected_ids
944+
)
943945

944946
seed_count = {}
945947
for config_id, costs in results.items():
946-
seed_count[config_id] = len(costs.values())
948+
seed_count[config_id] = len(costs)
947949
max_seed_count = max(seed_count.values())
948950

949951
for config_id, costs in results.items():
950952
# If there are multiple seeds, only configurations evaluated on all seeds are
951953
# considered. From these configurations, the one with the highest average cost
952954
# over the seeds is considered as the incumbent.
953955
if max_seed_count > 1:
954-
if len(costs.values()) < max_seed_count:
956+
if len(costs) < max_seed_count:
955957
continue
956958

957959
# Get average over all seeds
@@ -1396,7 +1398,7 @@ def check_equality(
13961398
configspace: bool = True,
13971399
objectives: bool = True,
13981400
budgets: bool = True,
1399-
seeds: bool = True,
1401+
seeds: bool = False,
14001402
) -> Dict[str, Any]:
14011403
"""
14021404
Check the passed runs on equality based on the selected runs.
@@ -1408,15 +1410,15 @@ def check_equality(
14081410
runs : list[AbstractRun]
14091411
Runs to check for equality.
14101412
meta : bool, optional
1411-
Meta-Data excluding objectives and budgets, by default True.
1413+
Meta-Data excluding objectives and budgets, by default False.
14121414
configspace : bool, optional
14131415
Wheter to include the configuration space, by default True.
14141416
objectives : bool, optional
14151417
Wheter to include the objectives, by default True.
14161418
budgets : bool, optional
14171419
Whether to include the budgets, by default True.
14181420
seeds : bool, optional
1419-
Whether to include the seeds, by default True.
1421+
Whether to include the seeds, by default False.
14201422
14211423
Returns
14221424
-------
@@ -1517,7 +1519,7 @@ def check_equality(
15171519
for run in runs:
15181520
s2 = run.get_seeds(include_combined=False)
15191521
if s1 != s2:
1520-
raise NotMergeableError("Seeds of runs are not equal.")
1522+
raise NotMergeableError("Seeds of runs are not equal.", RunInequality.INEQ_SEED)
15211523

15221524
result["seeds"] = s1
15231525
if meta:

deepcave/runs/exceptions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ class RunInequality(Enum):
3434
INEQ_OBJECTIVE = 2
3535
INEQ_BUDGET = 3
3636
INEQ_CONFIGSPACE = 4
37+
INEQ_SEED = 5

deepcave/runs/group.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def __init__(self, name: str, runs: List[AbstractRun]):
103103
# Deep copy trial
104104
trial = deepcopy(trial)
105105

106-
(config_id, budget) = trial.get_key()
106+
(config_id, budget, seed) = trial.get_key()
107107

108108
# Config id might have changed
109109
new_config_id = config_mapping[config_id]

deepcave/utils/styled_plotty.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -474,12 +474,15 @@ def get_hovertext_from_config(run: AbstractRun, config_id: int) -> str:
474474
objectives = run.get_objectives()
475475
budget = run.get_highest_budget(config_id)
476476

477-
avg_costs = run.get_avg_costs(config_id)
477+
avg_costs, std_costs = run.get_avg_costs(config_id, budget=budget)
478478

479479
assert budget is not None
480480
string += f"<b>Objectives</b> (on highest found budget {round(budget, 2)})<br>"
481-
for objective, cost in zip(objectives, avg_costs):
482-
string += f"{objective.name}: {cost}<br>"
481+
for objective, cost, std_cost in zip(objectives, avg_costs, std_costs):
482+
if std_cost == 0.0:
483+
string += f"{objective.name}: {cost}<br>"
484+
else:
485+
string += f"{objective.name}: {cost} ± {std_cost}<br>"
483486

484487
string += "<br><b>Hyperparameters</b>:<br>"
485488

0 commit comments

Comments
 (0)