Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix differential evolution #1150

Open
wants to merge 3 commits into
base: development
Choose a base branch
from
Open
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
10 changes: 7 additions & 3 deletions smac/acquisition/maximizer/differential_evolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from scipy.optimize._differentialevolution import DifferentialEvolutionSolver

from smac.acquisition.maximizer import AbstractAcquisitionMaximizer
from smac.utils.configspace import transform_continuous_designs

__copyright__ = "Copyright 2022, automl.org"
__license__ = "3-clause BSD"
Expand Down Expand Up @@ -36,7 +37,9 @@ def _maximize(

def func(x: np.ndarray) -> np.ndarray:
assert self._acquisition_function is not None
return -self._acquisition_function([Configuration(self._configspace, vector=x)])
return -self._acquisition_function([transform_continuous_designs(
design=np.expand_dims(x, axis=0), origin="Diffrential Evolution", configspace=self._configspace
)[0]])

ds = DifferentialEvolutionSolver(
func,
Expand All @@ -58,8 +61,9 @@ def func(x: np.ndarray) -> np.ndarray:

_ = ds.solve()
for pop, val in zip(ds.population, ds.population_energies):
rc = Configuration(self._configspace, vector=pop)
rc.origin = "Acquisition Function Maximizer: Differential Evolution"
rc = transform_continuous_designs(
design=np.expand_dims(pop, axis=0), origin="Acquisition Function Maximizer: Differential Evolution", configspace=self._configspace
)[0]
configs.append((-val, rc))

configs.sort(key=lambda t: t[0])
Expand Down
54 changes: 0 additions & 54 deletions smac/initial_design/abstract_initial_design.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,57 +155,3 @@ def select_configurations(self) -> list[Configuration]:
def _select_configurations(self) -> list[Configuration]:
"""Selects the initial configurations, depending on the implementation of the initial design."""
raise NotImplementedError

def _transform_continuous_designs(
self, design: np.ndarray, origin: str, configspace: ConfigurationSpace
) -> list[Configuration]:
"""Transforms the continuous designs into a discrete list of configurations.

Parameters
----------
design : np.ndarray
Array of hyperparameters originating from the initial design strategy.
origin : str | None, defaults to None
Label for a configuration where it originated from.
configspace : ConfigurationSpace

Returns
-------
configs : list[Configuration]
Continuous transformed configs.
"""
params = list(configspace.values())
for idx, param in enumerate(params):
if isinstance(param, IntegerHyperparameter):
design[:, idx] = param.to_vector(param.to_value(design[:, idx]))
elif isinstance(param, NumericalHyperparameter):
continue
elif isinstance(param, Constant):
design_ = np.zeros(np.array(design.shape) + np.array((0, 1)))
design_[:, :idx] = design[:, :idx]
design_[:, idx + 1 :] = design[:, idx:]
design = design_
elif isinstance(param, CategoricalHyperparameter):
v_design = design[:, idx]
v_design[v_design == 1] = 1 - 10**-10
design[:, idx] = np.array(v_design * len(param.choices), dtype=int)
elif isinstance(param, OrdinalHyperparameter):
v_design = design[:, idx]
v_design[v_design == 1] = 1 - 10**-10
design[:, idx] = np.array(v_design * len(param.sequence), dtype=int)
else:
raise ValueError("Hyperparameter not supported when transforming a continuous design.")

configs = []
for vector in design:
try:
conf = deactivate_inactive_hyperparameters(
configuration=None, configuration_space=configspace, vector=vector
)
except ForbiddenValueError:
continue

conf.origin = origin
configs.append(conf)

return configs
3 changes: 2 additions & 1 deletion smac/initial_design/latin_hypercube_design.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from scipy.stats.qmc import LatinHypercube

from smac.initial_design.abstract_initial_design import AbstractInitialDesign
from smac.utils.configspace import transform_continuous_designs

__copyright__ = "Copyright 2022, automl.org"
__license__ = "3-clause BSD"
Expand All @@ -25,6 +26,6 @@ def _select_configurations(self) -> list[Configuration]:

lhd = LatinHypercube(d=len(params) - constants, seed=self._rng.randint(0, 1000000)).random(n=self._n_configs)

return self._transform_continuous_designs(
return transform_continuous_designs(
design=lhd, origin="Initial Design: Latin Hypercube", configspace=self._configspace
)
4 changes: 3 additions & 1 deletion smac/initial_design/sobol_design.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from scipy.stats.qmc import Sobol

from smac.initial_design.abstract_initial_design import AbstractInitialDesign
from smac.utils.configspace import transform_continuous_designs


__copyright__ = "Copyright 2022, automl.org"
__license__ = "3-clause BSD"
Expand Down Expand Up @@ -43,6 +45,6 @@ def _select_configurations(self) -> list[Configuration]:
warnings.simplefilter("ignore")
sobol = sobol_gen.random(self._n_configs)

return self._transform_continuous_designs(
return transform_continuous_designs(
design=sobol, origin="Initial Design: Sobol", configspace=self._configspace
)
58 changes: 58 additions & 0 deletions smac/utils/configspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
OrdinalHyperparameter,
UniformFloatHyperparameter,
UniformIntegerHyperparameter,
IntegerHyperparameter,
NumericalHyperparameter,
)
from ConfigSpace.util import ForbiddenValueError, deactivate_inactive_hyperparameters
from ConfigSpace.util import get_one_exchange_neighbourhood

__copyright__ = "Copyright 2022, automl.org"
Expand Down Expand Up @@ -182,6 +185,61 @@ def print_config_changes(
logger.debug(msg)


def transform_continuous_designs(
design: np.ndarray, origin: str, configspace: ConfigurationSpace
) -> list[Configuration]:
"""Transforms the continuous designs into a discrete list of configurations.

Parameters
----------
design : np.ndarray
Array of hyperparameters originating from the initial design strategy.
origin : str | None, defaults to None
Label for a configuration where it originated from.
configspace : ConfigurationSpace

Returns
-------
configs : list[Configuration]
Continuous transformed configs.
"""
params = configspace.get_hyperparameters()
for idx, param in enumerate(params):
if isinstance(param, IntegerHyperparameter):
design[:, idx] = param._inverse_transform(param._transform(design[:, idx]))
elif isinstance(param, NumericalHyperparameter):
continue
elif isinstance(param, Constant):
design_ = np.zeros(np.array(design.shape) + np.array((0, 1)))
design_[:, :idx] = design[:, :idx]
design_[:, idx + 1 :] = design[:, idx:]
design = design_
elif isinstance(param, CategoricalHyperparameter):
v_design = design[:, idx]
v_design[v_design == 1] = 1 - 10**-10
design[:, idx] = np.array(v_design * len(param.choices), dtype=int)
elif isinstance(param, OrdinalHyperparameter):
v_design = design[:, idx]
v_design[v_design == 1] = 1 - 10**-10
design[:, idx] = np.array(v_design * len(param.sequence), dtype=int)
else:
raise ValueError("Hyperparameter not supported when transforming a continuous design.")

configs = []
for vector in design:
try:
conf = deactivate_inactive_hyperparameters(
configuration=None, configuration_space=configspace, vector=vector
)
except ForbiddenValueError:
continue

conf.origin = origin
configs.append(conf)

return configs


# def check_subspace_points(
# X: np.ndarray,
# cont_dims: np.ndarray | list = [],
Expand Down