Completed
Push — master ( fc102b...eeab31 )
by Simon
02:49
created

hyperactive.base_optimizer.BaseOptimizer.predict()   A

Complexity

Conditions 1

Size

Total Lines 12
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 12
rs 10
c 0
b 0
f 0
cc 1
nop 2
1
# Author: Simon Blanke
2
# Email: [email protected]
3
# License: MIT License
4
5
6
import numpy as np
7
import multiprocessing
8
9
from functools import partial
10
11
from .base_positioner import BasePositioner
12
from .sub_packages import MetaLearn
13
from .util import initialize_search, finish_search_, sort_for_best
14
15
16
class BaseOptimizer:
17
    def __init__(self, _config_, _arg_):
18
19
        """
20
21
        Parameters
22
        ----------
23
24
        search_config: dict
25
            A dictionary providing the model and hyperparameter search space for the
26
            optimization process.
27
        n_iter: int
28
            The number of iterations the optimizer performs.
29
        metric: string, optional (default: "accuracy")
30
            The metric the model is evaluated by.
31
        n_jobs: int, optional (default: 1)
32
            The number of searches to run in parallel.
33
        cv: int, optional (default: 3)
34
            The number of folds for the cross validation.
35
        verbosity: int, optional (default: 1)
36
            Verbosity level. 1 prints out warm_start points and their scores.
37
        random_state: int, optional (default: None)
38
            Sets the random seed.
39
        warm_start: dict, optional (default: False)
40
            Dictionary that definies a start point for the optimizer.
41
        memory: bool, optional (default: True)
42
            A memory, that saves the evaluation during the optimization to save time when
43
            optimizer returns to position.
44
        scatter_init: int, optional (default: False)
45
            Defines the number n of random positions that should be evaluated with 1/n the
46
            training data, to find a better initial position.
47
48
        Returns
49
        -------
50
        None
51
52
        """
53
54
        self._config_ = _config_
55
        self._arg_ = _arg_
56
57
        if self._config_.warnings:
58
            print("Warning: Since v0.5.0, this API is no longer supported.")
59
            print("Please use the new hyperactive API in the following link:")
60
            print("https://github.com/SimonBlanke/Hyperactive#how-to-use-hyperactive")
61
62
        if self._config_.meta_learn:
63
            self._meta_ = MetaLearn(self._config_.search_config)
64
65
        self.search_config = self._config_.search_config
66
        self.n_iter = self._config_.n_iter
67
68
        if self._config_.get_search_path:
69
            self.pos_list = []
70
            self.score_list = []
71
72
    def _hill_climb_iteration(self, _cand_, _p_, X, y):
73
        _p_.pos_new = _p_.move_climb(_cand_, _p_.pos_current)
74
        _p_.score_new = _cand_.eval_pos(_p_.pos_new, X, y)
75
76
        if _p_.score_new > _cand_.score_best:
77
            _cand_, _p_ = self._update_pos(_cand_, _p_)
78
79
        return _cand_, _p_
80
81
    def _init_base_positioner(self, _cand_, positioner=None, pos_para={}):
82
        if positioner:
83
            _p_ = positioner(**pos_para)
84
        else:
85
            _p_ = BasePositioner(**pos_para)
86
87
        _p_.pos_current = _cand_.pos_best
88
        _p_.score_current = _cand_.score_best
89
90
        return _p_
91
92
    def _update_pos(self, _cand_, _p_):
93
        _cand_.pos_best = _p_.pos_new
94
        _cand_.score_best = _p_.score_new
95
96
        _p_.pos_current = _p_.pos_new
97
        _p_.score_current = _p_.score_new
98
99
        return _cand_, _p_
100
101
    def search(self, nth_process, X, y):
102
        self._config_, _cand_ = initialize_search(self._config_, nth_process, X, y)
103
        _p_ = self._init_opt_positioner(_cand_, X, y)
104
105
        for i in range(self._config_.n_iter):
106
            _cand_ = self._iterate(i, _cand_, _p_, X, y)
107
            self._config_.update_p_bar(1)
108
109
            if self._config_.get_search_path:
110
                pos_list = []
111
                score_list = []
112
                if isinstance(_p_, list):
113
                    for p in _p_:
114
                        pos_list.append(p.pos_new)
115
                        score_list.append(p.score_new)
116
117
                        pos_list_ = np.array(pos_list)
118
                        score_list_ = np.array(score_list)
119
120
                    self.pos_list.append(pos_list_)
0 ignored issues
show
introduced by
The variable pos_list_ does not seem to be defined for all execution paths.
Loading history...
121
                    self.score_list.append(score_list_)
0 ignored issues
show
introduced by
The variable score_list_ does not seem to be defined for all execution paths.
Loading history...
122
                else:
123
                    pos_list.append(_p_.pos_new)
124
                    score_list.append(_p_.score_new)
125
126
                    pos_list_ = np.array(pos_list)
127
                    score_list_ = np.array(score_list)
128
129
                    self.pos_list.append(pos_list_)
130
                    self.score_list.append(score_list_)
131
132
        _cand_ = finish_search_(self._config_, _cand_, X, y)
133
134
        return _cand_
135
136
    def _search_multiprocessing(self, X, y):
137
        """Wrapper for the parallel search. Passes integer that corresponds to process number"""
138
        pool = multiprocessing.Pool(self._config_.n_jobs)
139
        search = partial(self.search, X=X, y=y)
140
141
        _cand_list = pool.map(search, self._config_._n_process_range)
142
143
        return _cand_list
144
145
    def _run_one_job(self, X, y):
146
        _cand_ = self.search(0, X, y)
147
        if self._config_.meta_learn:
148
            self._meta_.collect(X, y, _cand_list=[_cand_])
149
150
        self.model_best = _cand_.model
151
        self.score_best = _cand_.score_best
152
        start_point = _cand_._get_warm_start()
153
154
        if self._config_.verbosity:
155
            # print("\n", self._config_.metric, self.score_best)
156
            print("start_point =", start_point)
157
158
    def _run_multiple_jobs(self, X, y):
159
        _cand_list = self._search_multiprocessing(X, y)
160
161
        start_point_list = []
162
        score_best_list = []
163
        model_best_list = []
164
        for _cand_ in _cand_list:
165
            model_best = _cand_.model
166
            score_best = _cand_.score_best
167
            start_point = _cand_._get_warm_start()
168
169
            start_point_list.append(start_point)
170
            score_best_list.append(score_best)
171
            model_best_list.append(model_best)
172
173
        start_point_sorted, score_best_sorted = sort_for_best(
174
            start_point_list, score_best_list
175
        )
176
177
        model_best_sorted, score_best_sorted = sort_for_best(
178
            model_best_list, score_best_list
179
        )
180
181
        if self._config_.verbosity:
182
            print("\nList of start points (best first):")
183
            for start_point, score_best in zip(start_point_sorted, score_best_sorted):
184
                # print("\n", self._config_.metric, score_best)
185
                print("start_point =", start_point)
186
187
        self.score_best = score_best_sorted[0]
188
        self.model_best = model_best_sorted[0]
189
190
    def fit(self, X, y):
191
        """Public method for starting the search with the training data (X, y)
192
193
        Parameters
194
        ----------
195
        X : array-like or sparse matrix of shape = [n_samples, n_features]
196
197
        y : array-like, shape = [n_samples] or [n_samples, n_outputs]
198
199
        Returns
200
        -------
201
        None
202
        """
203
        X, y = self._config_._check_data(X, y)
204
205
        # if self._config_.model_type == "keras":
206
        #    self._config_.n_jobs = 1
207
208
        if self._config_.n_jobs == 1:
209
            self._run_one_job(X, y)
210
211
        else:
212
            self._run_multiple_jobs(X, y)
213