Passed
Push — master ( c241e4...b050e9 )
by Simon
01:57
created

CmaEsOptimizer.get_test_params()   A

Complexity

Conditions 1

Size

Total Lines 59
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 36
dl 0
loc 59
rs 9.016
c 0
b 0
f 0
cc 1
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
"""CMA-ES (Covariance Matrix Adaptation Evolution Strategy) optimizer."""
2
# copyright: hyperactive developers, MIT License (see LICENSE file)
3
4
from .._adapters._base_optuna_adapter import _BaseOptunaAdapter
5
6
7
class CmaEsOptimizer(_BaseOptunaAdapter):
8
    """CMA-ES (Covariance Matrix Adaptation Evolution Strategy) optimizer.
9
10
    Parameters
11
    ----------
12
    param_space : dict[str, tuple or list or optuna distributions]
13
        The search space to explore. Dictionary with parameter names
14
        as keys and either tuples/lists of (low, high) or
15
        optuna distribution objects as values.
16
    n_trials : int, default=100
17
        Number of optimization trials.
18
    initialize : dict[str, int], default=None
19
        The method to generate initial positions. A dictionary with
20
        the following key literals and the corresponding value type:
21
        {"grid": int, "vertices": int, "random": int, "warm_start": list[dict]}
22
    random_state : None, int, default=None
23
        If None, create a new random state. If int, create a new random state
24
        seeded with the value.
25
    early_stopping : int, default=None
26
        Number of trials after which to stop if no improvement.
27
    max_score : float, default=None
28
        Maximum score threshold. Stop optimization when reached.
29
    x0 : dict, default=None
30
        Initial parameter values for CMA-ES.
31
    sigma0 : float, default=1.0
32
        Initial standard deviation for CMA-ES.
33
    n_startup_trials : int, default=1
34
        Number of startup trials for CMA-ES.
35
    experiment : BaseExperiment, optional
36
        The experiment to optimize parameters for.
37
        Optional, can be passed later via ``set_params``.
38
39
    Examples
40
    --------
41
    Basic usage of CmaEsOptimizer with a scikit-learn experiment:
42
43
    >>> from hyperactive.experiment.integrations import SklearnCvExperiment
44
    >>> from hyperactive.opt.optuna import CmaEsOptimizer
45
    >>> from sklearn.datasets import load_iris
46
    >>> from sklearn.svm import SVC
47
    >>> X, y = load_iris(return_X_y=True)
48
    >>> sklearn_exp = SklearnCvExperiment(estimator=SVC(), X=X, y=y)
49
    >>> param_space = {
50
    ...     "C": (0.01, 10),
51
    ...     "gamma": (0.0001, 10),
52
    ... }
53
    >>> optimizer = CmaEsOptimizer(
54
    ...     param_space=param_space, n_trials=50, experiment=sklearn_exp
55
    ... )
56
    >>> best_params = optimizer.run()
57
    """
58
59
    _tags = {
60
        "info:name": "CMA-ES Optimizer",
61
        "info:local_vs_global": "global",
62
        "info:explore_vs_exploit": "mixed",
63
        "info:compute": "high",
64
        "python_dependencies": ["optuna", "cmaes"],
65
    }
66
67
    def __init__(
68
        self,
69
        param_space=None,
70
        n_trials=100,
71
        initialize=None,
72
        random_state=None,
73
        early_stopping=None,
74
        max_score=None,
75
        x0=None,
76
        sigma0=1.0,
77
        n_startup_trials=1,
78
        experiment=None,
79
    ):
80
        self.x0 = x0
81
        self.sigma0 = sigma0
82
        self.n_startup_trials = n_startup_trials
83
84
        super().__init__(
85
            param_space=param_space,
86
            n_trials=n_trials,
87
            initialize=initialize,
88
            random_state=random_state,
89
            early_stopping=early_stopping,
90
            max_score=max_score,
91
            experiment=experiment,
92
        )
93
94
    def _get_optimizer(self):
95
        """Get the CMA-ES optimizer.
96
97
        Returns
98
        -------
99
        optimizer
100
            The Optuna CmaEsOptimizer instance
101
        """
102
        import optuna
103
104
        try:
105
            import cmaes  # noqa: F401
106
        except ImportError:
107
            raise ImportError(
108
                "CmaEsOptimizer requires the 'cmaes' package. "
109
                "Install it with: pip install cmaes"
110
            )
111
112
        optimizer_kwargs = {
113
            "sigma0": self.sigma0,
114
            "n_startup_trials": self.n_startup_trials,
115
        }
116
117
        if self.x0 is not None:
118
            optimizer_kwargs["x0"] = self.x0
119
120
        if self.random_state is not None:
121
            optimizer_kwargs["seed"] = self.random_state
122
123
        return optuna.samplers.CmaEsSampler(**optimizer_kwargs)
124
125
    @classmethod
126
    def get_test_params(cls, parameter_set="default"):
127
        """Return testing parameter settings for the optimizer."""
128
        from sklearn.datasets import make_regression
129
        from sklearn.neural_network import MLPRegressor
130
131
        from hyperactive.experiment.integrations import SklearnCvExperiment
132
133
        # Test case 1: Basic continuous parameters (from base)
134
        params = super().get_test_params(parameter_set)
135
        params[0].update(
136
            {
137
                "sigma0": 0.5,
138
                "n_startup_trials": 1,
139
            }
140
        )
141
142
        # Test case 2: Neural network with continuous parameters only
143
        # (CMA-ES specific - only continuous parameters allowed)
144
        X, y = make_regression(n_samples=50, n_features=5, noise=0.1, random_state=42)
145
        mlp_exp = SklearnCvExperiment(
146
            estimator=MLPRegressor(random_state=42, max_iter=100), X=X, y=y, cv=3
147
        )
148
149
        continuous_param_space = {
150
            "alpha": (1e-5, 1e-1),  # L2 regularization (continuous)
151
            "learning_rate_init": (1e-4, 1e-1),  # Learning rate (continuous)
152
            "beta_1": (0.8, 0.99),  # Adam beta1 (continuous)
153
            "beta_2": (0.9, 0.999),  # Adam beta2 (continuous)
154
            # Note: No categorical parameters - CMA-ES doesn't support them
155
        }
156
157
        params.append(
158
            {
159
                "param_space": continuous_param_space,
160
                "n_trials": 8,  # Smaller for faster testing
161
                "experiment": mlp_exp,
162
                "sigma0": 0.3,  # Different sigma for diversity
163
                "n_startup_trials": 2,  # More startup trials
164
            }
165
        )
166
167
        # Test case 3: High-dimensional continuous space (CMA-ES strength)
168
        high_dim_continuous = {
169
            f"x{i}": (-1.0, 1.0)
170
            for i in range(6)  # 6D continuous optimization
171
        }
172
173
        params.append(
174
            {
175
                "param_space": high_dim_continuous,
176
                "n_trials": 12,
177
                "experiment": mlp_exp,
178
                "sigma0": 0.7,  # Larger initial spread
179
                "n_startup_trials": 3,
180
            }
181
        )
182
183
        return params
184