Skip to content

Commit 5d94fe1

Browse files
committed
modAL.models.BayesianOptimizer now keeps track of the argmax and the max val of the known values of the function to be optimized
1 parent f547a8d commit 5d94fe1

File tree

3 files changed

+43
-26
lines changed

3 files changed

+43
-26
lines changed

modAL/acquisition.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def optimizer_PI(optimizer, X, tradeoff=0):
4848
mean, std = optimizer.predict(X, return_std=True)
4949
std = std.reshape(-1, 1)
5050

51-
return PI(mean, std, optimizer.max_val, tradeoff)
51+
return PI(mean, std, optimizer.y_max, tradeoff)
5252

5353

5454
def optimizer_EI(optimizer, X, tradeoff=0):
@@ -74,7 +74,7 @@ def optimizer_EI(optimizer, X, tradeoff=0):
7474
mean, std = optimizer.predict(X, return_std=True)
7575
std = std.reshape(-1, 1)
7676

77-
return EI(mean, std, optimizer.max_val, tradeoff)
77+
return EI(mean, std, optimizer.y_max, tradeoff)
7878

7979

8080
def optimizer_UCB(optimizer, X, beta=1):

modAL/models.py

+18-10
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,10 @@ class BayesianOptimizer(BaseLearner):
402402
If the model has been fitted already: numpy.ndarray containing the
403403
labels corresponding to _training_samples
404404
405+
X_max: None or numpy.ndarray of shape (n_samples, 3)
406+
407+
y_max: -np.inf or float
408+
405409
Examples
406410
--------
407411
>>> import numpy as np
@@ -449,14 +453,19 @@ def __init__(self, *args, **kwargs):
449453
super(BayesianOptimizer, self).__init__(*args, **kwargs)
450454
# setting the maximum value
451455
if self.y_training is not None:
452-
self.max_val = np.max(self.y_training)
456+
max_idx = np.argmax(self.y_training)
457+
self.X_max = self.X_training[max_idx]
458+
self.y_max = self.y_training[max_idx]
453459
else:
454-
self.max_val = -np.inf
460+
self.X_max = None
461+
self.y_max = -np.inf
455462

456-
def _set_max(self, y):
457-
y_max = np.max(y)
458-
if y_max > self.max_val:
459-
self.max_val = y_max
463+
def _set_max(self, X, y):
464+
max_idx = np.argmax(y)
465+
y_max = y[max_idx]
466+
if y_max > self.y_max:
467+
self.y_max = y_max
468+
self.X_max = X[max_idx]
460469

461470
def get_max(self):
462471
"""
@@ -471,9 +480,8 @@ def get_max(self):
471480
The currently best value.
472481
473482
"""
474-
max_idx = np.argmax(self.y_training)
475483

476-
return self.X_training[max_idx], self.y_training[max_idx]
484+
return self.X_max, self.y_max
477485

478486
def teach(self, X, y, bootstrap=False, only_new=False, **fit_kwargs):
479487
"""
@@ -504,10 +512,10 @@ def teach(self, X, y, bootstrap=False, only_new=False, **fit_kwargs):
504512
self._add_training_data(X, y)
505513
if not only_new:
506514
self._fit_to_known(bootstrap=bootstrap, **fit_kwargs)
507-
self._set_max(y)
508515
else:
509516
self._fit_on_new(X, y, bootstrap=bootstrap, **fit_kwargs)
510-
self._set_max(y)
517+
518+
self._set_max(X, y)
511519

512520

513521
class BaseCommittee(ABC, BaseEstimator):

tests/core_tests.py

+23-14
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ def test_optimizer_PI(self):
150150
)
151151

152152
optimizer = modAL.models.BayesianOptimizer(estimator=mock_estimator)
153-
optimizer._set_max([max_val])
153+
optimizer._set_max([0], [max_val])
154154

155155
np.testing.assert_almost_equal(
156156
ndtr((mean - max_val - tradeoff)/std),
@@ -169,10 +169,10 @@ def test_optimizer_EI(self):
169169
)
170170

171171
optimizer = modAL.models.BayesianOptimizer(estimator=mock_estimator)
172-
optimizer._set_max([max_val])
172+
optimizer._set_max([0], [max_val])
173173

174-
true_EI = (mean - optimizer.max_val - tradeoff) * ndtr((mean - optimizer.max_val - tradeoff)/std)\
175-
+ std * norm.pdf((mean - optimizer.max_val - tradeoff)/std)
174+
true_EI = (mean - optimizer.y_max - tradeoff) * ndtr((mean - optimizer.y_max - tradeoff) / std) \
175+
+ std * norm.pdf((mean - optimizer.y_max - tradeoff) / std)
176176

177177
np.testing.assert_almost_equal(
178178
true_EI,
@@ -211,7 +211,7 @@ def test_selection(self):
211211
)
212212

213213
optimizer = modAL.models.BayesianOptimizer(estimator=mock_estimator)
214-
optimizer._set_max([max_val])
214+
optimizer._set_max([0], [max_val])
215215

216216
modAL.acquisition.max_PI(optimizer, X, tradeoff=np.random.rand(), n_instances=n_instances)
217217
modAL.acquisition.max_EI(optimizer, X, tradeoff=np.random.rand(), n_instances=n_instances)
@@ -532,7 +532,7 @@ def test_set_max(self):
532532
# case 1: the estimator is not fitted yet
533533
regressor = mock.MockEstimator()
534534
learner = modAL.models.BayesianOptimizer(estimator=regressor)
535-
self.assertEqual(-np.inf, learner.max_val)
535+
self.assertEqual(-np.inf, learner.y_max)
536536

537537
# case 2: the estimator is fitted already
538538
for n_samples in range(1, 100):
@@ -545,17 +545,20 @@ def test_set_max(self):
545545
estimator=regressor,
546546
X_training=X, y_training=y
547547
)
548-
np.testing.assert_almost_equal(max_val, learner.max_val)
548+
np.testing.assert_almost_equal(max_val, learner.y_max)
549549

550550
def test_set_new_max(self):
551551
for n_reps in range(100):
552552
# case 1: the learner is not fitted yet
553553
for n_samples in range(1, 10):
554+
X = np.random.rand(n_samples, 3)
554555
y = np.random.rand(n_samples)
556+
max_idx = np.argmax(y)
555557
regressor = mock.MockEstimator()
556558
learner = modAL.models.BayesianOptimizer(estimator=regressor)
557-
learner._set_max(y)
558-
self.assertEqual(learner.max_val, np.max(y))
559+
learner._set_max(X, y)
560+
np.testing.assert_equal(learner.X_max, X[max_idx])
561+
np.testing.assert_equal(learner.y_max, y[max_idx])
559562

560563
# case 2: new value is not a maximum
561564
for n_samples in range(1, 10):
@@ -568,10 +571,13 @@ def test_set_new_max(self):
568571
X_training=X, y_training=y
569572
)
570573

574+
X_new = np.random.rand()
571575
y_new = y - np.random.rand()
572-
old_max = learner.max_val
573-
learner._set_max(y_new)
574-
np.testing.assert_almost_equal(old_max, learner.max_val)
576+
X_old_max = learner.X_max
577+
y_old_max = learner.y_max
578+
learner._set_max(X_new, y_new)
579+
np.testing.assert_equal(X_old_max, learner.X_max)
580+
np.testing.assert_equal(y_old_max, learner.y_max)
575581

576582
# case 3: new value is a maximum
577583
for n_samples in range(1, 10):
@@ -584,9 +590,12 @@ def test_set_new_max(self):
584590
X_training=X, y_training=y
585591
)
586592

593+
X_new = np.random.rand(n_samples, 2)
587594
y_new = y + np.random.rand()
588-
learner._set_max(y_new)
589-
np.testing.assert_almost_equal(np.max(y_new), learner.max_val)
595+
max_idx = np.argmax(y_new)
596+
learner._set_max(X_new, y_new)
597+
np.testing.assert_equal(X_new[max_idx], learner.X_max)
598+
np.testing.assert_equal(y_new[max_idx], learner.y_max)
590599

591600
def test_get_max(self):
592601
for n_samples in range(1, 100):

0 commit comments

Comments
 (0)