如何在 OptunaHub 中实现您的基准问题(高级)

OptunaHub 提供了 optunahub.benchmarks 模块用于实现基准问题。在本教程中,我们将解释如何使用 optunahub.benchmarks 来实现复杂的基准问题,例如具有动态搜索空间的问题。

对于简单基准问题的实现,请参考 如何在 OptunaHub 中实现您的基准问题(基础)

实现具有动态搜索空间的问题

在这里,我们来实现一个具有动态搜索空间的问题。

首先,导入 optuna 和其他所需的模块。

from __future__ import annotations

import optuna

from optunahub.benchmarks import BaseProblem
from optunahub.benchmarks import ConstrainedMixin

接下来,通过继承 BaseProblem 类来定义您自己的问题类。为了实现具有动态搜索空间的问题,必须重写 __call__(self, trial: optuna.Trial) 方法,以便我们可以通过 define-by-run 的方式定义动态搜索空间。请注意,还必须实现 directions 属性。

class DynamicProblem(BaseProblem):
    def __call__(self, trial: optuna.Trial) -> float:
        x = trial.suggest_float("x", -5, 5)
        if x < 0:
            # Parameter `y` exists only when `x` is negative.
            y = trial.suggest_float("y", -5, 5)
            return x**2 + y
        else:
            return x**2

    @property
    def directions(self) -> list[optuna.study.StudyDirection]:
        return [optuna.study.StudyDirection.MINIMIZE]

    @property
    def search_space(self) -> dict[str, optuna.distributions.BaseDistribution]:
        # You can implement this property as you like, or leave it unimplemented (``BaseProblem`` provides this default behavior).
        raise NotImplementedError

    def evaluate(self, params: dict[str, float]) -> float:
        # You can implement this method as you like, or leave it unimplemented (``BaseProblem`` provides this default behavior).
        raise NotImplementedError

当搜索空间是动态的时,search_spaceevaluate 的实现并非易事。然而,由于 __call__(self, trial: optuna.Trial) 内部不必依赖 evaluate 方法和 search_space 属性,它们的实现取决于用户。如果可能,您可以提供它们的实现,但这并非使您的基准问题起作用的必要条件。请注意,如果您不实现它们,调用它们将导致 NotImplementedError

然后,您可以像往常一样使用 Optuna 优化问题。

dynamic_problem = DynamicProblem()
study = optuna.create_study(directions=dynamic_problem.directions)
study.optimize(dynamic_problem, n_trials=20)

实现带约束的问题

在这里,我们来实现一个带约束的问题。为了实现带约束的问题,除了继承 BaseProblem 类之外,还需要继承 ConstrainedMixin 类,并实现 evaluate_constraints 方法。evaluate_constraints 方法根据输入的参数字典评估约束函数,并返回一个约束值列表。然后,ConstrainedMixin 在内部为 Optuna 采样器定义了 constraints_func 方法。

class ConstrainedProblem(ConstrainedMixin, DynamicProblem):
    def evaluate_constraints(self, params: dict[str, float]) -> tuple[float, float]:
        x = params["x"]
        c0 = x - 2
        if "y" not in params:
            c1 = 0.0  # c1 <= 0, so c1 is satisfied in this case.
            return c0, c1
        else:
            y = params["y"]
            c1 = x + y - 3
            return c0, c1

然后,您可以像往常一样使用 Optuna 优化问题。请不要忘记将 constraints_func 参数设置为要使用的采样器。

problem = ConstrainedProblem()
sampler = optuna.samplers.TPESampler(
    constraints_func=problem.constraints_func
)  # Pass the constraints_func to the sampler.
study = optuna.create_study(sampler=sampler, directions=problem.directions)
study.optimize(problem, n_trials=20)
/opt/hostedtoolcache/Python/3.11.12/x64/lib/python3.11/site-packages/optuna/_experimental.py:31: ExperimentalWarning:

Argument ``constraints_func`` is an experimental feature. The interface can change in the future.

实现您自己的基准问题后,您可以将其注册到 OptunaHub。关于如何将您的基准问题注册到 OptunaHub,请参阅 如何将您的包注册到 OptunaHub

脚本总运行时间: (0 分 0.086 秒)

画廊由 Sphinx-Gallery 生成