Skip to content

Commit 60cc034

Browse files
committed
random search
1 parent b6ee9fb commit 60cc034

3 files changed

Lines changed: 92 additions & 21 deletions

File tree

src/hyperactive/opt/_common.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""This module contains common functions used by multiple optimizers."""
2+
3+
__all__ = ["_score_params"]
4+
5+
6+
def _score_params(params, meta):
7+
"""Function to score parameters, used in parallelization."""
8+
meta = meta.copy()
9+
experiment = meta["experiment"]
10+
error_score = meta["error_score"]
11+
12+
try:
13+
return experiment(**params)
14+
except Exception: # noqa: B904
15+
# Catch all exceptions and assign error_score
16+
return error_score

src/hyperactive/opt/gridsearch/_sk.py

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from sklearn.model_selection import ParameterGrid
99

1010
from hyperactive.base import BaseOptimizer
11+
from hyperactive.opt._common import _score_params
1112
from hyperactive.utils.parallel import parallelize
1213

1314

@@ -235,16 +236,3 @@ def get_test_params(cls, parameter_set="default"):
235236
params.append(new_ackley)
236237

237238
return params
238-
239-
240-
def _score_params(params, meta):
241-
"""Function to score parameters, used in parallelization."""
242-
meta = meta.copy()
243-
experiment = meta["experiment"]
244-
error_score = meta["error_score"]
245-
246-
try:
247-
return experiment(**params)
248-
except Exception: # noqa: B904
249-
# Catch all exceptions and assign error_score
250-
return error_score

src/hyperactive/opt/random_search.py

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from sklearn.model_selection import ParameterSampler
1010

1111
from hyperactive.base import BaseOptimizer
12+
from hyperactive.opt._common import _score_params
13+
from hyperactive.utils.parallel import parallelize
1214

1315

1416
class 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

Comments
 (0)