99from sklearn .model_selection import ParameterSampler
1010
1111from hyperactive .base import BaseOptimizer
12+ from hyperactive .opt ._common import _score_params
13+ from hyperactive .utils .parallel import parallelize
1214
1315
1416class RandomSearchSk (BaseOptimizer ):
@@ -19,12 +21,56 @@ class RandomSearchSk(BaseOptimizer):
1921 param_distributions : dict[str, list | scipy.stats.rv_frozen]
2022 Search space specification. Discrete lists are sampled uniformly;
2123 scipy distribution objects are sampled via their ``rvs`` method.
24+
2225 n_iter : int, default=10
2326 Number of parameter sets to evaluate.
27+
2428 random_state : int | np.random.RandomState | None, default=None
2529 Controls the pseudo-random generator for reproducibility.
30+
2631 error_score : float, default=np.nan
2732 Score assigned when the experiment raises an exception.
33+
34+ backend : {"dask", "loky", "multiprocessing", "threading","ray"}, by default "None".
35+ Runs parallel evaluate if specified and ``strategy`` is set as "refit".
36+
37+ - "None": executes loop sequentally, simple list comprehension
38+ - "loky", "multiprocessing" and "threading": uses ``joblib.Parallel`` loops
39+ - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark``
40+ - "dask": uses ``dask``, requires ``dask`` package in environment
41+ - "ray": uses ``ray``, requires ``ray`` package in environment
42+
43+ Recommendation: Use "dask" or "loky" for parallel evaluate.
44+ "threading" is unlikely to see speed ups due to the GIL and the serialization
45+ backend (``cloudpickle``) for "dask" and "loky" is generally more robust
46+ than the standard ``pickle`` library used in "multiprocessing".
47+
48+ backend_params : dict, optional
49+ additional parameters passed to the backend as config.
50+ Directly passed to ``utils.parallel.parallelize``.
51+ Valid keys depend on the value of ``backend``:
52+
53+ - "None": no additional parameters, ``backend_params`` is ignored
54+ - "loky", "multiprocessing" and "threading": default ``joblib`` backends
55+ any valid keys for ``joblib.Parallel`` can be passed here, e.g., ``n_jobs``,
56+ with the exception of ``backend`` which is directly controlled by ``backend``.
57+ If ``n_jobs`` is not passed, it will default to ``-1``, other parameters
58+ will default to ``joblib`` defaults.
59+ - "joblib": custom and 3rd party ``joblib`` backends, e.g., ``spark``.
60+ any valid keys for ``joblib.Parallel`` can be passed here, e.g., ``n_jobs``,
61+ ``backend`` must be passed as a key of ``backend_params`` in this case.
62+ If ``n_jobs`` is not passed, it will default to ``-1``, other parameters
63+ will default to ``joblib`` defaults.
64+ - "dask": any valid keys for ``dask.compute`` can be passed, e.g., ``scheduler``
65+
66+ - "ray": The following keys can be passed:
67+
68+ - "ray_remote_args": dictionary of valid keys for ``ray.init``
69+ - "shutdown_ray": bool, default=True; False prevents ``ray`` from shutting
70+ down after parallelization.
71+ - "logger_name": str, default="ray"; name of the logger to use.
72+ - "mute_warnings": bool, default=False; if True, suppresses warnings
73+
2874 experiment : BaseExperiment, optional
2975 Callable returning a scalar score when invoked with keyword
3076 arguments matching a parameter set.
@@ -45,13 +91,17 @@ def __init__(
4591 n_iter = 10 ,
4692 random_state = None ,
4793 error_score = np .nan ,
94+ backend = "None" ,
95+ backend_params = None ,
4896 experiment = None ,
4997 ):
5098 self .experiment = experiment
5199 self .param_distributions = param_distributions
52100 self .n_iter = n_iter
53101 self .random_state = random_state
54102 self .error_score = error_score
103+ self .backend = backend
104+ self .backend_params = backend_params
55105
56106 super ().__init__ ()
57107
@@ -104,13 +154,18 @@ def _run(
104154 )
105155 candidate_params = list (sampler )
106156
107- scores : list [float ] = []
108- for candidate_param in candidate_params :
109- try :
110- score = experiment (** candidate_param )
111- except Exception : # noqa: B904
112- score = error_score
113- scores .append (score )
157+ meta = {
158+ "experiment" : experiment ,
159+ "error_score" : error_score ,
160+ }
161+
162+ scores = parallelize (
163+ fun = _score_params ,
164+ iter = candidate_params ,
165+ meta = meta ,
166+ backend = self .backend ,
167+ backend_params = self .backend_params ,
168+ )
114169
115170 best_index = int (np .argmin (scores )) # lower-is-better convention
116171 best_params = candidate_params [best_index ]
@@ -154,4 +209,16 @@ def get_test_params(cls, parameter_set: str = "default"):
154209 "random_state" : 0 ,
155210 }
156211
157- return [params_sklearn , params_ackley ]
212+ params = [params_sklearn , params_ackley ]
213+
214+ from hyperactive .utils .parallel import _get_parallel_test_fixtures
215+
216+ parallel_fixtures = _get_parallel_test_fixtures ()
217+
218+ for k , v in parallel_fixtures .items ():
219+ new_ackley = params_ackley .copy ()
220+ new_ackley ["backend" ] = k
221+ new_ackley ["backend_params" ] = v
222+ params .append (new_ackley )
223+
224+ return params
0 commit comments