From ab9cb6af3094053e29fd56e1d6fe41775c8602af Mon Sep 17 00:00:00 2001 From: Hadar Shavit Date: Wed, 9 Oct 2024 13:11:09 +0000 Subject: [PATCH 1/7] Fix differential evolution --- .../maximizer/differential_evolution.py | 10 +++- .../initial_design/abstract_initial_design.py | 54 ----------------- smac/initial_design/latin_hypercube_design.py | 3 +- smac/initial_design/sobol_design.py | 4 +- smac/utils/configspace.py | 58 +++++++++++++++++++ 5 files changed, 70 insertions(+), 59 deletions(-) diff --git a/smac/acquisition/maximizer/differential_evolution.py b/smac/acquisition/maximizer/differential_evolution.py index 0f2ce15e6..855842783 100644 --- a/smac/acquisition/maximizer/differential_evolution.py +++ b/smac/acquisition/maximizer/differential_evolution.py @@ -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" @@ -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, @@ -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]) diff --git a/smac/initial_design/abstract_initial_design.py b/smac/initial_design/abstract_initial_design.py index 4b5224933..c9dc9376b 100644 --- a/smac/initial_design/abstract_initial_design.py +++ b/smac/initial_design/abstract_initial_design.py @@ -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 diff --git a/smac/initial_design/latin_hypercube_design.py b/smac/initial_design/latin_hypercube_design.py index 8cd3cf2a9..6a073299a 100644 --- a/smac/initial_design/latin_hypercube_design.py +++ b/smac/initial_design/latin_hypercube_design.py @@ -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" @@ -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 ) diff --git a/smac/initial_design/sobol_design.py b/smac/initial_design/sobol_design.py index 1c3c646f5..a5c7998d9 100644 --- a/smac/initial_design/sobol_design.py +++ b/smac/initial_design/sobol_design.py @@ -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" @@ -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 ) diff --git a/smac/utils/configspace.py b/smac/utils/configspace.py index 78201f923..1a3612798 100644 --- a/smac/utils/configspace.py +++ b/smac/utils/configspace.py @@ -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" @@ -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 = [], From 759eeff371f71dcbc8244c2009453dbf41e8bfcf Mon Sep 17 00:00:00 2001 From: Hadar Shavit Date: Mon, 28 Oct 2024 21:54:15 +0000 Subject: [PATCH 2/7] Update CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c20493be..ec94ce729 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ ## Dependencies - Allow numpy >= 2.x (#1146) +## Bugfixes +- Fix bug in differential evolution acquisition maximizer in case the search space contains categorical hyperparameters (#1150) + # Examples - Add warmstarting example (#1120) From 3cd9c2d0122410f07cb47661bfda2aad13204bb0 Mon Sep 17 00:00:00 2001 From: Hadar Shavit Date: Tue, 29 Oct 2024 20:59:02 +0000 Subject: [PATCH 3/7] Vectorize diff evo --- .../maximizer/differential_evolution.py | 61 ++++++++++++++++--- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/smac/acquisition/maximizer/differential_evolution.py b/smac/acquisition/maximizer/differential_evolution.py index 855842783..4751ea427 100644 --- a/smac/acquisition/maximizer/differential_evolution.py +++ b/smac/acquisition/maximizer/differential_evolution.py @@ -1,9 +1,10 @@ from __future__ import annotations import numpy as np -from ConfigSpace import Configuration +from ConfigSpace import Configuration, ConfigurationSpace from scipy.optimize._differentialevolution import DifferentialEvolutionSolver +from smac.acquisition.function.abstract_acquisition_function import AbstractAcquisitionFunction from smac.acquisition.maximizer import AbstractAcquisitionMaximizer from smac.utils.configspace import transform_continuous_designs @@ -24,7 +25,42 @@ class DifferentialEvolution(AbstractAcquisitionMaximizer): [1] Storn, R and Price, K, Differential Evolution - a Simple and Efficient Heuristic for Global Optimization over Continuous Spaces, Journal of Global Optimization, 1997, 11, 341 - 359. + + Parameters + ---------- + configspace : ConfigurationSpace + acquisition_function : AbstractAcquisitionFunction + challengers : int, defaults to 50000 + Number of challengers. + max_iter: int | None, defaults to None + Maximum number of iterations that the DE will perform. + strategy: str, defaults to "best1bin" + The strategy to use for the DE. + polish: bool, defaults to True + Whether to polish the final solution using L-BFGS-B. + mutation: tuple[float, float], defaults to (0.5, 1.0) + The mutation constant. + recombination: float, defaults to 0.7 + The recombination constant. + seed : int, defaults to 0 """ + def __init__(self, + configspace: ConfigurationSpace, + acquisition_function: AbstractAcquisitionFunction | None = None, + max_iter: int = 1000, + challengers: int = 50000, + strategy: str = "best1bin", + polish: bool = True, + mutation: tuple[float, float] = (0.5, 1.0), + recombination: float =0.7, + seed: int = 0): + super().__init__(configspace, acquisition_function, challengers, seed) + # raise NotImplementedError("DifferentialEvolution is not yet implemented.") + self.max_iter = max_iter + self.strategy = strategy + self.polish = polish + self.mutation = mutation + self.recombination = recombination def _maximize( self, @@ -37,26 +73,31 @@ def _maximize( def func(x: np.ndarray) -> np.ndarray: assert self._acquisition_function is not None - return -self._acquisition_function([transform_continuous_designs( - design=np.expand_dims(x, axis=0), origin="Diffrential Evolution", configspace=self._configspace - )[0]]) + if len(x.shape) == 1: + return -self._acquisition_function([transform_continuous_designs( + design=np.expand_dims(x, axis=0), origin="Diffrential Evolution", configspace=self._configspace + )[0]]) + return -self._acquisition_function(transform_continuous_designs( + design=x.T, origin="Diffrential Evolution", configspace=self._configspace + )) ds = DifferentialEvolutionSolver( func, bounds=[[0, 1] for _ in range(len(self._configspace))], args=(), - strategy="best1bin", - maxiter=1000, - popsize=50, + strategy=self.strategy, + maxiter=self.max_iter, + popsize=self._challengers // self.max_iter, tol=0.01, - mutation=(0.5, 1), - recombination=0.7, + mutation=self.mutation, + recombination=self.recombination, seed=self._rng.randint(1000), - polish=True, + polish=self.polish, callback=None, disp=False, init="latinhypercube", atol=0, + vectorized=True ) _ = ds.solve() From 1b651e5a74c387761048d498328fcf32f24419ea Mon Sep 17 00:00:00 2001 From: Hadar Shavit Date: Wed, 4 Dec 2024 21:43:54 +0000 Subject: [PATCH 4/7] Add test for categorical search space --- tests/test_acquisition/test_maximizers.py | 52 ++++++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/tests/test_acquisition/test_maximizers.py b/tests/test_acquisition/test_maximizers.py index c1de71617..3e3f70a6a 100644 --- a/tests/test_acquisition/test_maximizers.py +++ b/tests/test_acquisition/test_maximizers.py @@ -200,6 +200,20 @@ def configspace() -> ConfigurationSpace: return cs +@pytest.fixture +def configspace_categorical() -> ConfigurationSpace: + cs = ConfigurationSpace(seed=0) + + a = Categorical("a", ["c1", "c2", "c3"]) + b = Categorical("b", ["c1", "c2", "c3", "c4"]) + c = Float("c", (0, 1), default=0.5) + + # Add all hyperparameters at once: + cs.add([a, b, c]) + + return cs + + @pytest.fixture def model(configspace: ConfigurationSpace): model = RandomForest(configspace) @@ -256,6 +270,13 @@ def test_local_search_2(configspace, acquisition_function): assert values[0][0] >= values[1][0] +def test_local_search_categorical(configspace_categorical, acquisition_function): + start_points = configspace_categorical.sample_configuration(100) + ls = LocalSearch(configspace_categorical, acquisition_function, max_steps=100) + + values = ls._maximize(start_points, 1) + + def test_get_initial_points_moo(configspace): class Model: def predict_marginalized(self, X): @@ -302,6 +323,13 @@ def test_random_search(configspace, acquisition_function): assert all([v[0] == 0 for v in values]) +def test_random_search_categorical(configspace_categorical, acquisition_function): + start_points = configspace_categorical.sample_configuration(100) + rs = RandomSearch(configspace_categorical, acquisition_function) + + values = rs._maximize(start_points, 1) + + def test_random_search_sorted(configspace, acquisition_function): start_points = configspace.sample_configuration(100) rs = RandomSearch(configspace, acquisition_function, challengers=1000) @@ -317,6 +345,12 @@ def test_random_search_sorted(configspace, acquisition_function): assert all([v[0] > 0 for v in values]) +def test_sorted_random_search_categorical(configspace_categorical, acquisition_function): + start_points = configspace_categorical.sample_configuration(100) + rs = RandomSearch(configspace_categorical, acquisition_function) + + values = rs._maximize(start_points, 1, _sorted=True) + # -------------------------------------------------------------- # TestLocalAndRandomSearch # -------------------------------------------------------------- @@ -343,6 +377,13 @@ def test_local_and_random_search(configspace, acquisition_function): assert "Acquisition Function Maximizer: Local Search" in config_origins +def test_local_and_random_search_categorical(configspace_categorical, acquisition_function): + start_points = configspace_categorical.sample_configuration(100) + rs = LocalAndSortedRandomSearch(configspace_categorical, acquisition_function, max_steps=100) + + values = rs._maximize(start_points, 1) + + # -------------------------------------------------------------- # TestLocalAndSortedPriorRandomSearch # -------------------------------------------------------------- @@ -423,7 +464,14 @@ def __call__(self, arrays): def test_differential_evolution(configspace, acquisition_function): start_points = configspace.sample_configuration(100) - rs = DifferentialEvolution(configspace, acquisition_function, challengers=1000) + de = DifferentialEvolution(configspace, acquisition_function, challengers=1000) - values = rs._maximize(start_points, 1) + values = de._maximize(start_points, 1) values[0][1].origin == "Acquisition Function Maximizer: Differential Evolution" + + +def test_differential_evolution_categorical(configspace_categorical, acquisition_function): + start_points = configspace_categorical.sample_configuration(100) + de = DifferentialEvolution(configspace_categorical, acquisition_function) + + values = de._maximize(start_points, 1) From be46d671bffe6d118d77fcc69c054eada457b9e4 Mon Sep 17 00:00:00 2001 From: Hadar Shavit Date: Wed, 4 Dec 2024 21:52:46 +0000 Subject: [PATCH 5/7] Formatting --- .../maximizer/differential_evolution.py | 55 +++++---- smac/utils/configspace.py | 109 +++++++++--------- tests/test_acquisition/test_maximizers.py | 1 + 3 files changed, 91 insertions(+), 74 deletions(-) diff --git a/smac/acquisition/maximizer/differential_evolution.py b/smac/acquisition/maximizer/differential_evolution.py index 4751ea427..d948ec50b 100644 --- a/smac/acquisition/maximizer/differential_evolution.py +++ b/smac/acquisition/maximizer/differential_evolution.py @@ -4,7 +4,9 @@ from ConfigSpace import Configuration, ConfigurationSpace from scipy.optimize._differentialevolution import DifferentialEvolutionSolver -from smac.acquisition.function.abstract_acquisition_function import AbstractAcquisitionFunction +from smac.acquisition.function.abstract_acquisition_function import ( + AbstractAcquisitionFunction, +) from smac.acquisition.maximizer import AbstractAcquisitionMaximizer from smac.utils.configspace import transform_continuous_designs @@ -26,7 +28,7 @@ class DifferentialEvolution(AbstractAcquisitionMaximizer): [1] Storn, R and Price, K, Differential Evolution - a Simple and Efficient Heuristic for Global Optimization over Continuous Spaces, Journal of Global Optimization, 1997, 11, 341 - 359. - Parameters + Parameters ---------- configspace : ConfigurationSpace acquisition_function : AbstractAcquisitionFunction @@ -44,16 +46,19 @@ class DifferentialEvolution(AbstractAcquisitionMaximizer): The recombination constant. seed : int, defaults to 0 """ - def __init__(self, - configspace: ConfigurationSpace, - acquisition_function: AbstractAcquisitionFunction | None = None, - max_iter: int = 1000, - challengers: int = 50000, - strategy: str = "best1bin", - polish: bool = True, - mutation: tuple[float, float] = (0.5, 1.0), - recombination: float =0.7, - seed: int = 0): + + def __init__( + self, + configspace: ConfigurationSpace, + acquisition_function: AbstractAcquisitionFunction | None = None, + max_iter: int = 1000, + challengers: int = 50000, + strategy: str = "best1bin", + polish: bool = True, + mutation: tuple[float, float] = (0.5, 1.0), + recombination: float = 0.7, + seed: int = 0, + ): super().__init__(configspace, acquisition_function, challengers, seed) # raise NotImplementedError("DifferentialEvolution is not yet implemented.") self.max_iter = max_iter @@ -74,12 +79,18 @@ def _maximize( def func(x: np.ndarray) -> np.ndarray: assert self._acquisition_function is not None if len(x.shape) == 1: - return -self._acquisition_function([transform_continuous_designs( - design=np.expand_dims(x, axis=0), origin="Diffrential Evolution", configspace=self._configspace - )[0]]) - return -self._acquisition_function(transform_continuous_designs( - design=x.T, origin="Diffrential Evolution", configspace=self._configspace - )) + return -self._acquisition_function( + [ + transform_continuous_designs( + design=np.expand_dims(x, axis=0), + origin="Diffrential Evolution", + configspace=self._configspace, + )[0] + ] + ) + return -self._acquisition_function( + transform_continuous_designs(design=x.T, origin="Diffrential Evolution", configspace=self._configspace) + ) ds = DifferentialEvolutionSolver( func, @@ -97,14 +108,16 @@ def func(x: np.ndarray) -> np.ndarray: disp=False, init="latinhypercube", atol=0, - vectorized=True + vectorized=True, ) _ = ds.solve() for pop, val in zip(ds.population, ds.population_energies): rc = transform_continuous_designs( - design=np.expand_dims(pop, axis=0), origin="Acquisition Function Maximizer: Differential Evolution", configspace=self._configspace - )[0] + 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]) diff --git a/smac/utils/configspace.py b/smac/utils/configspace.py index 1a3612798..12fe84375 100644 --- a/smac/utils/configspace.py +++ b/smac/utils/configspace.py @@ -11,16 +11,19 @@ BetaIntegerHyperparameter, CategoricalHyperparameter, Constant, + IntegerHyperparameter, NormalFloatHyperparameter, NormalIntegerHyperparameter, + NumericalHyperparameter, OrdinalHyperparameter, UniformFloatHyperparameter, UniformIntegerHyperparameter, - IntegerHyperparameter, - NumericalHyperparameter, ) -from ConfigSpace.util import ForbiddenValueError, deactivate_inactive_hyperparameters -from ConfigSpace.util import get_one_exchange_neighbourhood +from ConfigSpace.util import ( + ForbiddenValueError, + deactivate_inactive_hyperparameters, + get_one_exchange_neighbourhood, +) __copyright__ = "Copyright 2022, automl.org" __license__ = "3-clause BSD" @@ -186,58 +189,58 @@ def print_config_changes( 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.") + 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 + 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) + conf.origin = origin + configs.append(conf) - return configs + return configs # def check_subspace_points( diff --git a/tests/test_acquisition/test_maximizers.py b/tests/test_acquisition/test_maximizers.py index 3e3f70a6a..b09abf2fe 100644 --- a/tests/test_acquisition/test_maximizers.py +++ b/tests/test_acquisition/test_maximizers.py @@ -351,6 +351,7 @@ def test_sorted_random_search_categorical(configspace_categorical, acquisition_f values = rs._maximize(start_points, 1, _sorted=True) + # -------------------------------------------------------------- # TestLocalAndRandomSearch # -------------------------------------------------------------- From 25714d0fdc1b83236a0dee4c45462ae34bcd4912 Mon Sep 17 00:00:00 2001 From: Hadar Shavit Date: Thu, 5 Dec 2024 10:41:14 +0000 Subject: [PATCH 6/7] Remove unused imports --- smac/initial_design/abstract_initial_design.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/smac/initial_design/abstract_initial_design.py b/smac/initial_design/abstract_initial_design.py index c9dc9376b..1a5fe0f3a 100644 --- a/smac/initial_design/abstract_initial_design.py +++ b/smac/initial_design/abstract_initial_design.py @@ -6,15 +6,7 @@ from collections import OrderedDict import numpy as np -from ConfigSpace.configuration_space import Configuration, ConfigurationSpace -from ConfigSpace.hyperparameters import ( - CategoricalHyperparameter, - Constant, - IntegerHyperparameter, - NumericalHyperparameter, - OrdinalHyperparameter, -) -from ConfigSpace.util import ForbiddenValueError, deactivate_inactive_hyperparameters +from ConfigSpace.configuration_space import Configuration from smac.scenario import Scenario from smac.utils.logging import get_logger From 6d0616b6b087f27dc55cd93b81c4b95c47d3eb3c Mon Sep 17 00:00:00 2001 From: Hadar Shavit Date: Thu, 5 Dec 2024 10:54:24 +0000 Subject: [PATCH 7/7] Another formatting fix --- smac/initial_design/sobol_design.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/smac/initial_design/sobol_design.py b/smac/initial_design/sobol_design.py index a5c7998d9..98dfba541 100644 --- a/smac/initial_design/sobol_design.py +++ b/smac/initial_design/sobol_design.py @@ -11,7 +11,6 @@ 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" @@ -45,6 +44,4 @@ def _select_configurations(self) -> list[Configuration]: warnings.simplefilter("ignore") sobol = sobol_gen.random(self._n_configs) - return transform_continuous_designs( - design=sobol, origin="Initial Design: Sobol", configspace=self._configspace - ) + return transform_continuous_designs(design=sobol, origin="Initial Design: Sobol", configspace=self._configspace)