Skip to content

Commit 7209049

Browse files
add init randomsearch
1 parent 9072c72 commit 7209049

4 files changed

Lines changed: 206 additions & 51 deletions

File tree

GPopt/GPOpt.py

Lines changed: 150 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
from sklearn.gaussian_process import GaussianProcessRegressor
2121
from sklearn.ensemble import RandomForestRegressor
2222
from sklearn.gaussian_process.kernels import Matern
23+
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
24+
2325
import scipy.stats as st
2426
from joblib import Parallel, delayed
2527
from time import time
@@ -302,12 +304,25 @@ def close_shelve(self):
302304

303305
# fit predict
304306
def surrogate_fit_predict(
305-
self, X_train, y_train, X_test, return_std=False, return_pi=False
307+
self, X_train, y_train, X_test, return_std=False, return_pi=False,
308+
param_search_init_design=False, param_distributions=None, **kwargs
306309
):
307310

308311
if len(X_train.shape) == 1:
309312
X_train = X_train.reshape((-1, 1))
310313
X_test = X_test.reshape((-1, 1))
314+
315+
if X_train.shape[0] <= self.n_init and param_search_init_design == True: # on initial design
316+
try:
317+
rs_obj = RandomizedSearchCV(self.surrogate_obj,
318+
param_distributions=param_distributions,
319+
random_state=42,
320+
cv=3,
321+
**kwargs)
322+
rs_obj.fit(X_train, y_train)
323+
self.surrogate_obj = rs_obj.best_estimator_
324+
except Exception as e:
325+
print(str(e))
311326

312327
# Get mean and standard deviation (+ lower and upper for not GPs)
313328
assert (
@@ -458,6 +473,8 @@ def optimize(
458473
ucb_tol=None,
459474
min_budget=50, # minimum budget for early stopping
460475
func_args=None,
476+
param_search_init_design=False,
477+
param_distributions=None
461478
):
462479
"""Launch optimization loop.
463480
@@ -482,7 +499,17 @@ def optimize(
482499
minimum number of iterations before early stopping controlled by `abs_tol`
483500
484501
func_args: a list;
485-
additional parameters for the objective function (if necessary)
502+
additional parameters for the objective function (if necessary)
503+
504+
param_search_init_design: a boolean;
505+
whether random search tuning must occur on the initial design or not
506+
507+
param_distributions: dict or list of dicts;
508+
Dictionary with parameters names (str) as keys and distributions or lists of
509+
parameters to try. Distributions must provide a rvs method for sampling
510+
(such as those from scipy.stats.distributions). If a list is given, it
511+
is sampled uniformly. If a list of dicts is given, first a dict is sampled
512+
uniformly, and then a parameter is sampled using that dict as above.
486513
487514
see also [Bayesian Optimization with GPopt](https://thierrymoudiki.github.io/blog/2021/04/16/python/misc/gpopt)
488515
and [Hyperparameters tuning with GPopt](https://thierrymoudiki.github.io/blog/2021/06/11/python/misc/hyperparam-tuning-gpopt)
@@ -601,64 +628,138 @@ def optimize(
601628

602629
# current gp mean and std on initial design
603630
# /!\ if GP
604-
if self.method == "bayesian":
605-
self.posterior_ = "gaussian"
606-
try:
607-
y_mean, y_std = self.surrogate_fit_predict(
631+
if param_search_init_design == False:
632+
633+
if self.method == "bayesian":
634+
self.posterior_ = "gaussian"
635+
try:
636+
y_mean, y_std = self.surrogate_fit_predict(
637+
np.asarray(self.parameters),
638+
np.asarray(self.scores),
639+
self.x_choices,
640+
return_std=True,
641+
return_pi=False,
642+
)
643+
except ValueError: # do not remove this
644+
preds_with_std = self.surrogate_fit_predict(
645+
np.asarray(self.parameters),
646+
np.asarray(self.scores),
647+
self.x_choices,
648+
return_std=True,
649+
return_pi=False,
650+
)
651+
y_mean, y_std = preds_with_std[0], preds_with_std[1]
652+
self.y_mean = y_mean
653+
self.y_std = np.maximum(2.220446049250313e-16, y_std)
654+
655+
elif self.method == "mc":
656+
657+
self.posterior_ = "mc"
658+
assert self.surrogate_obj.__class__.__name__.startswith(
659+
"CustomRegressor"
660+
) or self.surrogate_obj.__class__.__name__.startswith(
661+
"PredictionInterval"
662+
), "for `method = 'mc'`, the surrogate must be a nnetsauce.CustomRegressor() or nnetsauce.PredictionInterval()"
663+
assert (
664+
self.surrogate_obj.replications is not None
665+
), "for `method = 'mc'`, the surrogate must be a nnetsauce.CustomRegressor() with a number of 'replications' provided"
666+
preds_with_std = self.surrogate_fit_predict(
608667
np.asarray(self.parameters),
609668
np.asarray(self.scores),
610669
self.x_choices,
611-
return_std=True,
612-
return_pi=False,
670+
return_std=False,
671+
return_pi=True,
613672
)
614-
except ValueError: # do not remove this
673+
y_mean, y_std = preds_with_std[0], preds_with_std[1]
674+
self.y_mean = y_mean
675+
self.y_std = np.maximum(2.220446049250313e-16, y_std)
676+
677+
elif self.method == "splitconformal":
678+
self.posterior_ = None
679+
#assert self.surrogate_obj.__class__.__name__.startswith(
680+
# "PredictionInterval"
681+
#), "for `method = 'splitconformal'`, the surrogate must be a nnetsauce.PredictionInterval()"
682+
preds_with_pi = self.surrogate_fit_predict(
683+
np.asarray(self.parameters),
684+
np.asarray(self.scores),
685+
self.x_choices,
686+
return_std=False,
687+
return_pi=True,
688+
)
689+
y_lower = preds_with_pi[1]
690+
self.lower = y_lower
691+
692+
else:
693+
694+
assert param_distributions is not None,\
695+
"When 'param_search_init_design == False', 'param_distributions' must be provided"
696+
697+
if self.method == "bayesian":
698+
self.posterior_ = "gaussian"
699+
try:
700+
y_mean, y_std = self.surrogate_fit_predict(
701+
np.asarray(self.parameters),
702+
np.asarray(self.scores),
703+
self.x_choices,
704+
return_std=True,
705+
return_pi=False,
706+
param_search_init_design=True,
707+
param_distributions=param_distributions
708+
)
709+
except ValueError: # do not remove this
710+
preds_with_std = self.surrogate_fit_predict(
711+
np.asarray(self.parameters),
712+
np.asarray(self.scores),
713+
self.x_choices,
714+
return_std=True,
715+
return_pi=False,
716+
param_search_init_design=True,
717+
param_distributions=param_distributions
718+
)
719+
y_mean, y_std = preds_with_std[0], preds_with_std[1]
720+
self.y_mean = y_mean
721+
self.y_std = np.maximum(2.220446049250313e-16, y_std)
722+
723+
elif self.method == "mc":
724+
725+
self.posterior_ = "mc"
726+
assert self.surrogate_obj.__class__.__name__.startswith(
727+
"CustomRegressor"
728+
) or self.surrogate_obj.__class__.__name__.startswith(
729+
"PredictionInterval"
730+
), "for `method = 'mc'`, the surrogate must be a nnetsauce.CustomRegressor() or nnetsauce.PredictionInterval()"
731+
assert (
732+
self.surrogate_obj.replications is not None
733+
), "for `method = 'mc'`, the surrogate must be a nnetsauce.CustomRegressor() with a number of 'replications' provided"
615734
preds_with_std = self.surrogate_fit_predict(
616735
np.asarray(self.parameters),
617736
np.asarray(self.scores),
618737
self.x_choices,
619-
return_std=True,
620-
return_pi=False,
738+
return_std=False,
739+
return_pi=True,
740+
param_search_init_design=True,
741+
param_distributions=param_distributions
621742
)
622743
y_mean, y_std = preds_with_std[0], preds_with_std[1]
623-
self.y_mean = y_mean
624-
self.y_std = np.maximum(2.220446049250313e-16, y_std)
744+
self.y_mean = y_mean
745+
self.y_std = np.maximum(2.220446049250313e-16, y_std)
625746

626-
627-
elif self.method == "mc":
628-
self.posterior_ = "mc"
629-
assert self.surrogate_obj.__class__.__name__.startswith(
630-
"CustomRegressor"
631-
) or self.surrogate_obj.__class__.__name__.startswith(
632-
"PredictionInterval"
633-
), "for `method = 'mc'`, the surrogate must be a nnetsauce.CustomRegressor() or nnetsauce.PredictionInterval()"
634-
assert (
635-
self.surrogate_obj.replications is not None
636-
), "for `method = 'mc'`, the surrogate must be a nnetsauce.CustomRegressor() with a number of 'replications' provided"
637-
preds_with_std = self.surrogate_fit_predict(
638-
np.asarray(self.parameters),
639-
np.asarray(self.scores),
640-
self.x_choices,
641-
return_std=False,
642-
return_pi=True,
643-
)
644-
y_mean, y_std = preds_with_std[0], preds_with_std[1]
645-
self.y_mean = y_mean
646-
self.y_std = np.maximum(2.220446049250313e-16, y_std)
647-
648-
elif self.method == "splitconformal":
649-
self.posterior_ = None
650-
#assert self.surrogate_obj.__class__.__name__.startswith(
651-
# "PredictionInterval"
652-
#), "for `method = 'splitconformal'`, the surrogate must be a nnetsauce.PredictionInterval()"
653-
preds_with_pi = self.surrogate_fit_predict(
654-
np.asarray(self.parameters),
655-
np.asarray(self.scores),
656-
self.x_choices,
657-
return_std=False,
658-
return_pi=True,
659-
)
660-
y_lower = preds_with_pi[1]
661-
self.lower = y_lower
747+
elif self.method == "splitconformal":
748+
self.posterior_ = None
749+
#assert self.surrogate_obj.__class__.__name__.startswith(
750+
# "PredictionInterval"
751+
#), "for `method = 'splitconformal'`, the surrogate must be a nnetsauce.PredictionInterval()"
752+
preds_with_pi = self.surrogate_fit_predict(
753+
np.asarray(self.parameters),
754+
np.asarray(self.scores),
755+
self.x_choices,
756+
return_std=False,
757+
return_pi=True,
758+
param_search_init_design=True,
759+
param_distributions=param_distributions
760+
)
761+
y_lower = preds_with_pi[1]
762+
self.lower = y_lower
662763

663764
# saving after initial design computation
664765
if self.save is not None:

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ dist: clean ## builds source and wheel package
7575
ls -l dist
7676

7777
install: clean ## install the package to the active Python's site-packages
78-
python3 -m pip install .
78+
uv pip install -e .
7979

8080
build-site: docs ## export mkdocs website to a folder
8181
cp -rf gpopt-docs/* ../../Pro_Website/Techtonique.github.io/GPopt
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import os
2+
import GPopt as gp
3+
import nnetsauce as ns
4+
import numpy as np
5+
from os import chdir
6+
from scipy.optimize import minimize
7+
from sklearn.linear_model import RidgeCV
8+
from scipy.stats import randint, uniform
9+
10+
print(f"\n ----- Running: {os.path.basename(__file__)}... ----- \n")
11+
12+
# hart6D
13+
def hart6(xx):
14+
alpha = np.array([1.0, 1.2, 3.0, 3.2])
15+
16+
A = np.array([10, 3, 17, 3.5, 1.7, 8,
17+
0.05, 10, 17, 0.1, 8, 14,
18+
3, 3.5, 1.7, 10, 17, 8,
19+
17, 8, 0.05, 10, 0.1, 14]).reshape(4, 6)
20+
21+
P = 1e-4 * np.array([1312, 1696, 5569, 124, 8283, 5886,
22+
2329, 4135, 8307, 3736, 1004, 9991,
23+
2348, 1451, 3522, 2883, 3047, 6650,
24+
4047, 8828, 8732, 5743, 1091, 381]).reshape(4, 6)
25+
26+
xxmat = np.tile(xx,4).reshape(4, 6)
27+
28+
inner = np.sum(A*(xxmat-P)**2, axis = 1)
29+
outer = np.sum(alpha * np.exp(-inner))
30+
31+
return(-outer)
32+
33+
34+
gp_opt2 = gp.GPOpt(lower_bound = np.repeat(0, 6),
35+
upper_bound = np.repeat(1, 6),
36+
objective_func=hart6,
37+
n_choices=25000,
38+
n_init=20,
39+
n_iter=280,
40+
seed=4327,
41+
acquisition="ucb",
42+
method="splitconformal",
43+
surrogate_obj=ns.CustomRegressor(obj=RidgeCV())
44+
)
45+
46+
gp_opt2.optimize(verbose=2, abs_tol=1e-4,
47+
param_search_init_design=True,
48+
param_distributions={'n_hidden_features': randint(3, 50),
49+
'dropout': uniform(0, 0.4)})
50+
51+
print(gp_opt2.surrogate_obj)
52+
53+
print(gp_opt2.surrogate_obj.get_params())
54+

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from codecs import open
44
from os import path
55

6-
__version__ = "0.8.2"
6+
__version__ = "0.9.0"
77

88
subprocess.call("pip install -r requirements.txt", shell=True)
99

0 commit comments

Comments
 (0)