[tune] Add compatibility to nevergrad 0.2.0+ (#4529)

## What do these changes do?

This PR prepares for future version  0.2.0 of `nevergrad`, in which each suggestion is a `Candidate` instance having fields `args` and `kwargs` instead of being a `np.ndarray`. The proposed changes are compatible with all versions of `nevergrad` (manually tested with `nevergrad_example.py` on both `master` and current version `v0.1.6`).

See `nevergrad`'s [CHANGELOG](https://github.com/facebookresearch/nevergrad/blob/master/CHANGELOG.md) for more information on the change.

## Related issue number

None

## Linter

- [x] I've run `scripts/format.sh` to lint the changes in this PR.
This commit is contained in:
Jérémy
2019-04-06 04:44:58 +02:00
committed by Richard Liaw
parent bfd0af52bc
commit 300ec72d15
2 changed files with 60 additions and 6 deletions
+11 -2
View File
@@ -42,9 +42,18 @@ if __name__ == "__main__":
"timesteps_total": 100
}
}
optimizer = optimizerlib.OnePlusOne(dimension=2)
instrumentation = 2
parameter_names = ["height", "width"]
# With nevergrad v0.2.0+ the following is also possible:
# from nevergrad import instrumentation as inst
# instrumentation = inst.Instrumentation(
# height=inst.var.Array(1).bounded(0, 200).asfloat(),
# width=inst.var.OrderedDiscrete([0, 10, 20, 30, 40, 50]))
# parameter_names = None # names are provided by the instrumentation
optimizer = optimizerlib.OnePlusOne(instrumentation)
algo = NevergradSearch(
optimizer, ["height", "width"],
optimizer,
parameter_names,
max_concurrent=4,
reward_attr="neg_mean_loss")
scheduler = AsyncHyperBandScheduler(reward_attr="neg_mean_loss")
+49 -4
View File
@@ -23,7 +23,9 @@ class NevergradSearch(SuggestionAlgorithm):
optimizer (nevergrad.optimization.Optimizer): Optimizer provided
from Nevergrad.
parameter_names (list): List of parameter names. Should match
the dimension of the optimizer output.
the dimension of the optimizer output. Alternatively, set to None
if the optimizer is already instrumented with kwargs
(see nevergrad v0.2.0+).
max_concurrent (int): Number of maximum concurrent trials. Defaults
to 10.
reward_attr (str): The training result objective value attribute.
@@ -31,9 +33,24 @@ class NevergradSearch(SuggestionAlgorithm):
Example:
>>> from nevergrad.optimization import optimizerlib
>>> optimizer = optimizerlib.OnePlusOne(dimension=1, budget=100)
>>> algo = NevergradSearch(
>>> optimizer, max_concurrent=4, reward_attr="neg_mean_loss")
>>> instrumentation = 1
>>> optimizer = optimizerlib.OnePlusOne(instrumentation, budget=100)
>>> algo = NevergradSearch(optimizer, ["lr"], max_concurrent=4,
>>> reward_attr="neg_mean_loss")
Note:
In nevergrad v0.2.0+, optimizers can be instrumented.
For instance, the following will specifies searching
for "lr" from 1 to 2.
>>> from nevergrad.optimization import optimizerlib
>>> from nevergrad import instrumentation as inst
>>> lr = inst.var.Array(1).bounded(1, 2).asfloat()
>>> instrumentation = inst.Instrumentation(lr=lr)
>>> optimizer = optimizerlib.OnePlusOne(instrumentation, budget=100)
>>> algo = NevergradSearch(optimizer, None, max_concurrent=4,
>>> reward_attr="neg_mean_loss")
"""
def __init__(self,
@@ -50,12 +67,40 @@ class NevergradSearch(SuggestionAlgorithm):
self._nevergrad_opt = optimizer
self._live_trial_mapping = {}
super(NevergradSearch, self).__init__(**kwargs)
# validate parameters
if hasattr(optimizer, "instrumentation"): # added in v0.2.0
if optimizer.instrumentation.kwargs:
if optimizer.instrumentation.args:
raise ValueError(
"Instrumented optimizers should use kwargs only")
if parameter_names is not None:
raise ValueError("Instrumented optimizers should provide "
"None as parameter_names")
else:
if parameter_names is None:
raise ValueError("Non-instrumented optimizers should have "
"a list of parameter_names")
if len(optimizer.instrumentation.args) != 1:
raise ValueError(
"Instrumented optimizers should use kwargs only")
if parameter_names is not None and optimizer.dimension != len(
parameter_names):
raise ValueError("len(parameters_names) must match optimizer "
"dimension for non-instrumented optimizers")
def _suggest(self, trial_id):
if self._num_live_trials() >= self._max_concurrent:
return None
suggested_config = self._nevergrad_opt.ask()
self._live_trial_mapping[trial_id] = suggested_config
# in v0.2.0+, output of ask() is a Candidate,
# with fields args and kwargs
if hasattr(self._nevergrad_opt, "instrumentation"):
if not suggested_config.kwargs:
return dict(zip(self._parameters, suggested_config.args[0]))
else:
return suggested_config.kwargs
# legacy: output of ask() is a np.ndarray
return dict(zip(self._parameters, suggested_config))
def on_trial_result(self, trial_id, result):