From 2de7d5e277e7a8e00ab1b5605771cb0d0f12552f Mon Sep 17 00:00:00 2001 From: Jeremy Rapin Date: Wed, 1 Apr 2020 15:40:56 +0200 Subject: [PATCH 1/5] Use Parameter in OnePlusOne --- nevergrad/optimization/optimizerlib.py | 50 ++++++++++++++------------ 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py index da4ed7afa..499e39e1b 100644 --- a/nevergrad/optimization/optimizerlib.py +++ b/nevergrad/optimization/optimizerlib.py @@ -69,11 +69,11 @@ def __init__( self.mutation = mutation self.crossover = crossover - def _internal_ask(self) -> ArrayLike: + def _internal_ask_candidate(self) -> p.Parameter: # pylint: disable=too-many-return-statements, too-many-branches noise_handling = self.noise_handling if not self._num_ask: - return np.zeros(self.dimension) + return self.parametrization.spawn_child() # for noisy version if noise_handling is not None: limit = (0.05 if isinstance(noise_handling, str) else noise_handling[1]) * len(self.archive) ** 3 @@ -81,33 +81,39 @@ def _internal_ask(self) -> ArrayLike: if self._num_ask <= limit: if strategy in ["cubic", "random"]: idx = self._rng.choice(len(self.archive)) - return np.frombuffer(list(self.archive.bytesdict.keys())[idx]) # type: ignore + return list(self.archive.values())[idx].parameter.spawn_child() # type: ignore elif strategy == "optimistic": - return self.current_bests["optimistic"].parameter.get_standardized_data(reference=self.parametrization) + return self.current_bests["optimistic"].parameter.spawn_child() # crossover mutator = mutations.Mutator(self._rng) - pessimistic = self.current_bests["pessimistic"].parameter.get_standardized_data(reference=self.parametrization) + pessimistic = self.current_bests["pessimistic"].parameter.spawn_child() + ref = self.parametrization if self.crossover and self._num_ask % 2 == 1 and len(self.archive) > 2: - return mutator.crossover(pessimistic, mutator.get_roulette(self.archive, num=2)) + data = mutator.crossover(pessimistic.get_standardized_data(reference=ref), + mutator.get_roulette(self.archive, num=2)) + return pessimistic.set_standardized_data(data, reference=ref) # mutating mutation = self.mutation - if mutation == "gaussian": # standard case - return pessimistic + self._sigma * self._rng.normal(0, 1, self.dimension) # type: ignore - elif mutation == "cauchy": - return pessimistic + self._sigma * self._rng.standard_cauchy(self.dimension) # type: ignore - elif mutation == "crossover": - if self._num_ask % 2 == 0 or len(self.archive) < 3: - return mutator.portfolio_discrete_mutation(pessimistic) - else: - return mutator.crossover(pessimistic, mutator.get_roulette(self.archive, num=2)) + if mutation in ("gaussian", "cauchy"): # standard case + step = (self._rng.normal(0, 1, self.dimension) if mutation == "gaussian" else + self._rng.standard_cauchy(self.dimension)) + return pessimistic.set_standardized_data(self._sigma * step) # type: ignore else: - func: Callable[[ArrayLike], ArrayLike] = { # type: ignore - "discrete": mutator.discrete_mutation, - "fastga": mutator.doerr_discrete_mutation, - "doublefastga": mutator.doubledoerr_discrete_mutation, - "portfolio": mutator.portfolio_discrete_mutation, - }[mutation] - return func(pessimistic) + pessimistic_data = pessimistic.get_standardized_data(reference=ref) + if mutation == "crossover": + if self._num_ask % 2 == 0 or len(self.archive) < 3: + data = mutator.portfolio_discrete_mutation(pessimistic_data) + else: + data = mutator.crossover(pessimistic_data, mutator.get_roulette(self.archive, num=2)) + else: + func: Callable[[ArrayLike], ArrayLike] = { # type: ignore + "discrete": mutator.discrete_mutation, + "fastga": mutator.doerr_discrete_mutation, + "doublefastga": mutator.doubledoerr_discrete_mutation, + "portfolio": mutator.portfolio_discrete_mutation, + }[mutation] + data = func(pessimistic_data) + return pessimistic.set_standardized_data(data, reference=ref) def _internal_tell(self, x: ArrayLike, value: float) -> None: # only used for cauchy and gaussian From a9b4c031d73e61549238760761a6098390d01d1b Mon Sep 17 00:00:00 2001 From: Jeremy Rapin Date: Wed, 1 Apr 2020 16:46:06 +0200 Subject: [PATCH 2/5] sigmatracking --- nevergrad/optimization/optimizerlib.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py index 499e39e1b..6463edf76 100644 --- a/nevergrad/optimization/optimizerlib.py +++ b/nevergrad/optimization/optimizerlib.py @@ -73,7 +73,9 @@ def _internal_ask_candidate(self) -> p.Parameter: # pylint: disable=too-many-return-statements, too-many-branches noise_handling = self.noise_handling if not self._num_ask: - return self.parametrization.spawn_child() + out = self.parametrization.spawn_child() + out._meta["sigma"] = self._sigma + return out # for noisy version if noise_handling is not None: limit = (0.05 if isinstance(noise_handling, str) else noise_handling[1]) * len(self.archive) ** 3 @@ -97,7 +99,9 @@ def _internal_ask_candidate(self) -> p.Parameter: if mutation in ("gaussian", "cauchy"): # standard case step = (self._rng.normal(0, 1, self.dimension) if mutation == "gaussian" else self._rng.standard_cauchy(self.dimension)) - return pessimistic.set_standardized_data(self._sigma * step) # type: ignore + out = pessimistic.set_standardized_data(self._sigma * step) + out._meta["sigma"] = self._sigma + return out else: pessimistic_data = pessimistic.get_standardized_data(reference=ref) if mutation == "crossover": From 6c80f45dbc0fddc9cc978c80a646bbb344bcc56a Mon Sep 17 00:00:00 2001 From: Jeremy Rapin Date: Wed, 1 Apr 2020 16:47:48 +0200 Subject: [PATCH 3/5] fixtest --- nevergrad/optimization/test_callbacks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nevergrad/optimization/test_callbacks.py b/nevergrad/optimization/test_callbacks.py index a21bd4a6a..546e73180 100644 --- a/nevergrad/optimization/test_callbacks.py +++ b/nevergrad/optimization/test_callbacks.py @@ -31,9 +31,9 @@ def test_log_parameters(tmp_path: Path) -> None: logs = logger.load_flattened() assert len(logs) == 32 assert isinstance(logs[-1]["1"], float) - assert len(logs[-1]) == 34 + assert len(logs[-1]) == 35 logs = logger.load_flattened(max_list_elements=2) - assert len(logs[-1]) == 26 + assert len(logs[-1]) == 27 # deletion logger = callbacks.ParametersLogger(filepath, append=False) assert not logger.load() From 9b48b38492d04b69fee335ed779a65acd7e06e86 Mon Sep 17 00:00:00 2001 From: Jeremy Rapin Date: Wed, 1 Apr 2020 17:51:19 +0200 Subject: [PATCH 4/5] upd --- nevergrad/benchmark/experiments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nevergrad/benchmark/experiments.py b/nevergrad/benchmark/experiments.py index 1697ca7af..82689086c 100644 --- a/nevergrad/benchmark/experiments.py +++ b/nevergrad/benchmark/experiments.py @@ -818,7 +818,7 @@ def photonics(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: def bragg_structure(seed: tp.Optional[int] = None) -> tp.Iterator[Experiment]: seedg = create_seed_generator(seed) recombinable: tp.List[tp.Union[str, ConfiguredOptimizer]] = [ - ng.families.EvolutionStrategy(recombination_ratio=0.1, popsize=40).set_name("DES"), + ng.families.EvolutionStrategy(recombination_ratio=0.1, popsize=40).set_name("Pairwise-ES"), ng.families.DifferentialEvolution(crossover="parametrization").set_name("Param-DE") ] algos: tp.List[tp.Union[str, ConfiguredOptimizer]] = ["TwoPointsDE", "DE", "CMA", "NaiveTBPSA", "DiagonalCMA"] From bca2c9ea955f922f44f63a0ce558bc3b3ec7febe Mon Sep 17 00:00:00 2001 From: Jeremy Rapin Date: Thu, 2 Apr 2020 13:40:28 +0200 Subject: [PATCH 5/5] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 888abfb18..6f8526502 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ variables when the `full_range_sampling` is `True` [598](https://github.com/facebookresearch/nevergrad/pull/598). This required some ugly hacks, help is most welcome to find nices solutions. - `full_range_sampling` is activated by default if both range are provided in `Array.set_bounds`. +- Propagate parametrization system features (generation tracking, ...) to `OnePlusOne` based algorithms [599](https://github.com/facebookresearch/nevergrad/pull/599). ## v0.4.0 (2019-03-09)