Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions smac/facade/abstract_facade.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ class AbstractFacade:
----------
scenario : Scenario
The scenario object, holding all environmental information.
target_function : Callable | str | AbstractRunner
target_function : Callable | str | AbstractRunner | None, defaults to None
This function is called internally to judge a trial's performance. If a string is passed,
it is assumed to be a script. In this case, ``TargetFunctionScriptRunner`` is used to run the script.
In the rare case that only ``ask`` and ``tell`` and not ``optimize`` is used to optimize
the hyperparameters, the target_function argument can be None, because SMAC no longer is
charge of the evaluation of the configuration and thus does not need to know about it.
model : AbstractModel | None, defaults to None
The surrogate model.
acquisition_function : AbstractAcquisitionFunction | None, defaults to None
Expand Down Expand Up @@ -105,8 +108,8 @@ class AbstractFacade:
def __init__(
self,
scenario: Scenario,
target_function: Callable | str | AbstractRunner,
*,
target_function: Callable | str | AbstractRunner | None = None,
model: AbstractModel | None = None,
acquisition_function: AbstractAcquisitionFunction | None = None,
acquisition_maximizer: AbstractAcquisitionMaximizer | None = None,
Expand Down Expand Up @@ -175,8 +178,10 @@ def __init__(
self._overwrite = overwrite

# Prepare the algorithm executer
runner: AbstractRunner
if isinstance(target_function, AbstractRunner):
runner: AbstractRunner | None
if isinstance(target_function, AbstractRunner) or target_function is None:
# in case the target_function is None (e.g. we purely use ask & tell)
# we let smbo.optimize raise an error
runner = target_function
elif isinstance(target_function, str):
runner = TargetFunctionScriptRunner(
Expand All @@ -192,7 +197,7 @@ def __init__(
)

# In case of multiple jobs, we need to wrap the runner again using DaskParallelRunner
if (n_workers := scenario.n_workers) > 1 or dask_client is not None:
if ((n_workers := scenario.n_workers) > 1 or dask_client is not None) and runner is not None:
if dask_client is not None and n_workers > 1:
logger.warning(
"Provided `dask_client`. Ignore `scenario.n_workers`, directly set `n_workers` in `dask_client`."
Expand Down Expand Up @@ -261,7 +266,7 @@ def meta(self) -> dict[str, Any]:

meta = {
"facade": {"name": self.__class__.__name__},
"runner": self._runner.meta,
"runner": self._runner.meta if self._runner is not None else None,
"model": self._model.meta,
"acquisition_maximizer": self._acquisition_maximizer.meta,
"acquisition_function": self._acquisition_function.meta,
Expand Down
22 changes: 20 additions & 2 deletions smac/main/smbo.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ class SMBO:
----------
scenario : Scenario
The scenario object, holding all environmental information.
runner : AbstractRunner
runner : AbstractRunner | None
The runner (containing the target function) is called internally to judge a trial's performance.
In the rare case that ``optimize`` is never called and SMBO is operated with ``ask`` and ``tell`` only,
the runner is allowed to be None
runhistory : Runhistory
The runhistory stores all trials.
intensifier : AbstractIntensifier
Expand All @@ -60,7 +62,7 @@ class SMBO:
def __init__(
self,
scenario: Scenario,
runner: AbstractRunner,
runner: AbstractRunner | None,
runhistory: RunHistory,
intensifier: AbstractIntensifier,
overwrite: bool = False,
Expand Down Expand Up @@ -290,6 +292,11 @@ def optimize(self, *, data_to_scatter: dict[str, Any] | None = None) -> Configur
callback.on_start(self)

dask_data_to_scatter = {}
if self._runner is None:
raise ValueError(
"Runner is not set in SMBO. Likely issue is that the target_function was not set in the Facade."
)

if isinstance(self._runner, DaskParallelRunner) and data_to_scatter is not None:
dask_data_to_scatter = dict(data_to_scatter=self._runner._client.scatter(data_to_scatter, broadcast=True))
elif data_to_scatter is not None:
Expand Down Expand Up @@ -435,6 +442,12 @@ def _add_results(self) -> None:
"""Adds results from the runner to the runhistory. Although most of the functionality could be written
in the tell method, we separate it here to make it accessible for the automatic optimization procedure only.
"""
if self._runner is None:
raise ValueError(
"Runner is not set in SMBO. Likely issue is that the target_function was not set "
"in the Facade. So we cannot query the runner for results."
)

# Check if there is any result
for trial_info, trial_value in self._runner.iter_results():
# Add the results of the run to the run history
Expand Down Expand Up @@ -578,6 +591,11 @@ def validate(
The averaged cost of the configuration. In case of multi-fidelity, the cost of each objective is
averaged.
"""
if self._runner is None:
raise ValueError(
"Runner is not set in SMBO. Likely issue is that the target_function was not set in the Facade."
)

if seed is None:
seed = self._scenario.seed

Expand Down
Loading