Skip to content

Commit 7869c90

Browse files
authored
Merge pull request #100 from Luguza/fix_issue_99
Fixed issue 99
2 parents 90bc029 + 9dfb91c commit 7869c90

3 files changed

Lines changed: 32 additions & 8 deletions

File tree

LICENSE.txt renamed to LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright [yyyy] [name of copyright owner]
189+
Copyright [2021] [AutoML Freiburg]
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
[![Static Badge](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20-blue)](https://pypi.org/project/dehb/)
88
[![arXiv](https://img.shields.io/badge/arXiv-2105.09821-b31b1b.svg)](https://arxiv.org/abs/2105.09821)
99

10+
> **_NOTE:_** Following the release of v0.1.2, this project will be maintained for stability and compatibility purposes but will no longer undergo active development. While new features will not be added, the repository will continue to receive necessary updates to ensure ongoing functionality. For any feature requests, please feel free to fork the repository and submit a pull request.
11+
1012
Welcome to DEHB, an algorithm for Hyperparameter Optimization (HPO). DEHB uses Differential Evolution (DE) under-the-hood as an Evolutionary Algorithm to power the black-box optimization that HPO problems pose.
1113

1214
`dehb` is a python package implementing the [DEHB](https://arxiv.org/abs/2105.09821) algorithm. It offers an intuitive interface to optimize user-defined problems using DEHB.

src/dehb/optimizers/dehb.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ def __getstate__(self):
269269
d = dict(self.__dict__)
270270
d["client"] = None # hack to allow Dask client to be a class attribute
271271
d["logger"] = None # hack to allow logger object to be a class attribute
272+
d["_runtime_budget_timer"] = None # hack to allow timer object to be a class attribute
272273
return d
273274

274275
def __del__(self):
@@ -832,7 +833,7 @@ def _save_incumbent(self):
832833
res = {}
833834
if self.use_configspace:
834835
config = self.vector_to_configspace(self.inc_config)
835-
res["config"] = config.get_dictionary()
836+
res["config"] = dict(config)
836837
else:
837838
res["config"] = self.inc_config.tolist()
838839
res["score"] = self.inc_score
@@ -849,8 +850,11 @@ def _save_history(self, name="history.parquet.gzip"):
849850
return
850851
try:
851852
history_path = self.output_path / name
852-
history_df = pd.DataFrame(self.history, columns=["config_id", "config", "fitness",
853-
"cost", "fidelity", "info"])
853+
# Persist bracket_id to reconstruct serial replay order later
854+
history_df = pd.DataFrame(
855+
self.history,
856+
columns=["bracket_id", "config_id", "config", "fitness", "cost", "fidelity", "info"],
857+
)
854858
# Check if the 'info' column is empty or contains only None values
855859
if history_df["info"].apply(lambda x: (isinstance(x, dict) and len(x) == 0)).all():
856860
# Drop the 'info' column
@@ -935,12 +939,20 @@ def _load_checkpoint(self, run_dir: str):
935939
history_path = run_dir / "history.parquet.gzip"
936940
history = pd.read_parquet(history_path)
937941

938-
# Replay history
942+
# Sort history to emulate serial execution order if bracket_id available
943+
if "bracket_id" in history.columns:
944+
history = history.sort_values(by=["bracket_id", "fidelity", "config_id"]).reset_index(drop=True)
945+
else:
946+
# Fallback ordering for older checkpoints
947+
history = history.sort_values(by=["fidelity", "config_id"]).reset_index(drop=True)
948+
949+
# Replay history in the chosen order
939950
for _, row in history.iterrows():
940951
job_info = {
941952
"fidelity": row["fidelity"],
942953
"config_id": row["config_id"],
943954
"config": np.array(row["config"]),
955+
**({"bracket_id": int(row["bracket_id"]) } if "bracket_id" in history.columns else {}),
944956
}
945957
result = {
946958
"fitness": row["fitness"],
@@ -992,6 +1004,8 @@ def tell(self, job_info: dict, result: dict, replay: bool=False) -> None:
9921004
job_info_container["fidelity"] = job_info["fidelity"]
9931005
job_info_container["config"] = job_info["config"]
9941006
job_info_container["config_id"] = job_info["config_id"]
1007+
if "bracket_id" in job_info:
1008+
job_info_container["bracket_id"] = job_info["bracket_id"]
9951009

9961010
# Update entry in ConfigRepository
9971011
self.config_repository.configs[job_info["config_id"]].config = job_info["config"]
@@ -1035,8 +1049,16 @@ def tell(self, job_info: dict, result: dict, replay: bool=False) -> None:
10351049
inc_changed = True
10361050
# book-keeping
10371051
self._update_trackers(
1038-
traj=self.inc_score, runtime=cost, history=(
1039-
config_id, config.tolist(), float(fitness), float(cost), float(fidelity), info,
1052+
traj=self.inc_score,
1053+
runtime=cost,
1054+
history=(
1055+
bracket_id,
1056+
config_id,
1057+
config.tolist(),
1058+
float(fitness),
1059+
float(cost),
1060+
float(fidelity),
1061+
info,
10401062
),
10411063
)
10421064

@@ -1166,7 +1188,7 @@ def run(self, fevals=None, brackets=None, total_cost=None, single_node_with_gpus
11661188
self.logger.info("Incumbent config: ")
11671189
if self.use_configspace:
11681190
config = self.vector_to_configspace(self.inc_config)
1169-
for k, v in config.get_dictionary().items():
1191+
for k, v in dict(config).items():
11701192
self.logger.info(f"{k}: {v}")
11711193
else:
11721194
self.logger.info(f"{self.inc_config}")

0 commit comments

Comments
 (0)