Skip to content

Commit 3995607

Browse files
committed
List of results for multi-objective
1 parent 9dc7d57 commit 3995607

2 files changed

Lines changed: 21 additions & 12 deletions

File tree

plugboard/tune/tune.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,15 +136,20 @@ async def _run_process(process: Process) -> None: # pragma: no cover
136136
async with process:
137137
await process.run()
138138

139-
def run(self, spec: ProcessSpec) -> ray.tune.Result:
139+
@property
140+
def is_multi_objective(self) -> bool:
141+
"""Returns `True` if the optimisation is multi-objective."""
142+
return len(self._objective) > 1
143+
144+
def run(self, spec: ProcessSpec) -> ray.tune.Result | list[ray.tune.Result]:
140145
"""Run the optimisation job on Ray.
141146
142147
Args:
143148
spec: The [`ProcessSpec`][plugboard.schemas.ProcessSpec] to optimise.
144149
145150
Returns:
146-
A [`Result`][ray.tune.Result] containing the best trial result. Use the `result_grid`
147-
property to get full trial results.
151+
Either a single of list of [`Result`][ray.tune.Result] objects containing the best trial
152+
result. Use the `result_grid` property to get full trial results.
148153
"""
149154
self._logger.info("Running optimisation job on Ray")
150155
spec = spec.model_copy()
@@ -187,8 +192,11 @@ def _objective( # pragma: no cover
187192
self._logger.info("Starting Tuner")
188193
self._result_grid = _tune.fit()
189194
self._logger.info("Tuner finished")
190-
return self._result_grid.get_best_result(
191-
# Choose the first metric and mode if multiple are provided
192-
metric=self._metric[0] if isinstance(self._metric, list) else self._metric,
193-
mode=self._mode[0] if isinstance(self._mode, list) else self._mode,
194-
)
195+
if self.is_multi_objective:
196+
return [
197+
self._result_grid.get_best_result(metric=metric, mode=mode)
198+
for metric, mode in zip(self._metric, self._mode)
199+
]
200+
if isinstance(self._metric, list) or isinstance(self._mode, list): # pragma: no cover
201+
raise RuntimeError("Invalid configuration found for single-objective optimisation.")
202+
return self._result_grid.get_best_result(metric=self._metric, mode=self._mode)

tests/integration/test_tuner.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,8 @@ def test_multi_objective_tune(config: dict) -> None:
110110
# There must be no failed trials
111111
assert not [t for t in result if t.error]
112112
# Results must contain two objectives and correct optimimum must be found
113-
assert best_result.config["a.iters"] == 2
114-
assert best_result.config["b.factor"] == -1
115-
assert best_result.metrics["c.in_1"] == 1
116-
assert best_result.metrics["b.out_1"] == -1
113+
# The best result must be a list of two results
114+
assert best_result[0].config["a.iters"] == 2
115+
assert best_result[1].config["b.factor"] == -1
116+
assert best_result[0].metrics["c.in_1"] == 1
117+
assert best_result[1].metrics["b.out_1"] == -1

0 commit comments

Comments
 (0)