From 5e243e0215df7e28f1cac975346ac0970bec578c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20B=C3=A1rtek?= Date: Thu, 7 Oct 2021 09:53:26 +0200 Subject: [PATCH] Propagate minR and maxR from scenario into intensifier (#775) * Test propagation of minR and maxR from scenario into default intensifier in SMAC4AC. * Propagate intensifier kwargs from scenario to Intensifier in SMAC4AC even when the intensifier class is not specified explicitly and is defaulted to Intensifier. * Clean up intensifier instantiation - Only define `intensifier_def_kwargs` when needed. - Remove a superfluous condition `isinstance(intensifier, Intensifier)`. * Update documentation of argument `intensifier` of `SMAC4AC.__init__`. * Allow instantiating `SMAC4AC` with an intensifier object The object must be an instance of `Intensifier`. * Allow intensifier to be an instance of `AbstractRacer` instead of requiring an instance of `Intensifier`. * Document parameter `intensifier` in more detail --- smac/facade/smac_ac_facade.py | 59 ++++++++++++++-------------- test/test_facade/test_smac_facade.py | 17 +++++++- 2 files changed, 45 insertions(+), 31 deletions(-) diff --git a/smac/facade/smac_ac_facade.py b/smac/facade/smac_ac_facade.py index 487f262fa..a0859c777 100644 --- a/smac/facade/smac_ac_facade.py +++ b/smac/facade/smac_ac_facade.py @@ -124,9 +124,9 @@ def __init__(self, arguments passed to constructor of runhistory. We strongly advise against changing the aggregation function, since it will break some code assumptions - intensifier : Intensifier - intensification object to issue a racing to decide the current - incumbent + intensifier : AbstractRacer + intensification object or class to issue a racing to decide the current + incumbent. Default: class `Intensifier` intensifier_kwargs: Optional[Dict] arguments passed to the constructor of '~intensifier' acquisition_function : `~smac.optimizer.acquisition.AbstractAcquisitionFunction` @@ -413,34 +413,35 @@ def __init__(self, "the scenario must be the same, but are '%s' and " "'%s'" % (tae_runner_instance.run_obj, scenario.run_obj)) # type: ignore[union-attr] # noqa F821 - # initialize intensification - intensifier_def_kwargs = { - 'stats': self.stats, - 'traj_logger': traj_logger, - 'rng': rng, - 'instances': scenario.train_insts, # type: ignore[attr-defined] # noqa F821 - 'cutoff': scenario.cutoff, # type: ignore[attr-defined] # noqa F821 - 'deterministic': scenario.deterministic, # type: ignore[attr-defined] # noqa F821 - 'run_obj_time': scenario.run_obj == "runtime", # type: ignore[attr-defined] # noqa F821 - 'instance_specifics': scenario.instance_specific, # type: ignore[attr-defined] # noqa F821 - 'adaptive_capping_slackfactor': scenario.intens_adaptive_capping_slackfactor, # type: ignore[attr-defined] # noqa F821 - 'min_chall': scenario.intens_min_chall # type: ignore[attr-defined] # noqa F821 - } - - if isinstance(intensifier, Intensifier) \ - or (intensifier is not None and inspect.isclass(intensifier) and issubclass(intensifier, Intensifier)): - intensifier_def_kwargs['always_race_against'] = scenario.cs.get_default_configuration() # type: ignore[attr-defined] # noqa F821 - intensifier_def_kwargs['use_ta_time_bound'] = scenario.use_ta_time # type: ignore[attr-defined] # noqa F821 - intensifier_def_kwargs['minR'] = scenario.minR # type: ignore[attr-defined] # noqa F821 - intensifier_def_kwargs['maxR'] = scenario.maxR # type: ignore[attr-defined] # noqa F821 - if intensifier_kwargs is not None: - intensifier_def_kwargs.update(intensifier_kwargs) - if intensifier is None: - intensifier_instance = ( - Intensifier(**intensifier_def_kwargs) # type: ignore[arg-type] # noqa F821 - ) # type: AbstractRacer + intensifier = Intensifier + + if isinstance(intensifier, AbstractRacer): + intensifier_instance = intensifier elif inspect.isclass(intensifier): + # initialize intensification + intensifier_def_kwargs = { + 'stats': self.stats, + 'traj_logger': traj_logger, + 'rng': rng, + 'instances': scenario.train_insts, # type: ignore[attr-defined] # noqa F821 + 'cutoff': scenario.cutoff, # type: ignore[attr-defined] # noqa F821 + 'deterministic': scenario.deterministic, # type: ignore[attr-defined] # noqa F821 + 'run_obj_time': scenario.run_obj == "runtime", # type: ignore[attr-defined] # noqa F821 + 'instance_specifics': scenario.instance_specific, # type: ignore[attr-defined] # noqa F821 + 'adaptive_capping_slackfactor': scenario.intens_adaptive_capping_slackfactor, # type: ignore[attr-defined] # noqa F821 + 'min_chall': scenario.intens_min_chall # type: ignore[attr-defined] # noqa F821 + } + + if issubclass(intensifier, Intensifier): + intensifier_def_kwargs['always_race_against'] = scenario.cs.get_default_configuration() # type: ignore[attr-defined] # noqa F821 + intensifier_def_kwargs['use_ta_time_bound'] = scenario.use_ta_time # type: ignore[attr-defined] # noqa F821 + intensifier_def_kwargs['minR'] = scenario.minR # type: ignore[attr-defined] # noqa F821 + intensifier_def_kwargs['maxR'] = scenario.maxR # type: ignore[attr-defined] # noqa F821 + + if intensifier_kwargs is not None: + intensifier_def_kwargs.update(intensifier_kwargs) + intensifier_instance = intensifier(**intensifier_def_kwargs) # type: ignore[arg-type] # noqa F821 else: raise TypeError( diff --git a/test/test_facade/test_smac_facade.py b/test/test_facade/test_smac_facade.py index 37f55c4d9..64e4a9d6c 100644 --- a/test/test_facade/test_smac_facade.py +++ b/test/test_facade/test_smac_facade.py @@ -41,8 +41,9 @@ class TestSMACFacade(unittest.TestCase): def setUp(self): self.cs = ConfigurationSpace() - self.scenario = Scenario({'cs': self.cs, 'run_obj': 'quality', - 'output_dir': ''}) + self.scenario_dict_default = {'cs': self.cs, 'run_obj': 'quality', + 'output_dir': ''} + self.scenario = Scenario(self.scenario_dict_default) self.sh_intensifier_kwargs = {'n_seeds': 1, 'initial_budget': 1, 'eta': 3, @@ -218,6 +219,18 @@ class DummyIntensifier(Intensifier): self.assertIsInstance(smbo.solver.intensifier, DummyIntensifier) self.assertEqual(smbo.solver.intensifier.maxR, 987) + # Assert that minR, maxR and use_ta_time propagate from scenario to the default intensifier. + for scenario_dict in [{}, {'minR': self.scenario.minR + 1, 'maxR': self.scenario.maxR + 1, + 'use_ta_time': not self.scenario.use_ta_time}]: + for k, v in self.scenario_dict_default.items(): + if k not in scenario_dict: + scenario_dict[k] = v + scenario = Scenario(scenario_dict) + smac = SMAC4AC(scenario=scenario) + self.assertEqual(scenario.minR, smac.solver.intensifier.minR) + self.assertEqual(scenario.maxR, smac.solver.intensifier.maxR) + self.assertEqual(scenario.use_ta_time, smac.solver.intensifier.use_ta_time_bound) + def test_construct_initial_design(self): rng = np.random.RandomState(42)