From 4e031585b2d90b290d6bcd1dca5ccd50547a448a Mon Sep 17 00:00:00 2001 From: Contramundum Date: Thu, 14 Sep 2023 13:40:19 +0900 Subject: [PATCH 1/2] Support all-categorical cases --- optuna_dashboard/preferential/samplers/gp.py | 42 +++++++++++++++----- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/optuna_dashboard/preferential/samplers/gp.py b/optuna_dashboard/preferential/samplers/gp.py index 8349b1a4..349da03a 100644 --- a/optuna_dashboard/preferential/samplers/gp.py +++ b/optuna_dashboard/preferential/samplers/gp.py @@ -3,6 +3,7 @@ from __future__ import annotations import math from typing import Any from typing import Callable +from typing import cast import botorch.acquisition.analytic import botorch.models.model @@ -16,6 +17,8 @@ import optuna import optuna._transform import torch from torch import Tensor +from optuna.distributions import CategoricalDistribution +import itertools from .._system_attrs import get_preferences @@ -310,7 +313,7 @@ class PreferentialGPSampler(optuna.samplers.BaseSampler): search_space: dict[str, optuna.distributions.BaseDistribution], ) -> dict[str, Any]: preferences = get_preferences(study.system_attrs) - if len(preferences) == 0: + if len(preferences) == 0 or len(search_space) == 0: return {} trials = study.get_trials(deepcopy=False) @@ -355,16 +358,33 @@ class PreferentialGPSampler(optuna.samplers.BaseSampler): best_f=torch.max(sampled_gp.posterior(params[:, None, :]).mean), ) - # TODO: Make it possible to apply it on categorical variables - candidates, _ = botorch.optim.optimize_acqf( - acq_function=acqf, - bounds=torch.from_numpy(trans.bounds.T), - q=1, - num_restarts=10, - raw_samples=512, - options={"batch_limit": 5, "maxiter": 200}, - sequential=True, - ) + # TODO: Make it possible to apply it on mixed search space + if all(isinstance(dist, CategoricalDistribution) for dist in search_space.values()): + all_param_combinations = itertools.product( + *[ + [(name, choice) for choice in cast(CategoricalDistribution, dist).choices] + for name, dist in search_space.items() + ] + ) + choices = torch.tensor( + np.array([trans.transform(dict(params)) for params in all_param_combinations]), + dtype=torch.float64, + ) + candidates, _ = botorch.optim.optimize_acqf_discrete( + acq_function=acqf, + choices=choices, + q=1, + ) + else: + candidates, _ = botorch.optim.optimize_acqf( + acq_function=acqf, + bounds=torch.from_numpy(trans.bounds.T), + q=1, + num_restarts=10, + raw_samples=512, + options={"batch_limit": 5, "maxiter": 200}, + sequential=True, + ) next_x = trans.untransform(candidates[0].detach().numpy()) return next_x From b95f13e9fe9dc857bddf489666d8aea97374a8c1 Mon Sep 17 00:00:00 2001 From: Contramundum Date: Thu, 14 Sep 2023 13:45:22 +0900 Subject: [PATCH 2/2] format --- optuna_dashboard/preferential/samplers/gp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/optuna_dashboard/preferential/samplers/gp.py b/optuna_dashboard/preferential/samplers/gp.py index 349da03a..d023e741 100644 --- a/optuna_dashboard/preferential/samplers/gp.py +++ b/optuna_dashboard/preferential/samplers/gp.py @@ -1,5 +1,6 @@ from __future__ import annotations +import itertools import math from typing import Any from typing import Callable @@ -15,10 +16,9 @@ from gpytorch.likelihoods.gaussian_likelihood import Prior import numpy as np import optuna import optuna._transform +from optuna.distributions import CategoricalDistribution import torch from torch import Tensor -from optuna.distributions import CategoricalDistribution -import itertools from .._system_attrs import get_preferences