注意
跳转至末尾 下载完整的示例代码。
如何在 OptunaHub 中实现您的采样器
OptunaHub 是一个 Optuna 包注册中心,它是一个由贡献者分享算法的平台。本教程介绍了如何在 OptunaHub 中实现您自己的算法。
在这里,我们将展示如何实现您自己的采样器,即优化算法。如果您想实现采样器以外的算法,请参考其他教程。
通常,Optuna 提供 BaseSampler
类来实现您自己的采样器。然而,从头开始实现一个采样器有点复杂。作为替代,在 OptunaHub 中,您可以使用 optunahub.samplers.SimpleBaseSampler 类,它是一个易于扩展的采样器模板。
您需要安装 optuna
来实现您自己的采样器,并安装 optunahub
来使用模板 SimpleBaseSampler
。
$ pip install optuna optunahub
首先,导入 optuna
, optunahub
以及其他必需的模块。
from __future__ import annotations
from typing import Any
import numpy as np
import optuna
import optunahub
接下来,通过继承 SimpleBaseSampler
类来定义您自己的采样器类。在本例中,我们实现一个返回随机值的采样器。
class MySampler(optunahub.samplers.SimpleBaseSampler):
# By default, search space will be estimated automatically like Optuna's built-in samplers.
# You can fix the search spacd by `search_space` argument of `SimpleSampler` class.
def __init__(
self, search_space: dict[str, optuna.distributions.BaseDistribution] | None = None
) -> None:
super().__init__(search_space)
self._rng = np.random.RandomState()
# You need to implement sample_relative method.
# This method returns a dictionary of hyperparameters.
# The keys of the dictionary are the names of the hyperparameters, which must be the same as the keys of the search_space argument.
# The values of the dictionary are the values of the hyperparameters.
# In this example, sample_relative method returns a dictionary of randomly sampled hyperparameters.
def sample_relative(
self,
study: optuna.study.Study,
trial: optuna.trial.FrozenTrial,
search_space: dict[str, optuna.distributions.BaseDistribution],
) -> dict[str, Any]:
# search_space argument must be identical to search_space argument input to __init__ method.
# This method is automatically invoked by Optuna and SimpleBaseSampler.
# If search space is empty, all parameter values are sampled randomly by SimpleBaseSampler.
if search_space == {}:
return {}
params = {} # type: dict[str, Any]
for n, d in search_space.items():
if isinstance(d, optuna.distributions.FloatDistribution):
params[n] = self._rng.uniform(d.low, d.high)
elif isinstance(d, optuna.distributions.IntDistribution):
params[n] = self._rng.randint(d.low, d.high)
elif isinstance(d, optuna.distributions.CategoricalDistribution):
params[n] = d.choices[self._rng.randint(len(d.choices))]
else:
raise NotImplementedError
return params
这里,作为一个示例,目标函数定义如下。
def objective(trial: optuna.trial.Trial) -> float:
x = trial.suggest_float("x", -10, 10)
y = trial.suggest_int("y", -10, 10)
z = trial.suggest_categorical("z", ["a", "b", "c"])
return x**2 + y**2 + {"a": -10, "b": 0, "c": 10}[z] ** 2
该采样器可以像其他 Optuna 采样器一样使用。在以下示例中,我们创建一个研究并使用 MySampler
类对其进行优化。
sampler = MySampler()
study = optuna.create_study(sampler=sampler)
study.optimize(objective, n_trials=100)
最佳参数可以如下获取。
best_params = study.best_params
best_value = study.best_value
print(f"Best params: {best_params}, Best value: {best_value}")
Best params: {'x': -0.08051894464286669, 'y': -1, 'z': 'b'}, Best value: 1.006483300446401
我们可以看到,Optuna 找到的 best_params
值接近最优值 {"x":0, "y": 0, "z": "b"}
。
在上述示例中,搜索空间在第一次试验时被估计,并通过优化动态更新。如果您的采样器要求在优化前固定搜索空间,您可以在初始化时将搜索空间传递给采样器。传递搜索空间还可以让采样器避免估计搜索空间的开销。有关定义搜索空间的 optuna.distributions
的更多信息,请参见 文档。
sampler = MySampler(
search_space={
"x": optuna.distributions.FloatDistribution(-10, 10),
"y": optuna.distributions.IntDistribution(-10, 10),
"z": optuna.distributions.CategoricalDistribution(["a", "b", "c"]),
}
)
study = optuna.create_study(sampler=sampler)
study.optimize(objective, n_trials=100)
在下一个教程中,我们将展示如何将您的采样器注册到 OptunaHub。让我们继续阅读 如何在 OptunaHub 中注册您的包。有关实现采样器的更多信息,请参见 用户自定义采样器文档。
脚本总运行时间: (0 分钟 0.102 秒)