physbo 2.0.0__cp310-cp310-macosx_12_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- physbo/__init__.py +17 -0
- physbo/blm/__init__.py +17 -0
- physbo/blm/basis/__init__.py +8 -0
- physbo/blm/basis/fourier.py +148 -0
- physbo/blm/core/__init__.py +8 -0
- physbo/blm/core/model.py +257 -0
- physbo/blm/inf/__init__.py +8 -0
- physbo/blm/inf/exact.py +192 -0
- physbo/blm/lik/__init__.py +10 -0
- physbo/blm/lik/_src/__init__.py +8 -0
- physbo/blm/lik/_src/cov.py +113 -0
- physbo/blm/lik/gauss.py +136 -0
- physbo/blm/lik/linear.py +117 -0
- physbo/blm/predictor.py +238 -0
- physbo/blm/prior/__init__.py +8 -0
- physbo/blm/prior/gauss.py +215 -0
- physbo/gp/__init__.py +15 -0
- physbo/gp/core/__init__.py +11 -0
- physbo/gp/core/learning.py +364 -0
- physbo/gp/core/model.py +420 -0
- physbo/gp/core/prior.py +207 -0
- physbo/gp/cov/__init__.py +8 -0
- physbo/gp/cov/_src/__init__.py +1 -0
- physbo/gp/cov/_src/enhance_gauss.cpython-310-darwin.so +0 -0
- physbo/gp/cov/gauss.py +393 -0
- physbo/gp/inf/__init__.py +8 -0
- physbo/gp/inf/exact.py +231 -0
- physbo/gp/lik/__init__.py +8 -0
- physbo/gp/lik/gauss.py +179 -0
- physbo/gp/mean/__init__.py +9 -0
- physbo/gp/mean/const.py +150 -0
- physbo/gp/mean/zero.py +66 -0
- physbo/gp/predictor.py +170 -0
- physbo/misc/__init__.py +15 -0
- physbo/misc/_src/__init__.py +1 -0
- physbo/misc/_src/cholupdate.cpython-310-darwin.so +0 -0
- physbo/misc/_src/diagAB.cpython-310-darwin.so +0 -0
- physbo/misc/_src/logsumexp.cpython-310-darwin.so +0 -0
- physbo/misc/_src/traceAB.cpython-310-darwin.so +0 -0
- physbo/misc/centering.py +28 -0
- physbo/misc/gauss_elim.py +35 -0
- physbo/misc/set_config.py +299 -0
- physbo/opt/__init__.py +8 -0
- physbo/opt/adam.py +107 -0
- physbo/predictor.py +261 -0
- physbo/search/__init__.py +11 -0
- physbo/search/discrete/__init__.py +11 -0
- physbo/search/discrete/policy.py +804 -0
- physbo/search/discrete/results.py +192 -0
- physbo/search/discrete_multi/__init__.py +11 -0
- physbo/search/discrete_multi/policy.py +552 -0
- physbo/search/discrete_multi/results.py +128 -0
- physbo/search/pareto.py +206 -0
- physbo/search/score.py +155 -0
- physbo/search/score_multi.py +197 -0
- physbo/search/utility.py +101 -0
- physbo/variable.py +222 -0
- physbo-2.0.0.dist-info/METADATA +110 -0
- physbo-2.0.0.dist-info/RECORD +61 -0
- physbo-2.0.0.dist-info/WHEEL +5 -0
- physbo-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
# Copyright (C) 2020- The University of Tokyo
|
|
3
|
+
#
|
|
4
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import copy
|
|
10
|
+
import pickle as pickle
|
|
11
|
+
import time
|
|
12
|
+
|
|
13
|
+
from .results import history
|
|
14
|
+
from .. import discrete
|
|
15
|
+
from .. import utility
|
|
16
|
+
from .. import score_multi as search_score
|
|
17
|
+
from ...gp import predictor as gp_predictor
|
|
18
|
+
from ...blm import predictor as blm_predictor
|
|
19
|
+
from ...misc import set_config
|
|
20
|
+
from ...variable import variable
|
|
21
|
+
|
|
22
|
+
from typing import List, Optional
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class policy(discrete.policy):
|
|
26
|
+
new_data_list: List[Optional[variable]]
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self, test_X, num_objectives, comm=None, config=None, initial_data=None
|
|
30
|
+
):
|
|
31
|
+
self.num_objectives = num_objectives
|
|
32
|
+
self.history = history(num_objectives=self.num_objectives)
|
|
33
|
+
|
|
34
|
+
self.training_list = [variable() for _ in range(self.num_objectives)]
|
|
35
|
+
self.predictor_list = [None for _ in range(self.num_objectives)]
|
|
36
|
+
self.test_list = [
|
|
37
|
+
self._make_variable_X(test_X) for _ in range(self.num_objectives)
|
|
38
|
+
]
|
|
39
|
+
self.new_data_list = [None for _ in range(self.num_objectives)]
|
|
40
|
+
|
|
41
|
+
self.actions = np.arange(0, test_X.shape[0])
|
|
42
|
+
if config is None:
|
|
43
|
+
self.config = set_config()
|
|
44
|
+
else:
|
|
45
|
+
self.config = config
|
|
46
|
+
|
|
47
|
+
self.TS_candidate_num = None
|
|
48
|
+
|
|
49
|
+
if initial_data is not None:
|
|
50
|
+
if len(initial_data) != 2:
|
|
51
|
+
msg = "ERROR: initial_data should be 2-elements tuple or list (actions and objectives)"
|
|
52
|
+
raise RuntimeError(msg)
|
|
53
|
+
actions, fs = initial_data
|
|
54
|
+
if fs.shape[1] != self.num_objectives:
|
|
55
|
+
msg = "ERROR: initial_data[1].shape[1] != num_objectives"
|
|
56
|
+
raise RuntimeError(msg)
|
|
57
|
+
if len(actions) != fs.shape[0]:
|
|
58
|
+
msg = "ERROR: len(initial_data[0]) != initial_data[1].shape[0]"
|
|
59
|
+
raise RuntimeError(msg)
|
|
60
|
+
self.write(actions, fs)
|
|
61
|
+
self.actions = sorted(list(set(self.actions) - set(actions)))
|
|
62
|
+
|
|
63
|
+
if comm is None:
|
|
64
|
+
self.mpicomm = None
|
|
65
|
+
self.mpisize = 1
|
|
66
|
+
self.mpirank = 0
|
|
67
|
+
else:
|
|
68
|
+
self.mpicomm = comm
|
|
69
|
+
self.mpisize = comm.size
|
|
70
|
+
self.mpirank = comm.rank
|
|
71
|
+
self.actions = np.array_split(self.actions, self.mpisize)[self.mpirank]
|
|
72
|
+
|
|
73
|
+
def write(
|
|
74
|
+
self,
|
|
75
|
+
action,
|
|
76
|
+
t,
|
|
77
|
+
X=None,
|
|
78
|
+
time_total=None,
|
|
79
|
+
time_update_predictor=None,
|
|
80
|
+
time_get_action=None,
|
|
81
|
+
time_run_simulator=None,
|
|
82
|
+
):
|
|
83
|
+
self.history.write(
|
|
84
|
+
t,
|
|
85
|
+
action,
|
|
86
|
+
time_total=time_total,
|
|
87
|
+
time_update_predictor=time_update_predictor,
|
|
88
|
+
time_get_action=time_get_action,
|
|
89
|
+
time_run_simulator=time_run_simulator,
|
|
90
|
+
)
|
|
91
|
+
action = np.array(action)
|
|
92
|
+
t = np.array(t)
|
|
93
|
+
|
|
94
|
+
for i in range(self.num_objectives):
|
|
95
|
+
test = self.test_list[i]
|
|
96
|
+
predictor = self.predictor_list[i]
|
|
97
|
+
|
|
98
|
+
if X is None:
|
|
99
|
+
X = test.X[action, :]
|
|
100
|
+
Z = test.Z[action, :] if test.Z is not None else None
|
|
101
|
+
else:
|
|
102
|
+
Z = predictor.get_basis(X) if predictor is not None else None
|
|
103
|
+
|
|
104
|
+
if self.new_data_list[i] is None:
|
|
105
|
+
self.new_data_list[i] = variable(X, t[:, i], Z)
|
|
106
|
+
else:
|
|
107
|
+
self.new_data_list[i].add(X=X, t=t[:, i], Z=Z)
|
|
108
|
+
self.training_list[i].add(X=X, t=t[:, i], Z=Z)
|
|
109
|
+
local_index = np.searchsorted(self.actions, action)
|
|
110
|
+
local_index = local_index[
|
|
111
|
+
np.take(self.actions, local_index, mode="clip") == action
|
|
112
|
+
]
|
|
113
|
+
self.actions = self._delete_actions(local_index)
|
|
114
|
+
|
|
115
|
+
def _model(self, i):
|
|
116
|
+
training = self.training_list[i]
|
|
117
|
+
predictor = self.predictor_list[i]
|
|
118
|
+
test = self.test_list[i]
|
|
119
|
+
new_data = self.new_data_list[i]
|
|
120
|
+
return {
|
|
121
|
+
"training": training,
|
|
122
|
+
"predictor": predictor,
|
|
123
|
+
"test": test,
|
|
124
|
+
"new_data": new_data,
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
def random_search(
|
|
128
|
+
self,
|
|
129
|
+
max_num_probes,
|
|
130
|
+
num_search_each_probe=1,
|
|
131
|
+
simulator=None,
|
|
132
|
+
is_disp=True,
|
|
133
|
+
disp_pareto_set=False,
|
|
134
|
+
):
|
|
135
|
+
if self.mpirank != 0:
|
|
136
|
+
is_disp = False
|
|
137
|
+
|
|
138
|
+
N = int(num_search_each_probe)
|
|
139
|
+
|
|
140
|
+
if is_disp:
|
|
141
|
+
utility.show_interactive_mode(simulator, self.history)
|
|
142
|
+
|
|
143
|
+
for n in range(0, max_num_probes):
|
|
144
|
+
time_total = time.time()
|
|
145
|
+
if is_disp and N > 1:
|
|
146
|
+
utility.show_start_message_multi_search(
|
|
147
|
+
self.history.num_runs, score="random"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
time_get_action = time.time()
|
|
151
|
+
action = self._get_random_action(N)
|
|
152
|
+
time_get_action = time.time() - time_get_action
|
|
153
|
+
|
|
154
|
+
if simulator is None:
|
|
155
|
+
return action
|
|
156
|
+
|
|
157
|
+
time_run_simulator = time.time()
|
|
158
|
+
t = _run_simulator(simulator, action, self.mpicomm)
|
|
159
|
+
time_run_simulator = time.time() - time_run_simulator
|
|
160
|
+
|
|
161
|
+
time_total = time.time() - time_total
|
|
162
|
+
self.write(
|
|
163
|
+
action,
|
|
164
|
+
t,
|
|
165
|
+
time_total=[time_total] * N,
|
|
166
|
+
time_update_predictor=np.zeros(N, dtype=float),
|
|
167
|
+
time_get_action=[time_get_action] * N,
|
|
168
|
+
time_run_simulator=[time_run_simulator] * N,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if is_disp:
|
|
172
|
+
utility.show_search_results_mo(
|
|
173
|
+
self.history, N, disp_pareto_set=disp_pareto_set
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
return copy.deepcopy(self.history)
|
|
177
|
+
|
|
178
|
+
def bayes_search(
|
|
179
|
+
self,
|
|
180
|
+
training_list=None,
|
|
181
|
+
max_num_probes=None,
|
|
182
|
+
num_search_each_probe=1,
|
|
183
|
+
predictor_list=None,
|
|
184
|
+
is_disp=True,
|
|
185
|
+
disp_pareto_set=False,
|
|
186
|
+
simulator=None,
|
|
187
|
+
score="HVPI",
|
|
188
|
+
interval=0,
|
|
189
|
+
num_rand_basis=0,
|
|
190
|
+
):
|
|
191
|
+
if self.mpirank != 0:
|
|
192
|
+
is_disp = False
|
|
193
|
+
|
|
194
|
+
old_disp = self.config.learning.is_disp
|
|
195
|
+
self.config.learning.is_disp = is_disp
|
|
196
|
+
|
|
197
|
+
if max_num_probes is None:
|
|
198
|
+
max_num_probes = 1
|
|
199
|
+
simulator = None
|
|
200
|
+
|
|
201
|
+
is_rand_expans = False if num_rand_basis == 0 else True
|
|
202
|
+
|
|
203
|
+
if training_list is not None:
|
|
204
|
+
self.training_list = training_list
|
|
205
|
+
|
|
206
|
+
if predictor_list is None:
|
|
207
|
+
if is_rand_expans:
|
|
208
|
+
self.predictor_list = [
|
|
209
|
+
blm_predictor(self.config) for i in range(self.num_objectives)
|
|
210
|
+
]
|
|
211
|
+
else:
|
|
212
|
+
self.predictor_list = [
|
|
213
|
+
gp_predictor(self.config) for i in range(self.num_objectives)
|
|
214
|
+
]
|
|
215
|
+
else:
|
|
216
|
+
self.predictor_list = predictor_list
|
|
217
|
+
|
|
218
|
+
if max_num_probes == 0 and interval >= 0:
|
|
219
|
+
self._learn_hyperparameter(num_rand_basis)
|
|
220
|
+
|
|
221
|
+
N = int(num_search_each_probe)
|
|
222
|
+
|
|
223
|
+
for n in range(max_num_probes):
|
|
224
|
+
time_total = time.time()
|
|
225
|
+
time_update_predictor = time.time()
|
|
226
|
+
if utility.is_learning(n, interval):
|
|
227
|
+
self._learn_hyperparameter(num_rand_basis)
|
|
228
|
+
else:
|
|
229
|
+
self._update_predictor()
|
|
230
|
+
time_update_predictor = time.time() - time_update_predictor
|
|
231
|
+
|
|
232
|
+
if num_search_each_probe != 1:
|
|
233
|
+
utility.show_start_message_multi_search(self.history.num_runs, score)
|
|
234
|
+
|
|
235
|
+
time_get_action = time.time()
|
|
236
|
+
K = self.config.search.multi_probe_num_sampling
|
|
237
|
+
alpha = self.config.search.alpha
|
|
238
|
+
action = self._get_actions(score, N, K, alpha)
|
|
239
|
+
time_get_action = time.time() - time_get_action
|
|
240
|
+
|
|
241
|
+
N_indeed = len(action)
|
|
242
|
+
if N_indeed == 0:
|
|
243
|
+
if self.mpirank == 0:
|
|
244
|
+
print("WARNING: All actions have already searched.")
|
|
245
|
+
self.config.learning.is_disp = old_disp
|
|
246
|
+
return copy.deepcopy(self.history)
|
|
247
|
+
|
|
248
|
+
if simulator is None:
|
|
249
|
+
self.config.learning.is_disp = old_disp
|
|
250
|
+
return action
|
|
251
|
+
|
|
252
|
+
time_run_simulator = time.time()
|
|
253
|
+
t = _run_simulator(simulator, action, self.mpicomm)
|
|
254
|
+
time_run_simulator = time.time() - time_run_simulator
|
|
255
|
+
|
|
256
|
+
time_total = time.time() - time_total
|
|
257
|
+
self.write(
|
|
258
|
+
action,
|
|
259
|
+
t,
|
|
260
|
+
time_total=[time_total] * N_indeed,
|
|
261
|
+
time_update_predictor=[time_update_predictor] * N_indeed,
|
|
262
|
+
time_get_action=[time_get_action] * N_indeed,
|
|
263
|
+
time_run_simulator=[time_run_simulator] * N_indeed,
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
if is_disp:
|
|
267
|
+
utility.show_search_results_mo(
|
|
268
|
+
self.history, N, disp_pareto_set=disp_pareto_set
|
|
269
|
+
)
|
|
270
|
+
self._update_predictor()
|
|
271
|
+
self.config.learning.is_disp = old_disp
|
|
272
|
+
return copy.deepcopy(self.history)
|
|
273
|
+
|
|
274
|
+
def _get_actions(self, mode, N, K, alpha):
|
|
275
|
+
f = self.get_score(mode=mode, alpha=alpha, parallel=False)
|
|
276
|
+
champion, local_champion, local_index = self._find_champion(f)
|
|
277
|
+
if champion == -1:
|
|
278
|
+
return np.zeros(0, dtype=int)
|
|
279
|
+
if champion == local_champion:
|
|
280
|
+
self.actions = self._delete_actions(local_index)
|
|
281
|
+
|
|
282
|
+
chosen_actions = [champion]
|
|
283
|
+
for n in range(1, N):
|
|
284
|
+
f = self._get_marginal_score(mode, chosen_actions[0:n], K, alpha)
|
|
285
|
+
champion, local_champion, local_index = self._find_champion(f)
|
|
286
|
+
if champion == -1:
|
|
287
|
+
break
|
|
288
|
+
if champion == local_champion:
|
|
289
|
+
self.actions = self._delete_actions(local_index)
|
|
290
|
+
chosen_actions.append(champion)
|
|
291
|
+
return np.array(chosen_actions)
|
|
292
|
+
|
|
293
|
+
def get_post_fmean(self, xs):
|
|
294
|
+
if self.predictor_list == [None] * self.num_objectives:
|
|
295
|
+
self._warn_no_predictor("get_post_fmean()")
|
|
296
|
+
predictor_list = []
|
|
297
|
+
for i in range(self.num_objectives):
|
|
298
|
+
predictor = gp_predictor(self.config)
|
|
299
|
+
predictor.fit(self.training_list[i], 0)
|
|
300
|
+
predictor.prepare(self.training_list[i])
|
|
301
|
+
predictor_list.append(predictor)
|
|
302
|
+
else:
|
|
303
|
+
self._update_predictor()
|
|
304
|
+
predictor_list = self.predictor_list[:]
|
|
305
|
+
X = self._make_variable_X(xs)
|
|
306
|
+
fmean = [
|
|
307
|
+
predictor.get_post_fmean(training, X)
|
|
308
|
+
for predictor, training in zip(predictor_list, self.training_list)
|
|
309
|
+
]
|
|
310
|
+
return np.array(fmean).T
|
|
311
|
+
|
|
312
|
+
def get_post_fcov(self, xs):
|
|
313
|
+
if self.predictor_list == [None] * self.num_objectives:
|
|
314
|
+
self._warn_no_predictor("get_post_fcov()")
|
|
315
|
+
predictor_list = []
|
|
316
|
+
for i in range(self.num_objectives):
|
|
317
|
+
predictor = gp_predictor(self.config)
|
|
318
|
+
predictor.fit(self.training_list[i], 0)
|
|
319
|
+
predictor.prepare(self.training_list[i])
|
|
320
|
+
predictor_list.append(predictor)
|
|
321
|
+
else:
|
|
322
|
+
self._update_predictor()
|
|
323
|
+
predictor_list = self.predictor_list[:]
|
|
324
|
+
X = self._make_variable_X(xs)
|
|
325
|
+
fcov = [
|
|
326
|
+
predictor.get_post_fcov(training, X)
|
|
327
|
+
for predictor, training in zip(predictor_list, self.training_list)
|
|
328
|
+
]
|
|
329
|
+
return np.array(fcov).T
|
|
330
|
+
|
|
331
|
+
def get_score(
|
|
332
|
+
self,
|
|
333
|
+
mode,
|
|
334
|
+
actions=None,
|
|
335
|
+
xs=None,
|
|
336
|
+
predictor_list=None,
|
|
337
|
+
training_list=None,
|
|
338
|
+
pareto=None,
|
|
339
|
+
parallel=True,
|
|
340
|
+
alpha=1,
|
|
341
|
+
):
|
|
342
|
+
if training_list is None:
|
|
343
|
+
training_list = self.training_list
|
|
344
|
+
if pareto is None:
|
|
345
|
+
pareto = self.history.pareto
|
|
346
|
+
|
|
347
|
+
if training_list[0].X is None or training_list[0].X.shape[0] == 0:
|
|
348
|
+
msg = "ERROR: No training data is registered."
|
|
349
|
+
raise RuntimeError(msg)
|
|
350
|
+
|
|
351
|
+
if predictor_list is None:
|
|
352
|
+
if self.predictor_list == [None] * self.num_objectives:
|
|
353
|
+
self._warn_no_predictor("get_score()")
|
|
354
|
+
predictor_list = []
|
|
355
|
+
for i in range(self.num_objectives):
|
|
356
|
+
predictor = gp_predictor(self.config)
|
|
357
|
+
predictor.fit(training_list[i], 0)
|
|
358
|
+
predictor.prepare(training_list[i])
|
|
359
|
+
predictor_list.append(predictor)
|
|
360
|
+
else:
|
|
361
|
+
self._update_predictor()
|
|
362
|
+
predictor_list = self.predictor_list
|
|
363
|
+
|
|
364
|
+
if xs is not None:
|
|
365
|
+
if actions is not None:
|
|
366
|
+
raise RuntimeError("ERROR: both actions and xs are given")
|
|
367
|
+
if isinstance(xs, variable):
|
|
368
|
+
test = xs
|
|
369
|
+
else:
|
|
370
|
+
test = variable(X=xs)
|
|
371
|
+
if parallel and self.mpisize > 1:
|
|
372
|
+
actions = np.array_split(np.arange(test.X.shape[0]), self.mpisize)
|
|
373
|
+
test = test.get_subset(actions[self.mpirank])
|
|
374
|
+
else:
|
|
375
|
+
if actions is None:
|
|
376
|
+
actions = self.actions
|
|
377
|
+
else:
|
|
378
|
+
if isinstance(actions, int):
|
|
379
|
+
actions = [actions]
|
|
380
|
+
if parallel and self.mpisize > 1:
|
|
381
|
+
actions = np.array_split(actions, self.mpisize)[self.mpirank]
|
|
382
|
+
test = self.test_list[0].get_subset(actions)
|
|
383
|
+
|
|
384
|
+
f = search_score.score(
|
|
385
|
+
mode,
|
|
386
|
+
predictor_list=predictor_list,
|
|
387
|
+
training_list=training_list,
|
|
388
|
+
test=test,
|
|
389
|
+
pareto=pareto,
|
|
390
|
+
reduced_candidate_num=self.TS_candidate_num,
|
|
391
|
+
alpha=alpha,
|
|
392
|
+
)
|
|
393
|
+
if parallel and self.mpisize > 1:
|
|
394
|
+
fs = self.mpicomm.allgather(f)
|
|
395
|
+
f = np.hstack(fs)
|
|
396
|
+
return f
|
|
397
|
+
|
|
398
|
+
def _get_marginal_score(self, mode, chosen_actions, K, alpha):
|
|
399
|
+
"""
|
|
400
|
+
Getting marginal scores.
|
|
401
|
+
|
|
402
|
+
Parameters
|
|
403
|
+
----------
|
|
404
|
+
mode: str
|
|
405
|
+
The type of aquision funciton.
|
|
406
|
+
TS (Thompson Sampling), EI (Expected Improvement) and PI (Probability of Improvement) are available.
|
|
407
|
+
These functions are defined in score.py.
|
|
408
|
+
chosen_actions: numpy.ndarray
|
|
409
|
+
Array of selected actions.
|
|
410
|
+
K: int
|
|
411
|
+
The total number of search candidates.
|
|
412
|
+
alpha: float
|
|
413
|
+
not used.
|
|
414
|
+
|
|
415
|
+
Returns
|
|
416
|
+
-------
|
|
417
|
+
f: list
|
|
418
|
+
N dimensional scores (score is defined in each mode)
|
|
419
|
+
"""
|
|
420
|
+
f = np.zeros((K, len(self.actions)), dtype=float)
|
|
421
|
+
|
|
422
|
+
# draw K samples of the values of objective function of chosen actions
|
|
423
|
+
new_test_list = [variable() for _ in range(self.num_objectives)]
|
|
424
|
+
virtual_t_list = [np.zeros((K, 0)) for _ in range(self.num_objectives)]
|
|
425
|
+
for i in range(self.num_objectives):
|
|
426
|
+
new_test_local = self.test_list[i].get_subset(chosen_actions)
|
|
427
|
+
virtual_t_local = self.predictor_list[i].get_predict_samples(
|
|
428
|
+
self.training_list[i], new_test_local, K
|
|
429
|
+
)
|
|
430
|
+
if self.mpisize == 1:
|
|
431
|
+
new_test_list[i] = new_test_local
|
|
432
|
+
virtual_t_list[i] = virtual_t_local
|
|
433
|
+
else:
|
|
434
|
+
for nt in self.mpicomm.allgather(new_test_local):
|
|
435
|
+
new_test_list[i].add(X=nt.X, t=nt.t, Z=nt.Z)
|
|
436
|
+
virtual_t_list[i] = np.concatenate(
|
|
437
|
+
self.mpicomm.allgather(virtual_t_local), axis=1
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
for k in range(K):
|
|
441
|
+
predictor_list = [copy.deepcopy(p) for p in self.predictor_list]
|
|
442
|
+
training_list = [copy.deepcopy(t) for t in self.training_list]
|
|
443
|
+
|
|
444
|
+
for i in range(self.num_objectives):
|
|
445
|
+
virtual_train = new_test_list[i]
|
|
446
|
+
virtual_train.t = virtual_t_list[i][k, :]
|
|
447
|
+
|
|
448
|
+
if virtual_train.Z is None:
|
|
449
|
+
training_list[i].add(virtual_train.X, virtual_train.t)
|
|
450
|
+
else:
|
|
451
|
+
training_list[i].add(
|
|
452
|
+
virtual_train.X, virtual_train.t, virtual_train.Z
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
predictor_list[i].update(training_list[i], virtual_train)
|
|
456
|
+
|
|
457
|
+
f[k, :] = self.get_score(
|
|
458
|
+
mode,
|
|
459
|
+
predictor_list=predictor_list,
|
|
460
|
+
training_list=training_list,
|
|
461
|
+
parallel=False,
|
|
462
|
+
)
|
|
463
|
+
return np.mean(f, axis=0)
|
|
464
|
+
|
|
465
|
+
def save(self, file_history, file_training_list=None, file_predictor_list=None):
|
|
466
|
+
if self.mpirank == 0:
|
|
467
|
+
self.history.save(file_history)
|
|
468
|
+
if file_training_list is not None:
|
|
469
|
+
self.save_training_list(file_training_list)
|
|
470
|
+
if file_predictor_list is not None:
|
|
471
|
+
self.save_predictor_list(file_predictor_list)
|
|
472
|
+
|
|
473
|
+
def load(self, file_history, file_training_list=None, file_predictor_list=None):
|
|
474
|
+
self.history.load(file_history)
|
|
475
|
+
|
|
476
|
+
if file_training_list is None:
|
|
477
|
+
N = self.history.total_num_search
|
|
478
|
+
X = self.test_list[0].X[self.history.chosen_actions[0:N], :]
|
|
479
|
+
t = self.history.fx[0:N]
|
|
480
|
+
self.training_list = [
|
|
481
|
+
variable(X=X, t=t[:, i]) for i in range(self.num_objectives)
|
|
482
|
+
]
|
|
483
|
+
else:
|
|
484
|
+
self.load_training_list(file_training_list)
|
|
485
|
+
|
|
486
|
+
if file_predictor_list is not None:
|
|
487
|
+
self.load_predictor_list(file_predictor_list)
|
|
488
|
+
|
|
489
|
+
N = self.history.total_num_search
|
|
490
|
+
self.actions = self._delete_actions(self.history.chosen_actions[:N])
|
|
491
|
+
|
|
492
|
+
def save_predictor_list(self, file_name):
|
|
493
|
+
with open(file_name, "wb") as f:
|
|
494
|
+
pickle.dump(self.predictor_list, f, 2)
|
|
495
|
+
|
|
496
|
+
def save_training_list(self, file_name):
|
|
497
|
+
obj = [
|
|
498
|
+
{"X": training.X, "t": training.t, "Z": training.Z}
|
|
499
|
+
for training in self.training_list
|
|
500
|
+
]
|
|
501
|
+
with open(file_name, "wb") as f:
|
|
502
|
+
pickle.dump(obj, f, 2)
|
|
503
|
+
|
|
504
|
+
def load_predictor_list(self, file_name):
|
|
505
|
+
with open(file_name, "rb") as f:
|
|
506
|
+
self.predictor_list = pickle.load(f)
|
|
507
|
+
|
|
508
|
+
def load_training_list(self, file_name):
|
|
509
|
+
with open(file_name, "rb") as f:
|
|
510
|
+
data_list = pickle.load(f)
|
|
511
|
+
|
|
512
|
+
self.training_list = [variable() for i in range(self.num_objectives)]
|
|
513
|
+
for data, training in zip(data_list, self.training_list):
|
|
514
|
+
training.X = data["X"]
|
|
515
|
+
training.t = data["t"]
|
|
516
|
+
training.Z = data["Z"]
|
|
517
|
+
|
|
518
|
+
def _learn_hyperparameter(self, num_rand_basis):
|
|
519
|
+
for i in range(self.num_objectives):
|
|
520
|
+
m = self._model(i)
|
|
521
|
+
predictor = m["predictor"]
|
|
522
|
+
training = m["training"]
|
|
523
|
+
test = m["test"]
|
|
524
|
+
|
|
525
|
+
predictor.fit(training, num_rand_basis)
|
|
526
|
+
test.Z = predictor.get_basis(test.X)
|
|
527
|
+
training.Z = predictor.get_basis(training.X)
|
|
528
|
+
predictor.prepare(training)
|
|
529
|
+
self.new_data_list[i] = None
|
|
530
|
+
# self.predictor_list[i].fit(self.training_list[i], num_rand_basis)
|
|
531
|
+
# self.test_list[i].Z = self.predictor_list[i].get_basis(self.test_list[i].X)
|
|
532
|
+
# self.training_list[i].Z = self.predictor_list[i].get_basis(self.training_list[i].X)
|
|
533
|
+
# self.predictor_list[i].prepare(self.training_list[i])
|
|
534
|
+
# self.new_data_list[i] = None
|
|
535
|
+
|
|
536
|
+
def _update_predictor(self):
|
|
537
|
+
for i in range(self.num_objectives):
|
|
538
|
+
if self.new_data_list[i] is not None:
|
|
539
|
+
self.predictor_list[i].update(
|
|
540
|
+
self.training_list[i], self.new_data_list[i]
|
|
541
|
+
)
|
|
542
|
+
self.new_data_list[i] = None
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
def _run_simulator(simulator, action, comm=None):
|
|
546
|
+
if comm is None:
|
|
547
|
+
return simulator(action)
|
|
548
|
+
if comm.rank == 0:
|
|
549
|
+
t = simulator(action)
|
|
550
|
+
else:
|
|
551
|
+
t = 0.0
|
|
552
|
+
return comm.bcast(t, root=0)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
# Copyright (C) 2020- The University of Tokyo
|
|
3
|
+
#
|
|
4
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
5
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
6
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import pickle
|
|
10
|
+
import copy
|
|
11
|
+
|
|
12
|
+
from .. import pareto
|
|
13
|
+
|
|
14
|
+
MAX_SEARCH = int(30000)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class history(object):
|
|
18
|
+
def __init__(self, num_objectives):
|
|
19
|
+
self.num_objectives = num_objectives
|
|
20
|
+
self.pareto = pareto.Pareto(num_objectives=self.num_objectives)
|
|
21
|
+
|
|
22
|
+
self.num_runs = int(0)
|
|
23
|
+
self.total_num_search = int(0)
|
|
24
|
+
self.fx = np.zeros((MAX_SEARCH, self.num_objectives), dtype=float)
|
|
25
|
+
self.chosen_actions = np.zeros(MAX_SEARCH, dtype=int)
|
|
26
|
+
self.terminal_num_run = np.zeros(MAX_SEARCH, dtype=int)
|
|
27
|
+
|
|
28
|
+
self._time_total = np.zeros(MAX_SEARCH, dtype=float)
|
|
29
|
+
self._time_update_predictor = np.zeros(MAX_SEARCH, dtype=float)
|
|
30
|
+
self._time_get_action = np.zeros(MAX_SEARCH, dtype=float)
|
|
31
|
+
self._time_run_simulator = np.zeros(MAX_SEARCH, dtype=float)
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def time_total(self):
|
|
35
|
+
return copy.copy(self._time_total[0 : self.num_runs])
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def time_update_predictor(self):
|
|
39
|
+
return copy.copy(self._time_update_predictor[0 : self.num_runs])
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def time_get_action(self):
|
|
43
|
+
return copy.copy(self._time_get_action[0 : self.num_runs])
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def time_run_simulator(self):
|
|
47
|
+
return copy.copy(self._time_run_simulator[0 : self.num_runs])
|
|
48
|
+
|
|
49
|
+
def write(
|
|
50
|
+
self,
|
|
51
|
+
t,
|
|
52
|
+
action,
|
|
53
|
+
time_total=None,
|
|
54
|
+
time_update_predictor=None,
|
|
55
|
+
time_get_action=None,
|
|
56
|
+
time_run_simulator=None,
|
|
57
|
+
):
|
|
58
|
+
t = np.array(t)
|
|
59
|
+
action = np.array(action)
|
|
60
|
+
|
|
61
|
+
if t.ndim == 1:
|
|
62
|
+
N = 1
|
|
63
|
+
if len(t) != self.num_objectives:
|
|
64
|
+
raise ValueError("t does not match the number of objectives")
|
|
65
|
+
else:
|
|
66
|
+
N = t.shape[0]
|
|
67
|
+
if t.shape[1] != self.num_objectives:
|
|
68
|
+
raise ValueError("t does not match the number of objectives")
|
|
69
|
+
|
|
70
|
+
st = self.total_num_search
|
|
71
|
+
en = st + N
|
|
72
|
+
|
|
73
|
+
self.terminal_num_run[self.num_runs] = en
|
|
74
|
+
self.fx[st:en] = t
|
|
75
|
+
self.chosen_actions[st:en] = action
|
|
76
|
+
self.num_runs += 1
|
|
77
|
+
self.total_num_search += N
|
|
78
|
+
|
|
79
|
+
# update Pareto set
|
|
80
|
+
self.pareto.update_front(t)
|
|
81
|
+
|
|
82
|
+
if time_total is None:
|
|
83
|
+
time_total = np.zeros(N, dtype=float)
|
|
84
|
+
self._time_total[st:en] = time_total
|
|
85
|
+
|
|
86
|
+
if time_update_predictor is None:
|
|
87
|
+
time_update_predictor = np.zeros(N, dtype=float)
|
|
88
|
+
self._time_update_predictor[st:en] = time_update_predictor
|
|
89
|
+
|
|
90
|
+
if time_get_action is None:
|
|
91
|
+
time_get_action = np.zeros(N, dtype=float)
|
|
92
|
+
self._time_get_action[st:en] = time_get_action
|
|
93
|
+
|
|
94
|
+
if time_run_simulator is None:
|
|
95
|
+
time_run_simulator = np.zeros(N, dtype=float)
|
|
96
|
+
self._time_run_simulator[st:en] = time_run_simulator
|
|
97
|
+
|
|
98
|
+
def export_pareto_front(self):
|
|
99
|
+
return self.pareto.export_front()
|
|
100
|
+
|
|
101
|
+
def save(self, filename):
|
|
102
|
+
N = self.total_num_search
|
|
103
|
+
M = self.num_runs
|
|
104
|
+
|
|
105
|
+
obj = {
|
|
106
|
+
"num_runs": M,
|
|
107
|
+
"total_num_search": N,
|
|
108
|
+
"fx": self.fx[0:N],
|
|
109
|
+
"chosen_actions": self.chosen_actions[0:N],
|
|
110
|
+
"terminal_num_run": self.terminal_num_run[0:M],
|
|
111
|
+
"pareto": self.pareto,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
with open(filename, "wb") as f:
|
|
115
|
+
pickle.dump(obj, f)
|
|
116
|
+
|
|
117
|
+
def load(self, filename):
|
|
118
|
+
with open(filename, "rb") as f:
|
|
119
|
+
data = pickle.load(f)
|
|
120
|
+
|
|
121
|
+
M = data["num_runs"]
|
|
122
|
+
N = data["total_num_search"]
|
|
123
|
+
self.num_runs = M
|
|
124
|
+
self.total_num_search = N
|
|
125
|
+
self.fx[0:N] = data["fx"]
|
|
126
|
+
self.chosen_actions[0:N] = data["chosen_actions"]
|
|
127
|
+
self.terminal_num_run[0:M] = data["terminal_num_run"]
|
|
128
|
+
self.pareto = data["pareto"]
|