2020from sklearn .gaussian_process import GaussianProcessRegressor
2121from sklearn .ensemble import RandomForestRegressor
2222from sklearn .gaussian_process .kernels import Matern
23+ from sklearn .model_selection import GridSearchCV , RandomizedSearchCV
24+
2325import scipy .stats as st
2426from joblib import Parallel , delayed
2527from 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 :
0 commit comments