optuna / kurobako-py

A Python library to help implement kurobako's solvers and problems
MIT License
9 stars 7 forks source link

Support new multi-objective API from Optuna v.2.4.0 #7

Closed hvy closed 3 years ago

hvy commented 3 years ago

Multi-objective optimization (e.g. specifying directions instead of direction in optuna.create_study) is becoming a first class citizen in Optuna. C.f. https://github.com/optuna/optuna/issues/1980. Some private APIs that we rely on here were updated during the course. This PR aims to fix those compatibility issues.

Let me know if I'm missing something since I'm not that familiar with the internals of Kurobako. Thanks.

hvy commented 3 years ago

Ready for review. I think these are the minimum changes required to support Optuna's upcoming v2.4.

Verified with the following toy example.

binh_and_korn_problem.py

```python from kurobako import problem class BinhAndKornProblemFactory(problem.ProblemFactory): def specification(self): params = [ problem.Var("x", problem.ContinuousRange(0, 5)), problem.Var("y", problem.ContinuousRange(0, 3)), ] return problem.ProblemSpec( name="Binh and Korn Function", params=params, values=[ problem.Var("4 * x ** 2 + 4 * y ** 2"), problem.Var("(x - 5) ** 2 + (y - 5) ** 2"), ], ) def create_problem(self, seed): return BinhAndKornProblem() class BinhAndKornProblem(problem.Problem): def create_evaluator(self, params): return BinhAndKornEvaluator(params) class BinhAndKornEvaluator(problem.Evaluator): def __init__(self, params): self._x, self._y = params self._current_step = 0 def current_step(self): return self._current_step def evaluate(self, next_step): self._current_step = 1 return [4 * self._x ** 2 + 4 * self._y ** 2, (self._x - 5) ** 2 + (self._y - 5) ** 2] if __name__ == "__main__": runner = problem.ProblemRunner(BinhAndKornProblemFactory()) runner.run() ```

random_solver.py # Just Kurobako's official example.

```python from kurobako import problem from kurobako import solver from kurobako.solver.optuna import OptunaSolverFactory import numpy as np import optuna class RandomSolverFactory(solver.SolverFactory): def specification(self): return solver.SolverSpec(name="Random Search") def create_solver(self, seed, problem): return RandomSolver(seed, problem) class RandomSolver(solver.Solver): def __init__(self, seed, problem): self._rng = np.random.RandomState(seed) self._problem = problem def ask(self, idg): params = [] for p in self._problem.params: if p.distribution == problem.Distribution.UNIFORM: params.append(self._rng.uniform(p.range.low, p.range.high)) else: low = np.log(p.range.low) high = np.log(p.range.high) params.append(float(np.exp(self._rng.uniform(low, high)))) trial_id = idg.generate() next_step = self._problem.last_step return solver.NextTrial(trial_id, params, next_step) def tell(self, trial): pass if __name__ == "__main__": runner = solver.SolverRunner(RandomSolverFactory()) runner.run() ```

botorch_solver.py

```python from kurobako import problem from kurobako import solver from kurobako.solver.optuna import OptunaSolverFactory import numpy as np import optuna import argparse parser = argparse.ArgumentParser() parser.add_argument("--directions", nargs="+") args = parser.parse_args() def create_study(seed): sampler = optuna.integration.BoTorchSampler() return optuna.create_study(directions=args.directions, sampler=sampler) if __name__ == "__main__": factory = OptunaSolverFactory(create_study) runner = solver.SolverRunner(factory) runner.run() ```

sile commented 3 years ago

I think that I'll publish the next version of kurkobako-py once Optuna-v2.4 is released. Please let me know if you need the new version soon.

hvy commented 3 years ago

Thanks for checking, it's not a hurry actually. With v2.4 sounds good, since this change depends on it. It should be released rather soon.