optuna / optuna-examples

Examples for https://github.com/optuna/optuna
MIT License
632 stars 171 forks source link

Switch to NSGA sampler after initial trials with custom sampler #261

Closed Djkmarco closed 1 month ago

Djkmarco commented 1 month ago

Hello everyone,

I'm designing a study that involves two sampling strategies. In the first phase, I use a custom sampler to run 100 trials and store the results in a SQLite database.

In the second phase, I load the results from the first phase and employ the NGSAIII algorithm with a population size of 50 for 1000 trials.

I'm unclear about how NGSAIII leverages the information from the custom sampler trials. Does it incorporate the results into the initial population for the second phase?

To provide more context, here's a relevant code snippet.

import optuna

trials = 1000

def fake_objective(trial):
    x = trial.suggest_float("x", -10, 10)
    y = trial.suggest_float("y", -10, 10)
    return x**2 + y**2

sampler1 = optuna.samplers.RandomSampler(seed=42) # in my study this is a custom sampler

study1 = optuna.create_study(sampler=sampler1,
                            study_name="study",
                            storage=f"sqlite:///study.db",
                            load_if_exists=True,)

study1.optimize(fake_objective, n_trials=trials//5)

sampler2 = optuna.samplers.NSGAIIISampler(seed=42,
                                          population_size=trials//20,
                                          mutation_prob=.1,
                                          crossover=optuna.samplers.nsgaii.SBXCrossover(eta=10),
                                          crossover_prob = .8,
                                          )

study2 = optuna.create_study(sampler=sampler2,
                            study_name="study",
                            storage=f"sqlite:///study.db",
                            load_if_exists=True,)

study2.optimize(fake_objective, n_trials=trials)

For my understanding it doesn't as the trials from the first part of the study do not have a _GENERATION_KEY and _collect_parent_population requires that.

    def _collect_parent_population(self, study: Study) -> tuple[int, list[FrozenTrial]]:
        trials = study.get_trials(deepcopy=False)

        generation_to_runnings = defaultdict(list)
        generation_to_population = defaultdict(list)
        for trial in trials:
            if _GENERATION_KEY not in trial.system_attrs:
                continue

            generation = trial.system_attrs[_GENERATION_KEY]
            if trial.state != optuna.trial.TrialState.COMPLETE:
                if trial.state == optuna.trial.TrialState.RUNNING:
                    generation_to_runnings[generation].append(trial)
                continue

            # Do not use trials whose states are not COMPLETE, or `constraint` will be unavailable.
            generation_to_population[generation].append(trial)`

Any insights on this would be greatly appreciated. Thanks!

nzw0301 commented 1 month ago

duplicated with https://github.com/optuna/optuna/discussions/5436