from typing import Any
from smac.epm.random_forest.rf_with_instances import RandomForestWithInstances
from smac.facade.smac_ac_facade import SMAC4AC
from smac.initial_design.sobol_design import SobolDesign
from smac.optimizer.acquisition import LogEI
from smac.runhistory.runhistory2epm import RunHistory2EPM4LogScaledCost
__author__ = "Marius Lindauer"
__copyright__ = "Copyright 2018, ML4AAD"
__license__ = "3-clause BSD"
[docs]class SMAC4HPO(SMAC4AC):
"""Facade to use SMAC for hyperparameter optimization.
see smac.facade.smac_Facade for API
This facade overwrites options available via the SMAC facade
See Also
--------
:class:`~smac.facade.smac_ac_facade.SMAC4AC` for documentation of parameters.
Attributes
----------
logger
stats : Stats
solver : SMBO
runhistory : RunHistory
List with information about previous runs
trajectory : list
List of all incumbents
"""
def __init__(self, **kwargs: Any):
scenario = kwargs["scenario"]
kwargs["initial_design"] = kwargs.get("initial_design", SobolDesign)
if len(scenario.cs.get_hyperparameters()) > 21201 and kwargs["initial_design"] is SobolDesign:
raise ValueError(
'The default initial design "Sobol sequence" can only handle up to 21201 dimensions. '
'Please use a different initial design, such as "the Latin Hypercube design".',
)
init_kwargs = kwargs.get("initial_design_kwargs", dict())
init_kwargs["n_configs_x_params"] = init_kwargs.get("n_configs_x_params", 10)
init_kwargs["max_config_fracs"] = init_kwargs.get("max_config_fracs", 0.25)
kwargs["initial_design_kwargs"] = init_kwargs
# Intensification parameters - which intensifier to use and respective parameters
intensifier_kwargs = kwargs.get("intensifier_kwargs", dict())
intensifier_kwargs["min_chall"] = 1
kwargs["intensifier_kwargs"] = intensifier_kwargs
scenario.intensification_percentage = 1e-10
if kwargs.get("model") is None:
model_class = RandomForestWithInstances
kwargs["model"] = model_class
# == static RF settings
model_kwargs = kwargs.get("model_kwargs", dict())
model_kwargs["num_trees"] = model_kwargs.get("num_trees", 10)
model_kwargs["do_bootstrapping"] = model_kwargs.get("do_bootstrapping", True)
model_kwargs["ratio_features"] = model_kwargs.get("ratio_features", 1.0)
model_kwargs["min_samples_split"] = model_kwargs.get("min_samples_split", 2)
model_kwargs["min_samples_leaf"] = model_kwargs.get("min_samples_leaf", 1)
model_kwargs["log_y"] = model_kwargs.get("log_y", True)
kwargs["model_kwargs"] = model_kwargs
# == Acquisition function
kwargs["acquisition_function"] = kwargs.get("acquisition_function", LogEI)
kwargs["runhistory2epm"] = kwargs.get("runhistory2epm", RunHistory2EPM4LogScaledCost)
# assumes random chooser for random configs
random_config_chooser_kwargs = kwargs.get("random_configuration_chooser_kwargs", dict())
random_config_chooser_kwargs["prob"] = random_config_chooser_kwargs.get("prob", 0.2)
kwargs["random_configuration_chooser_kwargs"] = random_config_chooser_kwargs
# better improve acquisition function optimization
# 1. increase number of sls iterations
acquisition_function_optimizer_kwargs = kwargs.get("acquisition_function_optimizer_kwargs", dict())
acquisition_function_optimizer_kwargs["n_sls_iterations"] = 10
kwargs["acquisition_function_optimizer_kwargs"] = acquisition_function_optimizer_kwargs
super().__init__(**kwargs)
self.logger.info(self.__class__)
# better improve acquisition function optimization
# 2. more randomly sampled configurations
self.solver.scenario.acq_opt_challengers = 10000 # type: ignore[attr-defined] # noqa F821
# activate predict incumbent
self.solver.epm_chooser.predict_x_best = True