def select(self, keys): """Only select or only drop the specified keys For a pair (key, value) in the dictionnary, value=0 means the key will not be included while value=1 means it will. All specified keys should be 0 or 1. They cannot have different values with the exception of _id which can be specified to 0 while the others are at 1. The _id field is always returned unless specified with 0. Parameters ---------- keys: dict Pairs of keys and 0 or 1s. When a key is associated with 1, it is kept in the selection, otherwise it is dropped. """ if not keys: return unflatten(self._data) keys = flatten(keys) keys = self._validate_keys(keys) selection = dict() def key_is_match(key, selected_key): """Test if key matches the selected key key_is_match(abc.def.ghi, abc.def.ghi) -> True key_is_match(abc.def.ghi, abc.def) -> True key_is_match(abc.def.ghi, abc.de) -> False key_is_match(abc.def.ghi, xyz) -> False """ return (key == selected_key or (key.startswith(selected_key) and key.replace(selected_key, '')[0] == ".")) for selected_key, include in filter(lambda item: item[1], keys.items()): match = False for key, value in self._data.items(): if include and key_is_match(key, selected_key): match = True selection[key] = value if not match: selection[selected_key] = None return unflatten(selection)
def workon(self, fct, max_trials=infinity, **kwargs): """Optimize a given function Parameters ---------- fct: callable Function to optimize. Must take arguments provided by trial.params. Additional constant parameter can be passed as ``**kwargs`` to `workon`. Function must return the final objective. max_trials: int, optional Maximum number of trials to execute within `workon`. If the experiment or algorithm reach status is_done before, the execution of `workon` terminates. **kwargs Constant argument to pass to `fct` in addition to trial.params. If values in kwargs are present in trial.params, the latter takes precedence. Raises ------ `ValueError` If results returned by `fct` have invalid format """ trials = 0 kwargs = flatten(kwargs) while not self.is_done and trials < max_trials: trial = self.suggest() if trial is None: log.warning('Algorithm could not sample new points') return trials kwargs.update(flatten(trial.params)) results = fct(**unflatten(kwargs)) self.observe(trial, results=results) trials += 1 return trials
def _optimize(trial, fct, trial_arg, **kwargs): """Execute a trial on a worker""" kwargs.update(flatten(trial.params)) if trial_arg: kwargs[trial_arg] = trial return fct(**unflatten(kwargs))
def __call__(self, rng, space, params): """Execute perturbation Given a set of parameter values, this exploration object randomly perturb them with a given ``factor``. It will multiply the value of a dimension with probability 0.5, otherwise divide it. Values are clamped to limits of the search space when exceeding it. For categorical dimensions, a new value is sampled from categories with equal probability for each categories. Parameters ---------- rng: numpy.random.Generator A random number generator. It is not contained in ``BaseExplore`` because the explore class must be stateless. space: Space The search space optimized by the algorithm. params: dict Dictionary representing the parameters of the current trial under examination (`trial.params`). Returns ------- ``dict`` The new set of parameters for the trial to be branched. """ new_params = {} params = flatten(params) for dim in space.values(): dim_value = params[dim.name] if dim.type == "real": dim_value = self.perturb_real(rng, dim_value, dim.interval()) elif dim.type == "integer": dim_value = self.perturb_int(rng, dim_value, dim.interval()) elif dim.type == "categorical": dim_value = self.perturb_cat(rng, dim_value, dim) elif dim.type == "fidelity": # do nothing pass else: raise ValueError(f"Unsupported dimension type {dim.type}") new_params[dim.name] = dim_value return unflatten(new_params)
def update(self, data): """Update the values of the document. Parameters ---------- data: dict Dictionary of data to update the document. If `$set` is in the data, the corresponding `data[$set]` will be used instead. """ if "$set" in data: unflattened_data = unflatten(self._data) for key, value in data["$set"].items(): if isinstance(value, dict): value = flatten(value) unflattened_data[key] = value self._data = flatten(unflattened_data) else: self._data.update(flatten(data))
def fetch_config_from_cmdargs(cmdargs): """Turn flat cmdargs into nested dicts like orion.core.config.""" config_file = cmdargs.pop("config", None) tmp_cmdargs = copy.deepcopy(cmdargs) tmp_cmdargs["config"] = config_file cmdargs["config"] = config_file cmdargs = tmp_cmdargs cmdargs_config = {} if cmdargs.get("max_trials") is not None: log.warning("--max-trials is deprecated and will be removed in v0.3. " "Use --exp-max-trials instead") cmdargs_config["experiment.max_trials"] = cmdargs.pop("max_trials") if cmdargs.get("worker_trials") is not None: log.warning( "--worker-trials is deprecated and will be removed in v0.3. " "Use --worker-max-trials instead") cmdargs_config["worker.max_trials"] = cmdargs.pop("worker_trials") mappings = dict( experiment=dict(max_broken="exp_max_broken", max_trials="exp_max_trials"), worker=dict(max_broken="worker_max_broken", max_trials="worker_max_trials"), evc=dict(enable="enable_evc"), ) global_config = orion.core.config.to_dict() for key in ["config", "user_args"]: if cmdargs.get(key) not in [False, None]: cmdargs_config[key] = cmdargs[key] for key in ["name", "user", "version"]: if cmdargs.get(key) not in [False, None]: cmdargs_config[f"experiment.{key}"] = cmdargs[key] for key in ["branch_from", "branch_to"]: if cmdargs.get(key) not in [False, None]: cmdargs_config[f"evc.{key}"] = cmdargs[key] # Apply config at the root for key in ["debug"]: # Adapt to cli arguments cli_key = mappings.get(key, key) value = cmdargs.pop(cli_key, None) if value is not None: cmdargs_config[f"{key}"] = value # Apply to subconfigs for key in ["experiment", "worker", "evc"]: for subkey in global_config[key].keys(): # Adapt to cli arguments cli_key = mappings.get(key, {}).get(subkey, subkey) value = cmdargs.pop(cli_key, None) if value is not None: cmdargs_config[f"{key}.{subkey}"] = value return unflatten(cmdargs_config)
def fetch_config(args): """Return the config inside the .yaml file if present.""" orion_file = args.get("config") local_config = {} if orion_file: log.debug("Found orion configuration file at: %s", os.path.abspath(orion_file.name)) orion_file.seek(0) tmp_config = yaml.safe_load(orion_file) global_config = orion.core.config.to_dict() tmp_config = _convert_dashes(tmp_config, global_config) # Fix deprecations first because some names are shared by experiment and worker max_trials = tmp_config.pop("max_trials", None) if max_trials is not None: log.warning( "(DEPRECATED) Option `max_trials` is deprecated " "and will be removed in v0.3. Use instead the option" "\nexperiment:\n max_trials: %s", max_trials, ) local_config["experiment.max_trials"] = max_trials worker_trials = tmp_config.get("experiment", {}).pop("worker_trials", None) if worker_trials is not None: log.warning( "(DEPRECATED) Option `experiment.worker_trials` is deprecated " "and will be removed in v0.3. Use instead the option" "\nworker:\n max_trials: %s", worker_trials, ) local_config["worker.max_trials"] = worker_trials worker_trials = tmp_config.pop("worker_trials", None) if worker_trials is not None: log.warning( "(DEPRECATED) Option `worker_trials` is deprecated " "and will be removed in v0.3. Use instead the option" "\nworker:\n max_trials: %s", worker_trials, ) local_config["worker.max_trials"] = worker_trials # TODO: Remove for v0.3 producer = tmp_config.pop("producer", None) if producer is not None: log.warning( "(DEPRECATED) Option `producer` is deprecated " "and will be removed in v0.3. Use instead the option" "\nexperiment:\n strategy: %s", producer["strategy"], ) local_config["experiment.strategy"] = producer["strategy"] # TODO: Remove for v0.3 producer = tmp_config.get("experiment", {}).pop("producer", None) if producer is not None: log.warning( "(DEPRECATED) Option `experiment.producer` is deprecated " "and will be removed in v0.3. Use instead the option" "\nexperiment:\n strategy: %s", producer["strategy"], ) local_config["experiment.strategy"] = producer["strategy"] local_config = unflatten(local_config) # For backward compatibility for key in ["storage", "experiment", "worker", "evc"]: subkeys = list(global_config[key].keys()) # Arguments that are only supported locally if key == "experiment": subkeys += ["name", "version", "user"] elif key == "evc": subkeys += ["branch_from", "branch_to"] for subkey in subkeys: # Backward compatibility backward_value = tmp_config.pop(subkey, None) if backward_value is not None: log.warning( "(DEPRECATED) Option `%s` and will be removed in v0.3. " "Use instead the option" "\n%s:\n %s:\n %s", subkey, key, subkey, yaml.dump(backward_value, indent=6), ) value = tmp_config.get(key, {}).pop(subkey, backward_value) if value is not None: local_config.setdefault(key, {}) local_config[key][subkey] = value return local_config
def params(self): """Parameters of the trial""" return unflatten({param.name: param.value for param in self._params})
def fetch_config(args): """Return the config inside the .yaml file if present.""" orion_file = args.get('config') local_config = {} if orion_file: log.debug("Found orion configuration file at: %s", os.path.abspath(orion_file.name)) orion_file.seek(0) tmp_config = yaml.safe_load(orion_file) global_config = config.to_dict() tmp_config = _convert_dashes(tmp_config, global_config) # Fix deprecations first because some names are shared by experiment and worker max_trials = tmp_config.pop('max_trials', None) if max_trials is not None: log.warning( '(DEPRECATED) Option `max_trials` is deprecated ' 'and will be removed in v0.3. Use instead the option' '\nexperiment:\n max_trials: %s', max_trials) local_config['experiment.max_trials'] = max_trials worker_trials = tmp_config.get('experiment', {}).pop('worker_trials', None) if worker_trials is not None: log.warning( '(DEPRECATED) Option `experiment.worker_trials` is deprecated ' 'and will be removed in v0.3. Use instead the option' '\nworker:\n max_trials: %s', worker_trials) local_config['worker.max_trials'] = worker_trials worker_trials = tmp_config.pop('worker_trials', None) if worker_trials is not None: log.warning( '(DEPRECATED) Option `worker_trials` is deprecated ' 'and will be removed in v0.3. Use instead the option' '\nworker:\n max_trials: %s', worker_trials) local_config['worker.max_trials'] = worker_trials producer = tmp_config.pop('producer', None) if producer is not None: log.warning( '(DEPRECATED) Option `producer` is deprecated ' 'and will be removed in v0.3. Use instead the option' '\nexperiment:\n strategy: %s', producer['strategy']) local_config['experiment.strategy'] = producer['strategy'] producer = tmp_config.get('experiment', {}).pop('producer', None) if producer is not None: log.warning( '(DEPRECATED) Option `experiment.producer` is deprecated ' 'and will be removed in v0.3. Use instead the option' '\nexperiment:\n strategy: %s', producer['strategy']) local_config['experiment.strategy'] = producer['strategy'] local_config = unflatten(local_config) # For backward compatibility for key in ['storage', 'experiment', 'worker', 'evc']: subkeys = list(global_config[key].keys()) # Arguments that are only supported locally if key == 'experiment': subkeys += ['name', 'version', 'user'] elif key == 'evc': subkeys += ['branch_from', 'branch_to'] for subkey in subkeys: # Backward compatibility backward_value = tmp_config.pop(subkey, None) if backward_value is not None: log.warning( '(DEPRECATED) Option `%s` and will be removed in v0.3. ' 'Use instead the option' '\n%s:\n %s:\n %s', subkey, key, subkey, yaml.dump(backward_value, indent=6)) value = tmp_config.get(key, {}).pop(subkey, backward_value) if value is not None: local_config.setdefault(key, {}) local_config[key][subkey] = value return local_config
def fetch_config_from_cmdargs(cmdargs): """Turn flat cmdargs into nested dicts like orion.core.config.""" config_file = cmdargs.pop('config', None) tmp_cmdargs = copy.deepcopy(cmdargs) tmp_cmdargs['config'] = config_file cmdargs['config'] = config_file cmdargs = tmp_cmdargs cmdargs_config = {} if cmdargs.get('max_trials') is not None: log.warning( '--max-trials is deprecated and will be removed in v0.3. ' 'Use --exp-max-trials instead') cmdargs_config['experiment.max_trials'] = cmdargs.pop('max_trials') if cmdargs.get('worker_trials') is not None: log.warning( '--worker-trials is deprecated and will be removed in v0.3. ' 'Use --worker-max-trials instead') cmdargs_config['worker.max_trials'] = cmdargs.pop('worker_trials') mappings = dict( experiment=dict( exp_max_broken='max_broken', exp_max_trials='max_trials'), worker=dict( worker_max_broken='max_broken', worker_max_trials='max_trials')) mappings = dict( experiment=dict( max_broken='exp_max_broken', max_trials='exp_max_trials'), worker=dict( max_broken='worker_max_broken', max_trials='worker_max_trials')) global_config = config.to_dict() for key in ['config', 'user_args']: if cmdargs.get(key) not in [False, None]: cmdargs_config[key] = cmdargs[key] for key in ['name', 'user', 'version']: if cmdargs.get(key) not in [False, None]: cmdargs_config[f'experiment.{key}'] = cmdargs[key] for key in ['branch_from', 'branch_to']: if cmdargs.get(key) not in [False, None]: cmdargs_config[f'evc.{key}'] = cmdargs[key] # Apply config at the root for key in ['debug']: # Adapt to cli arguments cli_key = mappings.get(key, key) value = cmdargs.pop(cli_key, None) if value is not None: cmdargs_config[f'{key}'] = value # Apply to subconfigs for key in ['experiment', 'worker', 'evc']: for subkey in global_config[key].keys(): # Adapt to cli arguments cli_key = mappings.get(key, {}).get(subkey, subkey) value = cmdargs.pop(cli_key, None) if value is not None: cmdargs_config[f'{key}.{subkey}'] = value return unflatten(cmdargs_config)
def params(self): """See `~orion.core.worker.trial.Trial`""" if self.memory is not None: return self.memory.params return unflatten({param.name: param.value for param in self._params})
def test_unflatten(): """Test than unflatten(flatten(x)) is idempotent""" a = {"b": 2, "c": 3} d = {"a": a, "d": {"e": a}} assert unflatten(flatten(d)) == d