Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IPOP-CMA-ES support in CmaEsSampler. #1548

Merged
merged 34 commits into from Sep 1, 2020

Conversation

c-bata
Copy link
Member

@c-bata c-bata commented Jul 23, 2020

Motivation

As the benchmark of two-dimensional Rastrigin function shows, IPOP-CMA-ES outperforms non-restarting CMA-ES on multimodal functions.

rastrigin-dim-2-9855c695e5b1f00465f21e9fd2bebc2e4611a27a42ec8774548e78d4a7359a09

Auger, A., Hansen, N.: A restart CMA evolution strategy with increasing population size. In: Proceedings of the 2005 IEEE Congress on Evolutionary Computation (CEC’2005), pp. 1769–1776 (2005a)

Description of the changes

  • Add restart_strategy argument. Currently accepts ipop or None only. I will implement BIPOP-CMA-ES in the following pull request.
  • After each optimizer.tell(solutions) call, check whether optimizer.should_stop() method returns True or not.
    • If True, re-initialize CMA object with multiplied popsize by inc_popsize. inc_popsize is 2 by default. According to the paper, it reveal similar performance for factors between 2 and 3.
    • Sample initial starting point uniformly at each restart.

TODO:

This PR is ready for review.

@c-bata c-bata added feature Change that does not break compatibility, but affects the public interfaces. optuna.samplers Related to the `optuna.samplers` submodule. This is automatically labeled by github-actions. labels Jul 23, 2020
@c-bata c-bata marked this pull request as ready for review July 28, 2020 05:26
@c-bata c-bata changed the title Support IPOP-CMA-ES: restart with increasing population size. Add IPOP-CMA-ES support in CmaEsSampler. Jul 28, 2020

if self._consider_pruned_trials:
self._raise_experimental_warning_for_consider_pruned_trials()

# TODO(c-bata): Support BIPOP-CMA-ES.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

@c-bata c-bata Jul 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I implemented IPOP-CMA-ES and BIPOP-CMA-ES on Goptuna. A benchmark result of two-dimensional Rastringin function with 10000 trials is below.

rastrigin-function-dim-2-1a14f4610cabf55e51b3b006bfe723dcadef3a57d9eb5c82a09c2c9fbb804c42

It achieved almost the same performance on this benchmark.

optuna/samplers/_cmaes.py Outdated Show resolved Hide resolved
Comment on lines 61 to 62
and ``high`` for each distribution is used. Note that x0 is sampled uniformly within
the search space domain for each restart if you set ``restart_strategy`` argument.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memo: I comment the reason why I choose this design here.

In pycma's implementation, x0 accepts not only the float values. It also accepts callable object (e.g. np.random.rand) and string (e.g. "np.random.rand" which is evaluated by eval()). But I guess it's enough for almost every usecases to sample x0 uniformly at each restart.

@c-bata c-bata marked this pull request as draft July 28, 2020 09:03
@c-bata c-bata marked this pull request as ready for review July 28, 2020 09:14
@HideakiImamura HideakiImamura self-assigned this Aug 25, 2020
Copy link
Member

@HideakiImamura HideakiImamura left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update! LGTM!

Copy link
Member

@hvy hvy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for this very interesting PR.

The implementation is simple and the logic looks good for the most part. I left one question though regarding the system attribute if you could take a look.

optuna/samplers/_cmaes.py Show resolved Hide resolved
@hvy
Copy link
Member

hvy commented Aug 26, 2020

We decided to set experimental decorator at our off-line discussion.
Thank you @HideakiImamura!

Might be good for future record to leave a comment on why. 🙂

@hvy hvy self-assigned this Aug 26, 2020
@c-bata
Copy link
Member Author

c-bata commented Aug 31, 2020

Might be good for future record to leave a comment on why. 🙂

We set experimental decorator because there are some room for discussion about API (e.g. it might be better to make inc_popsize float). And we might find the room for improvements after dogfooding this feature.

@c-bata
Copy link
Member Author

c-bata commented Aug 31, 2020

PTAL.

Copy link
Member

@hvy hvy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your update. I thought that it basically looked good but noticed that the current logic will when collecting previous trial history include trials from "previous restarts". This is because the generation count is reset on restart (since a CMA object is re-instantiated) and we simply collect all trials belonging to the "same generation" and don't care if they stem from different restarts. Is this intended? Maybe we have to include the restart count after all and filter trials based on it in addition to the generation?

optuna/samplers/_cmaes.py Outdated Show resolved Hide resolved
@c-bata
Copy link
Member Author

c-bata commented Aug 31, 2020

Oh, thanks. You are completely correct. It is not intended behavior.
To fix the bug, we need to add n_restarts or something optimizer unique information into the key of system_attrs.

Co-authored-by: Hiroyuki Vincent Yamazaki <hiroyuki.vincent.yamazaki@gmail.com>
@hvy
Copy link
Member

hvy commented Aug 31, 2020

I'm really sorry after having asked you to remove n_restarts but reverting 4947c97 and also filtering based on this count when constructing solution_trials could be a reasonable fix?

@c-bata
Copy link
Member Author

c-bata commented Aug 31, 2020

I'm really sorry after having asked you to remove n_restarts but reverting 4947c97

No. It's not your fault. It's just my mistake.

reverting 4947c97 and also filtering based on this count when constructing solution_trials could be a reasonable fix?

Yeah, sounds reasonable. I'll fix the problem. Thank you!

@c-bata
Copy link
Member Author

c-bata commented Aug 31, 2020

I fixed the bug at cd2e10c.

Copy link
Member

@hvy hvy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick fix and the long running effort. Changes LGTM!

Also leaving the results from a small experiment run locally. It's clear that the restart makes it more explorative escaping a local minimum.

Vanilla

newplot (18)

IPOP

newplot (19)

import optuna

# Himmelblau
def objective(trial):
    x = trial.suggest_float("x", -6, 6)
    y = trial.suggest_float("y", -6, 6)
    return (x ** 2 + y - 11) ** 2 + (x + y ** 2 - 7) ** 2


if __name__ == "__main__":
    study = optuna.create_study(sampler=optuna.samplers.CmaEsSampler(restart_strategy="ipop"))
    study.optimize(objective, n_trials=1000)
    optuna.visualization.plot_slice(study).show()

@hvy
Copy link
Member

hvy commented Sep 1, 2020

@HideakiImamura might want to have another look as well, so I'll leave the final word to him.

@c-bata c-bata marked this pull request as draft September 1, 2020 04:28
@c-bata c-bata marked this pull request as ready for review September 1, 2020 05:19
@c-bata
Copy link
Member Author

c-bata commented Sep 1, 2020

I re-execute Rastrigin (2D) benchmark function at d35a3dc.

rastrigin-dim-2-9855c695e5b1f00465f21e9fd2bebc2e4611a27a42ec8774548e78d4a7359a09

Copy link
Member

@HideakiImamura HideakiImamura left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for all of your efforts. LGTM, again!

@HideakiImamura HideakiImamura merged commit 43d3022 into optuna:master Sep 1, 2020
@c-bata c-bata deleted the ipop-cma-es branch September 1, 2020 05:45
@HideakiImamura HideakiImamura added this to the v2.1.0 milestone Sep 1, 2020
@c-bata
Copy link
Member Author

c-bata commented Sep 1, 2020

Thank you for your thorough review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Change that does not break compatibility, but affects the public interfaces. optuna.samplers Related to the `optuna.samplers` submodule. This is automatically labeled by github-actions.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants