def __init__(self, pipeline_hyperparameter_ranges, random_seed=0, with_replacement=False, replacement_max_attempts=10): """ Sets up check for duplication if needed. Arguments: pipeline_hyperparameter_ranges (dict): a set of hyperparameter ranges corresponding to a pipeline's parameters random_state (int): Unused in this class. Defaults to 0. with_replacement (bool): If false, only unique hyperparameters will be shown replacement_max_attempts (int): The maximum number of tries to get a unique set of random parameters. Only used if tuner is initalized with with_replacement=True random_seed (int): Seed for random number generator. Defaults to 0. """ super().__init__(pipeline_hyperparameter_ranges, random_seed=random_seed) self._space = Space(self._search_space_ranges) self._random_state = get_random_state(random_seed) self._with_replacement = with_replacement self._replacement_max_attempts = replacement_max_attempts self._used_parameters = set() self._used_parameters.add(()) self.curr_params = None
def _init_space(self, space) -> Space: if space is None: self._domain = None elif len(space) == len(self.free_variables): self._domain = Space(space) elif len(space) == 1: self._domain = Space(space * len(self.free_variables)) else: raise ValueError("space is not correct") return self.domain
def initial_sampling(self, sampling_method=None): if sampling_method is not None: self.sampling_method = sampling_method if self.sampling_method.lower() in ['lh', 'lhs', 'latin hypercube', 'lh-maximin']: if self.sampling_method.lower() in ['lh', 'lhs', 'latin hypercube']: print('Using maximin criteria for latin hypercube sampling.') print('To use classic, centered, correlation or ratio-optimised criteria, input sampling_method') print('as lh-classic, lh-centered, lh-correlation and lh-ratio-optimised respectively.') samp = smp.Lhs(criterion="maximin", iterations=10000) elif self.sampling_method.lower() in ['lh-classic']: samp = smp.Lhs(lhs_type="classic", criterion=None) elif self.sampling_method.lower() in ['lh-centered']: samp = smp.Lhs(lhs_type="centered", criterion=None) elif self.sampling_method.lower() in ['lh-correlation']: samp = smp.Lhs(criterion="correlation", iterations=10000) elif self.sampling_method.lower() in ['lh-ratio-optimised']: samp = smp.Lhs(criterion="ratio", iterations=10000) elif self.sampling_method.lower() in ['sobol']: samp = smp.Sobol() elif self.sampling_method.lower() in ['halton']: samp = smp.Halton() elif self.sampling_method.lower() in ['hammersly']: samp = smp.Hammersly() elif self.sampling_method.lower() in ['grid']: samp = smp.Grid(border="include", use_full_layout=False) # print('Creating initial sampling...') # space = Space([(self.range_param[ke][0],self.range_param[ke][1]) for ke in self.range_param.keys()]) space = Space([(0,self.n_samples) for ke in self.range_param.keys()]) self.init_points = np.array(samp.generate(space.dimensions, self.n_samples)).astype(float) for i,ke in enumerate(self.range_param.keys()): self.init_points[:,i] = self.init_points[:,i]*(self.range_param[ke][1]-self.range_param[ke][0])/self.n_samples+self.range_param[ke][0]
def orion_space_to_skopt_space(orion_space): """Convert Oríon's definition of problem's domain to a skopt compatible.""" dimensions = [] for key, dimension in orion_space.items(): low, high = dimension.interval() shape = dimension.shape assert not shape or shape == [1] if not shape: shape = (1,) low = (low,) high = (high,) dimensions.append(Real(name=key, prior="uniform", low=low[0], high=high[0])) return Space(dimensions)
def convert_orion_space_to_skopt_space(orion_space): dimensions = [] for key, dimension in orion_space.items(): dimension_class = globals()[dimension.__class__.__name__] low = dimension._args[0] high = low + dimension._args[1] # NOTE: A hack, because orion priors have non-inclusive higher bound # while scikit-optimizer have inclusive ones. high = high - numpy.abs(high - 0.0001) * 0.0001 dimensions.append( dimension_class( name=key, prior=dimension._prior_name, low=low, high=high)) return Space(dimensions)
def skopt_main(): from skopt import Optimizer, dump, load, Space from skopt.learning import GaussianProcessRegressor from skopt.space import Real, Integer fname = 'optimizer-exp-pendulum-4.pkl' dims = [Integer(15, 500), Real(0.025, 0.1, prior="log-uniform")] try: optimizer = load(fname) optimizer.space = Space(dims) except: optimizer = Optimizer(dimensions=dims, random_state=1) n_jobs = 2 for i in range(3): pool = Pool(n_jobs, initializer=mute) x = optimizer.ask(n_points=n_jobs) # x is a list of n_points points print(x) y = pool.map(f, x) pool.close() optimizer.tell(x, y) print('Iteration %d. Best yi %.2f' % (i, min(optimizer.yi))) dump(optimizer, fname)
def convert_orion_space_to_skopt_space(orion_space): """Convert Oríon's definition of problem's domain to a skopt compatible.""" dimensions = [] for key, dimension in orion_space.items(): # low = dimension._args[0] # high = low + dimension._args[1] low, high = dimension.interval() # NOTE: A hack, because orion priors have non-inclusive higher bound # while scikit-optimizer have inclusive ones. high = numpy.nextafter(high, high - 1) shape = dimension.shape assert not shape or len(shape) == 1 if not shape: shape = (1, ) # Unpack dimension for i in range(shape[0]): dimensions.append( Real(name=key + '_' + str(i), prior='uniform', low=low, high=high)) return Space(dimensions)
def test_categorical_gp_has_gradients(): space = Space([('a', 'b')]) assert not has_gradients(cook_estimator('GP', space=space))
def test_has_gradients(estimator, gradients): space = Space([(-2.0, 2.0)]) assert has_gradients(cook_estimator(estimator, space=space)) == gradients
class RandomSearchTuner(Tuner): """Random Search Optimizer. Example: >>> tuner = RandomSearchTuner({'My Component': {'param a': [0.0, 10.0], 'param b': ['a', 'b', 'c']}}, random_seed=42) >>> proposal = tuner.propose() >>> assert proposal.keys() == {'My Component'} >>> assert proposal['My Component'] == {'param a': 3.7454011884736254, 'param b': 'c'} """ def __init__(self, pipeline_hyperparameter_ranges, random_seed=0, with_replacement=False, replacement_max_attempts=10): """ Sets up check for duplication if needed. Arguments: pipeline_hyperparameter_ranges (dict): a set of hyperparameter ranges corresponding to a pipeline's parameters random_state (int): Unused in this class. Defaults to 0. with_replacement (bool): If false, only unique hyperparameters will be shown replacement_max_attempts (int): The maximum number of tries to get a unique set of random parameters. Only used if tuner is initalized with with_replacement=True random_seed (int): Seed for random number generator. Defaults to 0. """ super().__init__(pipeline_hyperparameter_ranges, random_seed=random_seed) self._space = Space(self._search_space_ranges) self._random_state = get_random_state(random_seed) self._with_replacement = with_replacement self._replacement_max_attempts = replacement_max_attempts self._used_parameters = set() self._used_parameters.add(()) self.curr_params = None def add(self, pipeline_parameters, score): """Not applicable to random search tuner as generated parameters are not dependent on scores of previous parameters. Arguments: pipeline_parameters (dict): A dict of the parameters used to evaluate a pipeline score (float): The score obtained by evaluating the pipeline with the provided parameters """ pass def _get_sample(self): return tuple(self._space.rvs(random_state=self._random_state)[0]) def propose(self): """Generate a unique set of parameters. If tuner was initialized with ``with_replacement=True`` and the tuner is unable to generate a unique set of parameters after ``replacement_max_attempts`` tries, then ``NoParamsException`` is raised. Returns: dict: Proposed pipeline parameters """ if not len(self._search_space_ranges): return self._convert_to_pipeline_parameters({}) if self._with_replacement: return self._convert_to_pipeline_parameters(self._get_sample()) elif not self.curr_params: self.is_search_space_exhausted() params = self.curr_params self.curr_params = None return self._convert_to_pipeline_parameters(params) def is_search_space_exhausted(self): """Checks if it is possible to generate a set of valid parameters. Stores generated parameters in ``self.curr_params`` to be returned by ``propose()``. Raises: NoParamsException: If a search space is exhausted, then this exception is thrown. Returns: bool: If no more valid parameters exists in the search space, return false. """ if self._with_replacement: return False else: curr_params = () attempts = 0 while curr_params in self._used_parameters: if attempts >= self._replacement_max_attempts: raise NoParamsException( "Cannot create a unique set of unexplored parameters. Try expanding the search space." ) return True attempts += 1 curr_params = self._get_sample() self._used_parameters.add(curr_params) self.curr_params = curr_params return False