Esempio n. 1
0
    def test_local_search_finds_minimum(self):
        class AcquisitionFunction:

            model = None

            def __call__(self, arrays):
                rval = []
                for array in arrays:
                    rval.append([-rosenbrock_4d(array)])
                return np.array(rval)

        ls = LocalSearch(
            acquisition_function=AcquisitionFunction(),
            config_space=self.cs,
            n_steps_plateau_walk=10,
            max_steps=np.inf,
        )

        runhistory = RunHistory()
        self.cs.seed(1)
        random_configs = self.cs.sample_configuration(size=100)
        costs = [
            rosenbrock_4d(random_config) for random_config in random_configs
        ]
        self.assertGreater(np.min(costs), 100)
        for random_config, cost in zip(random_configs, costs):
            runhistory.add(config=random_config,
                           cost=cost,
                           time=0,
                           status=StatusType.SUCCESS)
        minimizer = ls.maximize(runhistory, None, 10)
        minima = [-rosenbrock_4d(m) for m in minimizer]
        self.assertGreater(minima[0], -0.05)
Esempio n. 2
0
    def test_get_initial_points_moo(self):
        class Model:
            def predict_marginalized_over_instances(self, X):
                return X, X

        class AcquisitionFunction:

            model = Model()

            def __call__(self, X):
                return np.array([x.get_array().sum() for x in X]).reshape(
                    (-1, 1))

        ls = LocalSearch(
            acquisition_function=AcquisitionFunction(),
            config_space=self.cs,
            n_steps_plateau_walk=10,
            max_steps=np.inf,
        )

        runhistory = RunHistory()
        random_configs = self.cs.sample_configuration(size=100)
        costs = np.array(
            [rosenbrock_4d(random_config) for random_config in random_configs])
        for random_config, cost in zip(random_configs, costs):
            runhistory.add(config=random_config,
                           cost=cost,
                           time=0,
                           status=StatusType.SUCCESS)

        points = ls._get_initial_points(num_points=5,
                                        runhistory=runhistory,
                                        additional_start_points=None)
        self.assertEqual(len(points), 10)
Esempio n. 3
0
    def test_local_search_2(
        self,
        _calculate_num_points_patch,
        _get_initial_points_patch,
    ):
        pcs_file = os.path.join(self.test_files_dir, "test_local_search.pcs")
        seed = np.random.randint(1, 100000)

        with open(pcs_file) as fh:
            config_space = pcs.read(fh.readlines())
            config_space.seed(seed)

        def acquisition_function(point):
            return np.array([np.count_nonzero(point[0].get_array())])

        start_point = config_space.get_default_configuration()
        _calculate_num_points_patch.return_value = 1
        _get_initial_points_patch.return_value = [start_point]

        l = LocalSearch(acquisition_function,
                        config_space,
                        epsilon=0.01,
                        max_iterations=100000)
        acq_val_incumbent, incumbent = l._maximize(None, None, 10)[0]

        np.testing.assert_allclose(
            incumbent.get_array(),
            np.ones(len(config_space.get_hyperparameters())))
Esempio n. 4
0
    def test_local_search_2(
        self,
        _get_initial_points_patch,
    ):
        pcs_file = os.path.join(self.test_files_dir, "test_local_search.pcs")
        seed = np.random.randint(1, 100000)

        runhistory = unittest.mock.Mock()
        runhistory.data = [None] * 1000

        with open(pcs_file) as fh:
            config_space = pcs.read(fh.readlines())
            config_space.seed(seed)

        def acquisition_function(points):
            return np.array([[np.count_nonzero(point.get_array())]
                             for point in points])

        start_point = config_space.get_default_configuration()
        _get_initial_points_patch.return_value = [start_point]

        ls = LocalSearch(acquisition_function, config_space, max_steps=100000)
        # To have some data in a mock runhistory
        ls.runhistory = [None] * 1000
        acq_val_incumbent, incumbent = ls._maximize(runhistory, None, 1)[0]

        np.testing.assert_allclose(
            incumbent.get_array(),
            np.ones(len(config_space.get_hyperparameters())))
Esempio n. 5
0
 def __init__(
     self,
     acquisition_function: AbstractAcquisitionFunction,
     config_space: ConfigurationSpace,
     rng: Union[bool, np.random.RandomState] = None,
 ):
     super().__init__(acquisition_function, config_space, rng)
     self.random_search = RandomSearch(acquisition_function, config_space,
                                       rng)
     self.local_search = LocalSearch(acquisition_function, config_space,
                                     rng)
     self.max_acq_value = sys.float_info.min
Esempio n. 6
0
    def test_local_search(self):
        def acquisition_function(point):
            point = [p.get_array() for p in point]
            opt = np.array([1, 1, 1, 1])
            dist = [euclidean(point, opt)]
            return np.array([-np.min(dist)])

        l = LocalSearch(acquisition_function, self.cs, max_steps=100000)

        start_point = self.cs.sample_configuration()
        acq_val_start_point = acquisition_function([start_point])

        acq_val_incumbent, _ = l._one_iter(start_point)

        # Local search needs to find something that is as least as good as the
        # start point
        self.assertLessEqual(acq_val_start_point, acq_val_incumbent)
Esempio n. 7
0
    def test_get_next_by_local_search(
            self,
            _get_initial_points_patch,
            patch
    ):
        # Without known incumbent
        class SideEffect(object):

            def __call__(self, *args, **kwargs):
                rval = []
                for i in range(len(args[0])):
                    rval.append((i, ConfigurationMock(i)))
                return rval

        patch.side_effect = SideEffect()
        cs = test_helpers.get_branin_config_space()
        rand_confs = cs.sample_configuration(size=9)
        _get_initial_points_patch.return_value = rand_confs
        acq_func = EI(None)

        ls = LocalSearch(acq_func, cs)

        # To have some data in a mock runhistory
        runhistory = unittest.mock.Mock()
        runhistory.data = [None] * 1000

        rval = ls._maximize(runhistory, None, 9)
        self.assertEqual(len(rval), 9)
        self.assertEqual(patch.call_count, 1)
        for i in range(9):
            self.assertIsInstance(rval[i][1], ConfigurationMock)
            self.assertEqual(rval[i][1].value, 8 - i)
            self.assertEqual(rval[i][0], 8 - i)
            self.assertEqual(rval[i][1].origin, 'Local Search')

        # Check that the known 'incumbent' is transparently passed through
        patch.side_effect = SideEffect()
        _get_initial_points_patch.return_value = ['Incumbent'] + rand_confs
        rval = ls._maximize(runhistory, None, 10)
        self.assertEqual(len(rval), 10)
        self.assertEqual(patch.call_count, 2)
        # Only the first local search in each iteration starts from the
        # incumbent
        self.assertEqual(patch.call_args_list[1][0][0][0], 'Incumbent')
        for i in range(10):
            self.assertEqual(rval[i][1].origin, 'Local Search')
Esempio n. 8
0
    def test_local_search(self):
        def acquisition_function(points):
            rval = []
            for point in points:
                opt = np.array([1, 1, 1, 1])
                rval.append([-euclidean(point.get_array(), opt)])
            return np.array(rval)

        ls = LocalSearch(acquisition_function, self.cs, max_steps=100)

        start_point = self.cs.sample_configuration()
        acq_val_start_point = acquisition_function([start_point])

        acq_val_incumbent, _ = ls._do_search(start_point)[0]

        # Local search needs to find something that is as least as good as the
        # start point
        self.assertLessEqual(acq_val_start_point, acq_val_incumbent)
Esempio n. 9
0
    def test_get_next_by_local_search(self, _get_initial_points_patch, patch):
        # Without known incumbent
        class SideEffect(object):
            def __init__(self):
                self.call_number = 0

            def __call__(self, *args, **kwargs):
                rval = 9 - self.call_number
                self.call_number += 1
                return (rval, ConfigurationMock(rval))

        patch.side_effect = SideEffect()
        cs = test_helpers.get_branin_config_space()
        rand_confs = cs.sample_configuration(size=9)
        _get_initial_points_patch.return_value = rand_confs
        acq_func = EI(None)

        ls = LocalSearch(acq_func, cs)

        # To have some data in a mock runhistory
        runhistory = unittest.mock.Mock()
        runhistory.data = [None] * 1000

        rval = ls._maximize(runhistory, None, 9)
        self.assertEqual(len(rval), 9)
        self.assertEqual(patch.call_count, 9)
        for i in range(9):
            self.assertIsInstance(rval[i][1], ConfigurationMock)
            self.assertEqual(rval[i][1].value, 9 - i)
            self.assertEqual(rval[i][0], 9 - i)
            self.assertEqual(rval[i][1].origin, 'Local Search')

        # With known incumbent
        patch.side_effect = SideEffect()
        _get_initial_points_patch.return_value = ['Incumbent'] + rand_confs
        rval = ls._maximize(runhistory, None, 10)
        self.assertEqual(len(rval), 10)
        self.assertEqual(patch.call_count, 19)
        # Only the first local search in each iteration starts from the
        # incumbent
        self.assertEqual(patch.call_args_list[9][0][0], 'Incumbent')
        for i in range(10):
            self.assertEqual(rval[i][1].origin, 'Local Search')
Esempio n. 10
0
    def __init__(
        self,
        configspace,
        random_fraction=1 / 2,
        logger=None,
        configs=None,
        losses=None,
    ):
        self.logger = logger

        self.random_fraction = random_fraction
        self.configspace = configspace
        self.min_points_in_model = len(self.configspace.get_hyperparameters())

        rng = np.random.RandomState(random.randint(0, 100))

        self.model = _construct_model(configspace, rng)
        self.acquisition_func = EI(model=self.model)
        self.acq_optimizer = LocalSearch(
            acquisition_function=self.acquisition_func,
            config_space=configspace,
            rng=rng)
        self.runhistory = RunHistory()

        self.configs = configs or list()
        self.losses = losses or list()
        if self.has_model:
            for config, cost in zip(self.configs, self.losses):
                self.runhistory.add(config, cost, 0, StatusType.SUCCESS)

            X = convert_configurations_to_array(self.configs)
            Y = np.array(self.losses, dtype=np.float64)
            self.model.train(X, Y)
            self.acquisition_func.update(
                model=self.model,
                eta=min(self.losses),
            )
Esempio n. 11
0
    def __init__(
        self,
        configspace,
        random_fraction=1 / 2,
        logger=None,
        previous_results=None
    ):
        self.logger = logger
        self.random_fraction = random_fraction

        self.runhistory = RunHistory()
        self.configs = list()
        self.losses = list()
        rng = np.random.RandomState(random.randint(0, 100))

        if previous_results is not None and len(previous_results.batch_results) > 0:
            # Assume same-task changing-configspace trajectory for now
            results_previous_adjustment = previous_results.batch_results[-1]
            configspace_previous = results_previous_adjustment.configspace

            # Construct combined config space
            configspace_combined = ConfigSpace.ConfigurationSpace()
            development_step = CSH.CategoricalHyperparameter("development_step", choices=["old", "new"])
            configspace_combined.add_hyperparameter(
                development_step
            )

            configspace_only_old, configspace_both, configspace_only_new = get_configspace_partitioning_cond(configspace, configspace_previous)

            configspace_combined.add_hyperparameters(configspace_both.get_hyperparameters())
            configspace_combined.add_hyperparameters(configspace_only_old.get_hyperparameters())
            configspace_combined.add_hyperparameters(configspace_only_new.get_hyperparameters())

            for hyperparameter in configspace_only_old.get_hyperparameters():
                configspace_combined.add_condition(
                    ConfigSpace.EqualsCondition(hyperparameter, development_step, "old")
                )
            for hyperparameter in configspace_only_new.get_hyperparameters():
                configspace_combined.add_condition(
                    ConfigSpace.EqualsCondition(hyperparameter, development_step, "new")
                )

            # Read old configs and losses
            result_previous = results_previous_adjustment.results[0]
            all_runs = result_previous.get_all_runs(only_largest_budget=False)
            self.losses_old = [run.loss for run in all_runs]
            self.configs_old = [run.config_id for run in all_runs]
            id2conf = result_previous.get_id2config_mapping()
            self.configs_old = [id2conf[id_]["config"] for id_ in self.configs_old]

            # Map old configs to combined space
            for config in self.configs_old:
                config["development_step"] = "old"
            self.configs_old = [ConfigSpace.Configuration(configspace_combined, config) for config in self.configs_old]

            for config, cost in zip(self.configs_old, self.losses_old):
                self.runhistory.add(config, cost, 0, StatusType.SUCCESS)

            # Construct and fit model
            self.configspace = configspace_combined
            self.model = _construct_model(self.configspace, rng)
            self.acquisition_func = EI(model=self.model)
            self.acq_optimizer = LocalSearch(acquisition_function=self.acquisition_func,
                                             config_space=self.configspace, rng=rng)

            X = convert_configurations_to_array(self.configs_old)
            Y = np.array(self.losses_old, dtype=np.float64)
            self.model.train(X, Y)
            self.acquisition_func.update(
                model=self.model,
                eta=min(self.losses_old),
            )
        else:
            self.configspace = configspace
            self.model = _construct_model(self.configspace, rng)
            self.acquisition_func = EI(model=self.model)
            self.acq_optimizer = LocalSearch(acquisition_function=self.acquisition_func,
                                             config_space=self.configspace, rng=rng)

        self.min_points_in_model = len(self.configspace.get_hyperparameters())  # TODO
Esempio n. 12
0
class GPCondSampler:
    def __init__(
        self,
        configspace,
        random_fraction=1 / 2,
        logger=None,
        previous_results=None
    ):
        self.logger = logger
        self.random_fraction = random_fraction

        self.runhistory = RunHistory()
        self.configs = list()
        self.losses = list()
        rng = np.random.RandomState(random.randint(0, 100))

        if previous_results is not None and len(previous_results.batch_results) > 0:
            # Assume same-task changing-configspace trajectory for now
            results_previous_adjustment = previous_results.batch_results[-1]
            configspace_previous = results_previous_adjustment.configspace

            # Construct combined config space
            configspace_combined = ConfigSpace.ConfigurationSpace()
            development_step = CSH.CategoricalHyperparameter("development_step", choices=["old", "new"])
            configspace_combined.add_hyperparameter(
                development_step
            )

            configspace_only_old, configspace_both, configspace_only_new = get_configspace_partitioning_cond(configspace, configspace_previous)

            configspace_combined.add_hyperparameters(configspace_both.get_hyperparameters())
            configspace_combined.add_hyperparameters(configspace_only_old.get_hyperparameters())
            configspace_combined.add_hyperparameters(configspace_only_new.get_hyperparameters())

            for hyperparameter in configspace_only_old.get_hyperparameters():
                configspace_combined.add_condition(
                    ConfigSpace.EqualsCondition(hyperparameter, development_step, "old")
                )
            for hyperparameter in configspace_only_new.get_hyperparameters():
                configspace_combined.add_condition(
                    ConfigSpace.EqualsCondition(hyperparameter, development_step, "new")
                )

            # Read old configs and losses
            result_previous = results_previous_adjustment.results[0]
            all_runs = result_previous.get_all_runs(only_largest_budget=False)
            self.losses_old = [run.loss for run in all_runs]
            self.configs_old = [run.config_id for run in all_runs]
            id2conf = result_previous.get_id2config_mapping()
            self.configs_old = [id2conf[id_]["config"] for id_ in self.configs_old]

            # Map old configs to combined space
            for config in self.configs_old:
                config["development_step"] = "old"
            self.configs_old = [ConfigSpace.Configuration(configspace_combined, config) for config in self.configs_old]

            for config, cost in zip(self.configs_old, self.losses_old):
                self.runhistory.add(config, cost, 0, StatusType.SUCCESS)

            # Construct and fit model
            self.configspace = configspace_combined
            self.model = _construct_model(self.configspace, rng)
            self.acquisition_func = EI(model=self.model)
            self.acq_optimizer = LocalSearch(acquisition_function=self.acquisition_func,
                                             config_space=self.configspace, rng=rng)

            X = convert_configurations_to_array(self.configs_old)
            Y = np.array(self.losses_old, dtype=np.float64)
            self.model.train(X, Y)
            self.acquisition_func.update(
                model=self.model,
                eta=min(self.losses_old),
            )
        else:
            self.configspace = configspace
            self.model = _construct_model(self.configspace, rng)
            self.acquisition_func = EI(model=self.model)
            self.acq_optimizer = LocalSearch(acquisition_function=self.acquisition_func,
                                             config_space=self.configspace, rng=rng)

        self.min_points_in_model = len(self.configspace.get_hyperparameters())  # TODO

    @property
    def has_model(self):
        return len(self.configs) >= self.min_points_in_model

    def get_config(self, budget):  # pylint: disable=unused-argument
        self.logger.debug("start sampling a new configuration.")

        is_random_fraction = np.random.rand() < self.random_fraction
        if is_random_fraction or not self.has_model:
            if "development_step" in self.configspace.get_hyperparameter_names():
                while True:
                    sample = self.configspace.sample_configuration()
                    if sample["development_step"] == "new":
                        break
            else:
                sample = self.configspace.sample_configuration()
        else:
            # Use private _maximize to not return challenger list object
            sample = self.acq_optimizer._maximize(
                runhistory=self.runhistory,
                stats=None,
                num_points=1,
            )
            sample = sample[0][1]

        sample = ConfigSpace.util.deactivate_inactive_hyperparameters(sample.get_dictionary(), self.configspace)
        sample = sample.get_dictionary()
        info = {}
        self.logger.debug("done sampling a new configuration.")
        return sample, info

    def new_result(self, job, config_info):  # pylint: disable=unused-argument
        if job.exception is not None:
            self.logger.warning(f"job {job.id} failed with exception\n{job.exception}")

        if job.result is None:
            # One could skip crashed results, but we decided to
            # assign a +inf loss and count them as bad configurations
            loss = np.inf
        else:
            # same for non numeric losses.
            # Note that this means losses of minus infinity will count as bad!
            loss = job.result["loss"] if np.isfinite(job.result["loss"]) else np.inf

        config = ConfigSpace.Configuration(self.configspace, job.kwargs["config"])
        self.configs.append(config)
        self.losses.append(loss)

        if self.has_model:
            # TODO: include old
            X = convert_configurations_to_array(self.configs)
            Y = np.array(self.losses, dtype=np.float64)
            self.model.train(X, Y)
            self.acquisition_func.update(
                model=self.model,
                eta=min(self.losses),
            )
Esempio n. 13
0
    def __init__(
            self,
            scenario: Scenario,
            # TODO: once we drop python3.4 add type hint
            # typing.Union[ExecuteTARun, callable]
            tae_runner=None,
            runhistory: RunHistory = None,
            intensifier: Intensifier = None,
            acquisition_function: AbstractAcquisitionFunction = None,
            model: AbstractEPM = None,
            runhistory2epm: AbstractRunHistory2EPM = None,
            initial_design: InitialDesign = None,
            initial_configurations: typing.List[Configuration] = None,
            stats: Stats = None,
            rng: np.random.RandomState = None,
            run_id: int = 1):
        """Constructor"""
        self.logger = logging.getLogger(self.__module__ + "." +
                                        self.__class__.__name__)

        aggregate_func = average_cost
        self.runhistory = None
        self.trajectory = None

        # initialize stats object
        if stats:
            self.stats = stats
        else:
            self.stats = Stats(scenario)

        self.output_dir = create_output_directory(scenario, run_id)
        scenario.write()

        # initialize empty runhistory
        if runhistory is None:
            runhistory = RunHistory(aggregate_func=aggregate_func)
        # inject aggr_func if necessary
        if runhistory.aggregate_func is None:
            runhistory.aggregate_func = aggregate_func

        # initial random number generator
        num_run, rng = self._get_rng(rng=rng)

        # reset random number generator in config space to draw different
        # random configurations with each seed given to SMAC
        scenario.cs.seed(rng.randint(MAXINT))

        # initial Trajectory Logger
        traj_logger = TrajLogger(output_dir=self.output_dir, stats=self.stats)

        # initial EPM
        types, bounds = get_types(scenario.cs, scenario.feature_array)
        if model is None:
            model = RandomForestWithInstances(
                types=types,
                bounds=bounds,
                instance_features=scenario.feature_array,
                seed=rng.randint(MAXINT),
                pca_components=scenario.PCA_DIM,
                num_trees=scenario.rf_num_trees,
                do_bootstrapping=scenario.rf_do_bootstrapping,
                ratio_features=scenario.rf_ratio_features,
                min_samples_split=scenario.rf_min_samples_split,
                min_samples_leaf=scenario.rf_min_samples_leaf,
                max_depth=scenario.rf_max_depth)
        # initial acquisition function
        if acquisition_function is None:
            if scenario.run_obj == "runtime":
                acquisition_function = LogEI(model=model)
            else:
                acquisition_function = EI(model=model)
        # inject model if necessary
        if acquisition_function.model is None:
            acquisition_function.model = model

        # initialize optimizer on acquisition function
        local_search = LocalSearch(
            acquisition_function,
            scenario.cs,
            max_steps=scenario.sls_max_steps,
            n_steps_plateau_walk=scenario.sls_n_steps_plateau_walk)

        # initialize tae_runner
        # First case, if tae_runner is None, the target algorithm is a call
        # string in the scenario file
        if tae_runner is None:
            tae_runner = ExecuteTARunOld(
                ta=scenario.ta,
                stats=self.stats,
                run_obj=scenario.run_obj,
                runhistory=runhistory,
                par_factor=scenario.par_factor,
                cost_for_crash=scenario.cost_for_crash)
        # Second case, the tae_runner is a function to be optimized
        elif callable(tae_runner):
            tae_runner = ExecuteTAFuncDict(
                ta=tae_runner,
                stats=self.stats,
                run_obj=scenario.run_obj,
                memory_limit=scenario.memory_limit,
                runhistory=runhistory,
                par_factor=scenario.par_factor,
                cost_for_crash=scenario.cost_for_crash)
        # Third case, if it is an ExecuteTaRun we can simply use the
        # instance. Otherwise, the next check raises an exception
        elif not isinstance(tae_runner, ExecuteTARun):
            raise TypeError("Argument 'tae_runner' is %s, but must be "
                            "either a callable or an instance of "
                            "ExecuteTaRun. Passing 'None' will result in the "
                            "creation of target algorithm runner based on the "
                            "call string in the scenario file." %
                            type(tae_runner))

        # Check that overall objective and tae objective are the same
        if tae_runner.run_obj != scenario.run_obj:
            raise ValueError("Objective for the target algorithm runner and "
                             "the scenario must be the same, but are '%s' and "
                             "'%s'" % (tae_runner.run_obj, scenario.run_obj))

        # inject stats if necessary
        if tae_runner.stats is None:
            tae_runner.stats = self.stats
        # inject runhistory if necessary
        if tae_runner.runhistory is None:
            tae_runner.runhistory = runhistory
        # inject cost_for_crash
        if tae_runner.crash_cost != scenario.cost_for_crash:
            tae_runner.crash_cost = scenario.cost_for_crash

        # initialize intensification
        if intensifier is None:
            intensifier = Intensifier(
                tae_runner=tae_runner,
                stats=self.stats,
                traj_logger=traj_logger,
                rng=rng,
                instances=scenario.train_insts,
                cutoff=scenario.cutoff,
                deterministic=scenario.deterministic,
                run_obj_time=scenario.run_obj == "runtime",
                always_race_against=scenario.cs.get_default_configuration()
                if scenario.always_race_default else None,
                instance_specifics=scenario.instance_specific,
                minR=scenario.minR,
                maxR=scenario.maxR,
                adaptive_capping_slackfactor=scenario.
                intens_adaptive_capping_slackfactor,
                min_chall=scenario.intens_min_chall)
        # inject deps if necessary
        if intensifier.tae_runner is None:
            intensifier.tae_runner = tae_runner
        if intensifier.stats is None:
            intensifier.stats = self.stats
        if intensifier.traj_logger is None:
            intensifier.traj_logger = traj_logger

        # initial design
        if initial_design is not None and initial_configurations is not None:
            raise ValueError(
                "Either use initial_design or initial_configurations; but not both"
            )

        if initial_configurations is not None:
            initial_design = MultiConfigInitialDesign(
                tae_runner=tae_runner,
                scenario=scenario,
                stats=self.stats,
                traj_logger=traj_logger,
                runhistory=runhistory,
                rng=rng,
                configs=initial_configurations,
                intensifier=intensifier,
                aggregate_func=aggregate_func)
        elif initial_design is None:
            if scenario.initial_incumbent == "DEFAULT":
                initial_design = DefaultConfiguration(tae_runner=tae_runner,
                                                      scenario=scenario,
                                                      stats=self.stats,
                                                      traj_logger=traj_logger,
                                                      rng=rng)
            elif scenario.initial_incumbent == "RANDOM":
                initial_design = RandomConfiguration(tae_runner=tae_runner,
                                                     scenario=scenario,
                                                     stats=self.stats,
                                                     traj_logger=traj_logger,
                                                     rng=rng)
            else:
                raise ValueError("Don't know what kind of initial_incumbent "
                                 "'%s' is" % scenario.initial_incumbent)
        # inject deps if necessary
        if initial_design.tae_runner is None:
            initial_design.tae_runner = tae_runner
        if initial_design.scenario is None:
            initial_design.scenario = scenario
        if initial_design.stats is None:
            initial_design.stats = self.stats
        if initial_design.traj_logger is None:
            initial_design.traj_logger = traj_logger

        # initial conversion of runhistory into EPM data
        if runhistory2epm is None:

            num_params = len(scenario.cs.get_hyperparameters())
            if scenario.run_obj == "runtime":

                # if we log the performance data,
                # the RFRImputator will already get
                # log transform data from the runhistory
                cutoff = np.log(scenario.cutoff)
                threshold = np.log(scenario.cutoff * scenario.par_factor)

                imputor = RFRImputator(rng=rng,
                                       cutoff=cutoff,
                                       threshold=threshold,
                                       model=model,
                                       change_threshold=0.01,
                                       max_iter=2)

                runhistory2epm = RunHistory2EPM4LogCost(
                    scenario=scenario,
                    num_params=num_params,
                    success_states=[
                        StatusType.SUCCESS,
                    ],
                    impute_censored_data=True,
                    impute_state=[
                        StatusType.CAPPED,
                    ],
                    imputor=imputor)

            elif scenario.run_obj == 'quality':
                runhistory2epm = RunHistory2EPM4Cost(
                    scenario=scenario,
                    num_params=num_params,
                    success_states=[
                        StatusType.SUCCESS,
                    ],
                    impute_censored_data=False,
                    impute_state=None)

            else:
                raise ValueError('Unknown run objective: %s. Should be either '
                                 'quality or runtime.' % self.scenario.run_obj)

        # inject scenario if necessary:
        if runhistory2epm.scenario is None:
            runhistory2epm.scenario = scenario

        self.solver = EPILS_Solver(scenario=scenario,
                                   stats=self.stats,
                                   initial_design=initial_design,
                                   runhistory=runhistory,
                                   runhistory2epm=runhistory2epm,
                                   intensifier=intensifier,
                                   aggregate_func=aggregate_func,
                                   num_run=num_run,
                                   model=model,
                                   acq_optimizer=local_search,
                                   acquisition_func=acquisition_function,
                                   rng=rng)
Esempio n. 14
0
class GPSampler:
    def __init__(
        self,
        configspace,
        random_fraction=1 / 2,
        logger=None,
        configs=None,
        losses=None,
    ):
        self.logger = logger

        self.random_fraction = random_fraction
        self.configspace = configspace
        self.min_points_in_model = len(self.configspace.get_hyperparameters())

        rng = np.random.RandomState(random.randint(0, 100))

        self.model = _construct_model(configspace, rng)
        self.acquisition_func = EI(model=self.model)
        self.acq_optimizer = LocalSearch(
            acquisition_function=self.acquisition_func,
            config_space=configspace,
            rng=rng)
        self.runhistory = RunHistory()

        self.configs = configs or list()
        self.losses = losses or list()
        if self.has_model:
            for config, cost in zip(self.configs, self.losses):
                self.runhistory.add(config, cost, 0, StatusType.SUCCESS)

            X = convert_configurations_to_array(self.configs)
            Y = np.array(self.losses, dtype=np.float64)
            self.model.train(X, Y)
            self.acquisition_func.update(
                model=self.model,
                eta=min(self.losses),
            )

    @property
    def has_model(self):
        return len(self.configs) >= self.min_points_in_model

    def get_config(self, budget):  # pylint: disable=unused-argument
        self.logger.debug("start sampling a new configuration.")

        is_random_fraction = np.random.rand() < self.random_fraction
        if is_random_fraction:
            sample = self.configspace.sample_configuration()
        elif self.has_model:
            # Use private _maximize to not return challenger list object
            sample = self.acq_optimizer._maximize(
                runhistory=self.runhistory,
                stats=None,
                num_points=1,
            )
            sample = sample[0][1]
        else:
            sample = self.configspace.sample_configuration()

        sample = sample.get_dictionary()
        info = {}
        self.logger.debug("done sampling a new configuration.")
        return sample, info

    def new_result(self, job, config_info):  # pylint: disable=unused-argument
        if job.exception is not None:
            self.logger.warning(
                f"job {job.id} failed with exception\n{job.exception}")

        if job.result is None:
            # One could skip crashed results, but we decided to
            # assign a +inf loss and count them as bad configurations
            loss = np.inf
        else:
            # same for non numeric losses.
            # Note that this means losses of minus infinity will count as bad!
            loss = job.result["loss"] if np.isfinite(
                job.result["loss"]) else np.inf

        config = ConfigSpace.Configuration(self.configspace,
                                           job.kwargs["config"])
        self.configs.append(config)
        self.losses.append(loss)
        self.runhistory.add(config, loss, 0, StatusType.SUCCESS)

        if self.has_model:
            X = convert_configurations_to_array(self.configs)
            Y = np.array(self.losses, dtype=np.float64)
            self.model.train(X, Y)
            self.acquisition_func.update(
                model=self.model,
                eta=min(self.losses),
            )
Esempio n. 15
0
class InterleavedLocalAndRandomSearch(AcquisitionFunctionMaximizer):
    """Implements SMAC's default acquisition function optimization.
    
    This optimizer performs local search from the previous best points 
    according, to the acquisition function, uses the acquisition function to 
    sort randomly sampled configurations and interleaves unsorted, randomly 
    sampled configurations in between.
    
    Parameters
    ----------
    acquisition_function : ~smac.optimizer.acquisition.AbstractAcquisitionFunction
        
    config_space : ~smac.configspace.ConfigurationSpace
    
    rng : np.random.RandomState or int, optional
    """
    def __init__(
        self,
        acquisition_function: AbstractAcquisitionFunction,
        config_space: ConfigurationSpace,
        rng: Union[bool, np.random.RandomState] = None,
    ):
        super().__init__(acquisition_function, config_space, rng)
        self.random_search = RandomSearch(acquisition_function, config_space,
                                          rng)
        self.local_search = LocalSearch(acquisition_function, config_space,
                                        rng)
        self.max_acq_value = sys.float_info.min

    def maximize(self, runhistory: RunHistory, stats: Stats, num_points: int,
                 *args) -> Iterable[Configuration]:
        next_configs_by_local_search = self.local_search._maximize(
            runhistory,
            stats,
            10,
        )

        # Get configurations sorted by EI
        next_configs_by_random_search_sorted = self.random_search._maximize(
            runhistory,
            stats,
            num_points - len(next_configs_by_local_search),
            _sorted=True,
        )

        # Having the configurations from random search, sorted by their
        # acquisition function value is important for the first few iterations
        # of SMAC. As long as the random forest predicts constant value, we
        # want to use only random configurations. Having them at the begging of
        # the list ensures this (even after adding the configurations by local
        # search, and then sorting them)
        next_configs_by_acq_value = (next_configs_by_random_search_sorted +
                                     next_configs_by_local_search)
        next_configs_by_acq_value.sort(reverse=True, key=lambda x: x[0])
        self.logger.debug(
            "First 10 acq func (origin) values of selected configurations: %s",
            str([[_[0], _[1].origin] for _ in next_configs_by_acq_value[:10]]))
        # store the max last expansion (challengers generation)
        self.max_acq_value = next_configs_by_acq_value[0][0]

        next_configs_by_acq_value = [_[1] for _ in next_configs_by_acq_value]

        challengers = ChallengerList(next_configs_by_acq_value,
                                     self.config_space)
        return challengers

    def _maximize(self, runhistory: RunHistory, stats: Stats,
                  num_points: int) -> Iterable[Tuple[float, Configuration]]:
        raise NotImplementedError()