Beispiel #1
0
    def main_cli(self):
        '''
            main function of SMAC for CLI interface
        '''

        cmd_reader = CMDReader()
        args_, misc_args = cmd_reader.read_cmd()

        logging.basicConfig(level=args_.verbose_level)

        root_logger = logging.getLogger()
        root_logger.setLevel(args_.verbose_level)

        scen = Scenario(args_.scenario_file, misc_args)

        try:
            smbo = SMBO(scenario=scen, rng=np.random.RandomState(args_.seed))
            smbo.run(max_iters=args_.max_iterations)

        finally:
            smbo.stats.print_stats()
            self.logger.info("Final Incumbent: %s" % (smbo.incumbent))

            smbo.runhistory.save_json(
                fn=os.path.join(scen.output_dir, "runhistory.json"))
Beispiel #2
0
 def test_eips(self):
     scenario = Scenario({
         'cs': test_helpers.get_branin_config_space(),
         'run_obj': 'quality',
         'deterministic': True
     })
     types = get_types(scenario.cs, None)
     umrfwi = UncorrelatedMultiObjectiveRandomForestWithInstances(
         ['cost', 'runtime'], types)
     eips = EIPS(umrfwi)
     rh2EPM = RunHistory2EPM4EIPS(scenario, 2)
     taf = ExecuteTAFunc(test_function)
     smbo = SMBO(scenario,
                 model=umrfwi,
                 acquisition_function=eips,
                 runhistory2epm=rh2EPM,
                 tae_runner=taf)
     smbo.run(5)
     print(smbo.incumbent)
     raise ValueError()
Beispiel #3
0
    def get_tuned_config(self, scenario: ASlibScenario):
        '''
            uses SMAC3 to determine a well-performing configuration in the configuration space self.cs on the given scenario

            Arguments
            ---------
            scenario: ASlibScenario
                ASlib Scenario at hand

            Returns
            -------
            Configuration
                best incumbent configuration found by SMAC
        '''

        taf = ExecuteTAFunc(functools.partial(self.run_cv, scenario=scenario))

        ac_scenario = Scenario({"run_obj": "quality",  # we optimize quality
                                # at most 10 function evaluations
                                "runcount-limit": 10,
                                "cs": self.cs,  # configuration space
                                "deterministic": "true"
                                })

        # necessary to use stats options related to scenario information
        AC_Stats.scenario = ac_scenario

        # Optimize
        self.logger.info(
            ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
        self.logger.info("Start Configuration")
        self.logger.info(
            ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
        smbo = SMBO(scenario=ac_scenario, tae_runner=taf,
                    rng=np.random.RandomState(42))
        smbo.run(max_iters=999)

        AC_Stats.print_stats()
        self.logger.info("Final Incumbent: %s" % (smbo.incumbent))

        return smbo.incumbent
Beispiel #4
0
    "run_obj": "quality",  # we optimize quality (alternative runtime)
    "runcount-limit": 200,  # at most 200 function evaluations
    "cs": cs,  # configuration space
    "deterministic": "true",
    #"tuner-timeout" : 1,
    #"wallclock_limit": 2
})
stats = Stats(scenario)

# register function to be optimize
taf = ExecuteTAFunc(rosenbrock_4d, stats)

# example call of the function
# it returns: Status, Cost, Runtime, Additional Infos
def_value = taf.run(cs.get_default_configuration())[1]
print("Default Value: %.2f" % (def_value))

# Optimize
smbo = SMBO(scenario=scenario,
            tae_runner=taf,
            stats=stats,
            rng=np.random.RandomState(42))
try:
    smbo.run(max_iters=999)
finally:
    smbo.stats.print_stats()
print("Final Incumbent: %s" % (smbo.incumbent))

inc_value = taf.run(smbo.incumbent)[1]
print("Optimized Value: %.2f" % (inc_value))
Beispiel #5
0
class SMAC(object):
    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):
        '''
        Facade to use SMAC default mode

        Parameters
        ----------
        scenario: smac.scenario.scenario.Scenario
            Scenario object
        tae_runner: ExecuteTARun or callable
            Callable or implementation of :class:`ExecuteTaRun`. In case a
            callable is passed it will be wrapped by tae.ExecuteTaFunc().
            If not set, tae_runner will be initialized with
            the tae.ExecuteTARunOld()
        runhistory: RunHistory
            runhistory to store all algorithm runs
        intensifier: Intensifier
            intensification object to issue a racing to decide the current
            incumbent
        acquisition_function : AcquisitionFunction
            Object that implements the AbstractAcquisitionFunction. Will use
            EI if not set.
        model : AbstractEPM
            Model that implements train() and predict(). Will use a
            RandomForest if not set.
        runhistory2epm : RunHistory2EMP
            Object that implements the AbstractRunHistory2EPM. If None,
            will use RunHistory2EPM4Cost if objective is cost or
            RunHistory2EPM4LogCost if objective is runtime.
        initial_design: InitialDesign
            initial sampling design
        initial_configurations: typing.List[Configuration]
            list of initial configurations for initial design -- 
            cannot be used together with initial_design
        stats: Stats
            optional stats object
        rng: np.random.RandomState
            Random number generator
        '''
        self.logger = logging.getLogger("SMAC")

        aggregate_func = average_cost

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

        # initialize empty runhistory
        if runhistory is None:
            runhistory = 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=scenario.output_dir,
                                 stats=self.stats)

        # initial EPM
        types = get_types(scenario.cs, scenario.feature_array)
        if model is None:
            model = RandomForestWithInstances(
                types=types,
                instance_features=scenario.feature_array,
                seed=rng.randint(MAXINT))
        # initial acquisition function
        if acquisition_function is None:
            acquisition_function = EI(model=model)

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

        # 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)
        # 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)
        # 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

        # initial 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",
                instance_specifics=scenario.instance_specific,
                minR=scenario.minR,
                maxR=scenario.maxR)

        # 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)

        # 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.log10(scenario.cutoff)
                threshold = np.log10(scenario.cutoff * scenario.par_factor)

                imputor = RFRImputator(rs=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.TIMEOUT,
                    ],
                    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)

        self.solver = SMBO(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)

    def _get_rng(self, rng):
        '''
            initial random number generator 

            Arguments
            ---------
            rng: np.random.RandomState|int|None

            Returns
            -------
            int, np.random.RandomState
        '''

        # initialize random number generator
        if rng is None:
            num_run = np.random.randint(1234567980)
            rng = np.random.RandomState(seed=num_run)
        elif isinstance(rng, int):
            num_run = rng
            rng = np.random.RandomState(seed=rng)
        elif isinstance(rng, np.random.RandomState):
            num_run = rng.randint(1234567980)
            rng = rng
        else:
            raise TypeError('Unknown type %s for argument rng. Only accepts '
                            'None, int or np.random.RandomState' %
                            str(type(rng)))
        return num_run, rng

    def optimize(self):
        '''
            optimize the algorithm provided in scenario (given in constructor)

            Arguments
            ---------
            max_iters: int
                maximal number of iterations
        '''
        incumbent = None
        try:
            incumbent = self.solver.run()
        finally:
            self.solver.stats.print_stats()
            self.logger.info("Final Incumbent: %s" % (self.solver.incumbent))
            self.runhistory = self.solver.runhistory
            self.trajectory = self.solver.intensifier.traj_logger.trajectory
        return incumbent

    def get_runhistory(self):
        if not hasattr(self, 'runhistory'):
            raise ValueError('SMAC was not fitted yet. Call optimize() prior '
                             'to accessing the runhistory.')
        return self.runhistory

    def get_trajectory(self):
        if not hasattr(self, 'trajectory'):
            raise ValueError('SMAC was not fitted yet. Call optimize() prior '
                             'to accessing the runhistory.')
        return self.trajectory