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

Upgrade to ConfigSpace 1.x #1124

Merged
merged 9 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
- Add example to specify total budget (fidelity units) instead of n_trials for multi-fidelity/Hyperband (#1121)

## Dependencies
- Update numpy NaN (#1122) and restrict numpy and ConfigSpace versions
- Update numpy NaN (#1122) and restrict numpy version
- Upgrade to ConfigSpace 1.x.x (#1124)

# 2.1.0

Expand Down
4 changes: 3 additions & 1 deletion benchmark/src/benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
from collections import defaultdict
from pathlib import Path

from smac.utils.numpyencoder import NumpyEncoder

import pandas as pd
from src.tasks import TASKS # noqa: E402
from src.utils.exceptions import NotSupportedError # noqa: E402
Expand Down Expand Up @@ -79,7 +81,7 @@ def _save_data(self) -> None:
"""Saves the internal data to the file."""
print("Saving data...")
with open(str(RAW_FILENAME), "w") as f:
json.dump(self._data, f, indent=4)
json.dump(self._data, f, indent=4, cls=NumpyEncoder)

def _fill_keys(self) -> None:
"""Fill data with keys based on computer name, tasks, and selected version."""
Expand Down
2 changes: 1 addition & 1 deletion benchmark/src/models/ac_branin.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def configspace(self) -> ConfigurationSpace:
x2 = Float("x2", (0, 15), default=7.5)

# Add hyperparameters and conditions to our configspace
cs.add_hyperparameters([x2])
cs.add([x2])

return cs

Expand Down
2 changes: 1 addition & 1 deletion benchmark/src/models/branin.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def configspace(self) -> ConfigurationSpace:
x2 = Float("x2", (0, 15), default=0)

# Add hyperparameters and conditions to our configspace
cs.add_hyperparameters([x1, x2])
cs.add([x1, x2])

return cs

Expand Down
2 changes: 1 addition & 1 deletion benchmark/src/models/himmelblau.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def configspace(self) -> ConfigurationSpace:
y = Float("y", (-5, 5))

# Add hyperparameters and conditions to our configspace
cs.add_hyperparameters([x, y])
cs.add([x, y])

return cs

Expand Down
4 changes: 2 additions & 2 deletions benchmark/src/models/mlp.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def configspace(self) -> ConfigurationSpace:
learning_rate_init = Float("learning_rate_init", (0.0001, 1.0), default=0.001, log=True)

# Add all hyperparameters at once:
cs.add_hyperparameters([n_layer, n_neurons, activation, solver, batch_size, learning_rate, learning_rate_init])
cs.add([n_layer, n_neurons, activation, solver, batch_size, learning_rate, learning_rate_init])

# Adding conditions to restrict the hyperparameter space...
# ... since learning rate is used when solver is 'sgd'.
Expand All @@ -44,7 +44,7 @@ def configspace(self) -> ConfigurationSpace:
use_batch_size = InCondition(child=batch_size, parent=solver, values=["sgd", "adam"])

# We can also add multiple conditions on hyperparameters at once:
cs.add_conditions([use_lr, use_batch_size, use_lr_init])
cs.add([use_lr, use_batch_size, use_lr_init])

return cs

Expand Down
4 changes: 2 additions & 2 deletions benchmark/src/models/svm.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ def configspace(self) -> ConfigurationSpace:
use_gamma_value = InCondition(child=gamma_value, parent=gamma, values=["value"])

# Add hyperparameters and conditions to our configspace
cs.add_hyperparameters([kernel, C, shrinking, degree, coef, gamma, gamma_value])
cs.add_conditions([use_degree, use_coef, use_gamma, use_gamma_value])
cs.add([kernel, C, shrinking, degree, coef, gamma, gamma_value])
cs.add([use_degree, use_coef, use_gamma, use_gamma_value])

return cs

Expand Down
2 changes: 1 addition & 1 deletion examples/1_basics/1_quadratic_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class QuadraticFunction:
def configspace(self) -> ConfigurationSpace:
cs = ConfigurationSpace(seed=0)
x = Float("x", (-5, 5), default=-5)
cs.add_hyperparameters([x])
cs.add([x])

return cs

Expand Down
4 changes: 2 additions & 2 deletions examples/1_basics/2_svm_cv.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def configspace(self) -> ConfigurationSpace:
use_gamma_value = InCondition(child=gamma_value, parent=gamma, values=["value"])

# Add hyperparameters and conditions to our configspace
cs.add_hyperparameters([kernel, C, shrinking, degree, coef, gamma, gamma_value])
cs.add_conditions([use_degree, use_coef, use_gamma, use_gamma_value])
cs.add([kernel, C, shrinking, degree, coef, gamma, gamma_value])
cs.add([use_degree, use_coef, use_gamma, use_gamma_value])

return cs

Expand Down
2 changes: 1 addition & 1 deletion examples/1_basics/3_ask_and_tell.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def configspace(self) -> ConfigurationSpace:
cs = ConfigurationSpace(seed=0)
x0 = Float("x0", (-5, 10), default=-3)
x1 = Float("x1", (-5, 10), default=-4)
cs.add_hyperparameters([x0, x1])
cs.add([x0, x1])

return cs

Expand Down
2 changes: 1 addition & 1 deletion examples/1_basics/4_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def configspace(self) -> ConfigurationSpace:
cs = ConfigurationSpace(seed=0)
x0 = Float("x0", (-5, 10), default=-3)
x1 = Float("x1", (-5, 10), default=-4)
cs.add_hyperparameters([x0, x1])
cs.add([x0, x1])

return cs

Expand Down
2 changes: 1 addition & 1 deletion examples/1_basics/5_continue.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class QuadraticFunction:
def configspace(self) -> ConfigurationSpace:
cs = ConfigurationSpace(seed=0)
x = Float("x", (-5, 5), default=-5)
cs.add_hyperparameters([x])
cs.add([x])

return cs

Expand Down
6 changes: 3 additions & 3 deletions examples/1_basics/6_priors.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ def configspace(self) -> ConfigurationSpace:
"learning_rate_init",
lower=1e-5,
upper=1.0,
mu=np.log(1e-3),
sigma=np.log(10),
mu=1e-3, # will be transformed to log space later
sigma=10, # will be transformed to log space later
log=True,
)

# Add all hyperparameters at once:
cs.add_hyperparameters([n_layer, n_neurons, activation, optimizer, batch_size, learning_rate_init])
cs.add([n_layer, n_neurons, activation, optimizer, batch_size, learning_rate_init])

return cs

Expand Down
2 changes: 1 addition & 1 deletion examples/1_basics/7_parallelization_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def configspace(self) -> ConfigurationSpace:
cs = ConfigurationSpace(seed=0)
x0 = Float("x0", (-5, 10), default=-5, log=False)
x1 = Float("x1", (0, 15), default=2, log=False)
cs.add_hyperparameters([x0, x1])
cs.add([x0, x1])

return cs

Expand Down
4 changes: 2 additions & 2 deletions examples/2_multi_fidelity/1_mlp_epochs.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def configspace(self) -> ConfigurationSpace:
learning_rate_init = Float("learning_rate_init", (0.0001, 1.0), default=0.001, log=True)

# Add all hyperparameters at once:
cs.add_hyperparameters([n_layer, n_neurons, activation, solver, batch_size, learning_rate, learning_rate_init])
cs.add([n_layer, n_neurons, activation, solver, batch_size, learning_rate, learning_rate_init])

# Adding conditions to restrict the hyperparameter space...
# ... since learning rate is only used when solver is 'sgd'.
Expand All @@ -76,7 +76,7 @@ def configspace(self) -> ConfigurationSpace:
use_batch_size = InCondition(child=batch_size, parent=solver, values=["sgd", "adam"])

# We can also add multiple conditions on hyperparameters at once:
cs.add_conditions([use_lr, use_batch_size, use_lr_init])
cs.add([use_lr, use_batch_size, use_lr_init])

return cs

Expand Down
2 changes: 1 addition & 1 deletion examples/2_multi_fidelity/2_sgd_datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def configspace(self) -> ConfigurationSpace:
learning_rate = Categorical("learning_rate", ["constant", "invscaling", "adaptive"], default="constant")
eta0 = Float("eta0", (0.00001, 1), default=0.1, log=True)
# Add the parameters to configuration space
cs.add_hyperparameters([alpha, l1_ratio, learning_rate, eta0])
cs.add([alpha, l1_ratio, learning_rate, eta0])

return cs

Expand Down
2 changes: 1 addition & 1 deletion examples/2_multi_fidelity/3_specify_HB_via_total_budget.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class QuadraticFunction:
def configspace(self) -> ConfigurationSpace:
cs = ConfigurationSpace(seed=0)
x = Float("x", (-5, 5), default=-5)
cs.add_hyperparameters([x])
cs.add([x])

return cs

Expand Down
4 changes: 2 additions & 2 deletions examples/3_multi_objective/2_parego.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,14 @@ def configspace(self) -> ConfigurationSpace:
learning_rate = Categorical("learning_rate", ["constant", "invscaling", "adaptive"], default="constant")
learning_rate_init = Float("learning_rate_init", (0.0001, 1.0), default=0.001, log=True)

cs.add_hyperparameters([n_layer, n_neurons, activation, solver, batch_size, learning_rate, learning_rate_init])
cs.add([n_layer, n_neurons, activation, solver, batch_size, learning_rate, learning_rate_init])

use_lr = EqualsCondition(child=learning_rate, parent=solver, value="sgd")
use_lr_init = InCondition(child=learning_rate_init, parent=solver, values=["sgd", "adam"])
use_batch_size = InCondition(child=batch_size, parent=solver, values=["sgd", "adam"])

# We can also add multiple conditions on hyperparameters at once:
cs.add_conditions([use_lr, use_batch_size, use_lr_init])
cs.add([use_lr, use_batch_size, use_lr_init])

return cs

Expand Down
2 changes: 1 addition & 1 deletion examples/4_advanced_optimizer/1_turbo_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
# cs = ConfigurationSpace(seed=0)
# x0 = Float("x0", (-5, 10), default=-3)
# x1 = Float("x1", (-5, 10), default=-4)
# cs.add_hyperparameters([x0, x1])
# cs.add([x0, x1])

# return cs

Expand Down
2 changes: 1 addition & 1 deletion examples/4_advanced_optimizer/2_boing_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
# cs = ConfigurationSpace(seed=0)
# x0 = Float("x0", (-5, 10), default=-3)
# x1 = Float("x1", (-5, 10), default=-4)
# cs.add_hyperparameters([x0, x1])
# cs.add([x0, x1])

# return cs

Expand Down
2 changes: 1 addition & 1 deletion examples/4_advanced_optimizer/3_metadata_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def configspace(self) -> ConfigurationSpace:
cs = ConfigurationSpace(seed=0)
x0 = Float("x0", (-5, 10), default=-3)
x1 = Float("x1", (-5, 10), default=-4)
cs.add_hyperparameters([x0, x1])
cs.add([x0, x1])

return cs

Expand Down
27 changes: 13 additions & 14 deletions examples/4_advanced_optimizer/4_intensify_crossvalidation.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ def configspace(self) -> ConfigurationSpace:
cs = ConfigurationSpace(seed=0)

# First we create our hyperparameters
C = Float("C", (2 ** - 5, 2 ** 15), default=1.0, log=True)
gamma = Float("gamma", (2 ** -15, 2 ** 3), default=1.0, log=True)
C = Float("C", (2**-5, 2**15), default=1.0, log=True)
gamma = Float("gamma", (2**-15, 2**3), default=1.0, log=True)

# Add hyperparameters to our configspace
cs.add_hyperparameters([C, gamma])
cs.add([C, gamma])

return cs

def train(self, config: Configuration, instance: str, seed: int = 0) -> float:
"""Creates a SVM based on a configuration and evaluate on the given fold of the digits dataset

Parameters
----------
config: Configuration
Expand Down Expand Up @@ -81,15 +81,14 @@ def train(self, config: Configuration, instance: str, seed: int = 0) -> float:
scenario = Scenario(
classifier.configspace,
n_trials=50, # We want to run max 50 trials (combination of config and instances in the case of
# deterministic=True. In the case of deterministic=False, this would be the
# combination of instances, seeds and configs). The number of distinct configurations
# evaluated by SMAC will be lower than this number because some of the configurations
# will be executed on more than one instance (CV fold).
# deterministic=True. In the case of deterministic=False, this would be the
# combination of instances, seeds and configs). The number of distinct configurations
# evaluated by SMAC will be lower than this number because some of the configurations
# will be executed on more than one instance (CV fold).
instances=[f"{i}" for i in range(N_FOLDS)], # Specify all instances by their name (as a string)
instance_features={f"{i}": [i] for i in range(N_FOLDS)}, # breaks SMAC
instance_features={f"{i}": [i] for i in range(N_FOLDS)}, # breaks SMAC
deterministic=True # To simplify the problem we make SMAC believe that we have a deterministic
# optimization problem.

# optimization problem.
)

# We want to run the facade's default initial design, but we want to change the number
Expand All @@ -102,12 +101,12 @@ def train(self, config: Configuration, instance: str, seed: int = 0) -> float:
classifier.train,
initial_design=initial_design,
overwrite=True, # If the run exists, we overwrite it; alternatively, we can continue from last state
# The next line defines the intensifier, i.e., the module that governs the selection of
# The next line defines the intensifier, i.e., the module that governs the selection of
# instance-seed pairs. Since we set deterministic to True above, it only governs the instance in
# this example. Technically, it is not necessary to create the intensifier as a user, but it is
# necessary to do so because we change the argument max_config_calls (the number of instance-seed pairs
# per configuration to try) to the number of cross-validation folds, while the default would be 3.
intensifier=Intensifier(scenario=scenario, max_config_calls=N_FOLDS, seed=0)
intensifier=Intensifier(scenario=scenario, max_config_calls=N_FOLDS, seed=0),
)

incumbent = smac.optimize()
Expand All @@ -124,4 +123,4 @@ def train(self, config: Configuration, instance: str, seed: int = 0) -> float:
# at more configurations than would have been possible with regular cross-validation, where the number
# of configurations would be determined by the number of trials divided by the number of folds (50 / 10).
runhistory = smac.runhistory
print(f"Number of evaluated configurations: {len(runhistory.config_ids)}")
print(f"Number of evaluated configurations: {len(runhistory.config_ids)}")
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def read_file(filepath: str) -> str:
"scipy>=1.9.2",
"psutil",
"pynisher>=1.0.0",
"ConfigSpace>=0.6.1,<1.0.0",
"ConfigSpace>=1.0.0",
"joblib",
"scikit-learn>=1.1.2",
"pyrfr>=0.9.0",
Expand Down
1 change: 0 additions & 1 deletion smac/acquisition/maximizer/local_and_random_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ def _maximize(
previous_configs: list[Configuration],
n_points: int,
) -> list[tuple[float, Configuration]]:

if self._uniform_configspace is not None and self._prior_sampling_fraction is not None:
# Get configurations sorted by acquisition function value
next_configs_by_prior_random_search_sorted = self._prior_random_search._maximize(
Expand Down
2 changes: 1 addition & 1 deletion smac/acquisition/maximizer/local_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ def _search(
if acq_val[acq_index] > acq_val_candidates[i]:
is_valid = False
try:
neighbors[acq_index].is_valid_configuration()
neighbors[acq_index].check_valid_configuration()
is_valid = True
except (ValueError, ForbiddenValueError) as e:
logger.debug("Local search %d: %s", i, e)
Expand Down
3 changes: 2 additions & 1 deletion smac/callback/metadata_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import smac
from smac.callback.callback import Callback
from smac.main.smbo import SMBO
from smac.utils.numpyencoder import NumpyEncoder

__copyright__ = "Copyright 2023, AutoML.org Freiburg-Hannover"
__license__ = "3-clause BSD"
Expand All @@ -31,4 +32,4 @@ def on_start(self, smbo: SMBO) -> None:
path.mkdir(parents=True, exist_ok=True)

with open(path / "metadata.json", "w") as fp:
json.dump(meta_dict, fp, indent=2)
json.dump(meta_dict, fp, indent=2, cls=NumpyEncoder)
1 change: 0 additions & 1 deletion smac/initial_design/abstract_initial_design.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ def _transform_continuous_designs(
"""
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):
Expand Down
3 changes: 2 additions & 1 deletion smac/intensifier/abstract_intensifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from smac.scenario import Scenario
from smac.utils.configspace import get_config_hash, print_config_changes
from smac.utils.logging import get_logger
from smac.utils.numpyencoder import NumpyEncoder
from smac.utils.pareto_front import calculate_pareto_front, sort_by_crowding_distance

__copyright__ = "Copyright 2022, automl.org"
Expand Down Expand Up @@ -666,7 +667,7 @@ def save(self, filename: str | Path) -> None:
}

with open(filename, "w") as fp:
json.dump(data, fp, indent=2)
json.dump(data, fp, indent=2, cls=NumpyEncoder)

def load(self, filename: str | Path) -> None:
"""Loads the latest state of the intensifier including the incumbents and trajectory."""
Expand Down
Loading
Loading