def impute_inactive_values(configuration: Configuration, strategy: Union[str, float]='default') -> Configuration: """Impute inactive parameters. Parameters ---------- strategy : string, optional (default='default') The imputation strategy. - If 'default', replace inactive parameters by their default. - If float, replace inactive parameters by the given float value, which should be able to be splitted apart by a tree-based model. """ values = dict() for hp in configuration.configuration_space.get_hyperparameters(): value = configuration.get(hp.name) if value is None: if strategy == 'default': new_value = hp.default_value elif isinstance(strategy, float): new_value = strategy else: raise ValueError('Unknown imputation strategy %s' % str(strategy)) value = new_value values[hp.name] = value new_configuration = Configuration(configuration.configuration_space, values=values, allow_inactive_with_values=True) return new_configuration
def get_one_exchange_neighbourhood( configuration: Configuration, seed: int, num_neighbors: int=4, stdev: float=0.2, ) -> Generator[Configuration, None, None]: """Return all configurations in a one-exchange neighborhood. The method is implemented as defined by: Frank Hutter, Holger H. Hoos and Kevin Leyton-Brown Sequential Model-Based Optimization for General Algorithm Configuration In: Proceedings of the conference on Learning and Intelligent OptimizatioN (LION 5) """ random = np.random.RandomState(seed) hyperparameters_list = list( list(configuration.configuration_space._hyperparameters.keys()) ) hyperparameters_list_length = len(hyperparameters_list) hyperparameters_used = [hp.name for hp in configuration.configuration_space.get_hyperparameters() if hp.get_num_neighbors(configuration.get(hp.name)) == 0 and configuration.get(hp.name) is not None] number_of_usable_hyperparameters = sum(np.isfinite(configuration.get_array())) n_neighbors_per_hp = { hp.name: num_neighbors if np.isinf(hp.get_num_neighbors(configuration.get(hp.name))) else hp.get_num_neighbors(configuration.get(hp.name)) for hp in configuration.configuration_space.get_hyperparameters() } finite_neighbors_stack = {} # type: Dict configuration_space = configuration.configuration_space # type: ConfigSpaceNNI while len(hyperparameters_used) < number_of_usable_hyperparameters: index = int(random.randint(hyperparameters_list_length)) hp_name = hyperparameters_list[index] if n_neighbors_per_hp[hp_name] == 0: continue else: neighbourhood = [] number_of_sampled_neighbors = 0 array = configuration.get_array() # type: np.ndarray value = array[index] # type: float # Check for NaNs (inactive value) if value != value: continue iteration = 0 hp = configuration_space.get_hyperparameter(hp_name) # type: Hyperparameter num_neighbors_for_hp = hp.get_num_neighbors(configuration.get(hp_name)) while True: # Obtain neigbors differently for different possible numbers of # neighbors if num_neighbors_for_hp == 0: break # No infinite loops elif iteration > 100: break elif np.isinf(num_neighbors_for_hp): if number_of_sampled_neighbors >= 1: break # TODO if code becomes slow remove the isinstance! if isinstance(hp, (UniformFloatHyperparameter, UniformIntegerHyperparameter)): neighbor = hp.get_neighbors(value, random, number=1, std=stdev)[0] else: neighbor = hp.get_neighbors(value, random, number=1)[0] else: if iteration > 0: break if hp_name not in finite_neighbors_stack: neighbors = hp.get_neighbors(value, random) random.shuffle(neighbors) finite_neighbors_stack[hp_name] = neighbors else: neighbors = finite_neighbors_stack[hp_name] neighbor = neighbors.pop() # Check all newly obtained neigbors new_array = array.copy() new_array = ConfigSpaceNNI.c_util.change_hp_value( configuration_space=configuration_space, configuration_array=new_array, hp_name=hp_name, hp_value=neighbor, index=index) try: # Populating a configuration from an array does not check # if it is a legal configuration - check this (slow) new_configuration = Configuration(configuration_space, vector=new_array) # type: Configuration # Only rigorously check every tenth configuration ( # because moving around in the neighborhood should # just work!) if np.random.random() > 0.95: new_configuration.is_valid_configuration() else: configuration_space._check_forbidden(new_array) neighbourhood.append(new_configuration) except ForbiddenValueError as e: pass iteration += 1 if len(neighbourhood) > 0: number_of_sampled_neighbors += 1 # Some infinite loop happened and no valid neighbor was found OR # no valid neighbor is available for a categorical if len(neighbourhood) == 0: hyperparameters_used.append(hp_name) n_neighbors_per_hp[hp_name] = 0 hyperparameters_used.append(hp_name) else: if hp_name not in hyperparameters_used: n_ = neighbourhood.pop() n_neighbors_per_hp[hp_name] -= 1 if n_neighbors_per_hp[hp_name] == 0: hyperparameters_used.append(hp_name) yield n_