Skip to content

Commit e06d57e

Browse files
added comparative examples for BOLFI with GPy and BOLFI with GPyTorch
1 parent b516a97 commit e06d57e

File tree

3 files changed

+636
-1
lines changed

3 files changed

+636
-1
lines changed
+314
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
import elfi
2+
import matplotlib
3+
import matplotlib.pyplot as plt
4+
import numpy as np
5+
import scipy.stats as ss
6+
7+
from elfi import BOLFI
8+
from matplotlib.animation import FuncAnimation, FFMpegWriter
9+
10+
seed = 0
11+
12+
# Number of minimum samples.
13+
n_low = 1
14+
# Number of maximum samples.
15+
n = 5
16+
np.random.seed(seed)
17+
gauss_samples = ss.norm().rvs(size=n)
18+
"""
19+
t_plus_range = [0.36, 0.44]
20+
t_plus = np.linspace(*t_plus_range, 200)
21+
model = lambda t_plus: t_plus**2
22+
x_range = [0.36, 0.44]
23+
y_range = [-0.8, 1.5]
24+
canvas = np.meshgrid(np.linspace(*x_range, 200),
25+
np.linspace(*reversed(y_range), 200))
26+
t_plus_samples = t_plus_range.copy()
27+
28+
fit_spline = []
29+
fit_spline_uncertainty = []
30+
fit_acq = []
31+
fit_discrepancy = []
32+
fit_acq_t_plus = []
33+
34+
prior = elfi.Prior('norm', 0.4, 0.02**2, name='t_+')
35+
elfi_simulator = elfi.Simulator(
36+
lambda *args, **_: model(args[0]) + ss.norm().rvs(size=1)[0],
37+
prior, observed=model(0.415)
38+
)
39+
processed_data = elfi.Summary(lambda data: data, elfi_simulator)
40+
distance = elfi.Distance('euclidean', processed_data)
41+
log_distance = elfi.Operation(np.log, distance)
42+
bolfi = elfi.BOLFI(
43+
log_distance, initial_evidence=10, bounds={'t_+': t_plus_range}, seed=seed
44+
)
45+
for i in range(20):
46+
bolfi.fit(n_evidence=10 + i + 1, bar=True)
47+
#plt.plot(t_plus, bolfi.target_model.predict(t_plus, noiseless=True)[0])
48+
#plt.show()
49+
"""
50+
51+
t_plus_range = [0.36, 0.44]
52+
t_plus = np.linspace(*t_plus_range, 200)
53+
54+
55+
def model(t_plus):
56+
return t_plus**2
57+
58+
59+
x_range = [0.358, 0.442]
60+
t_plus_eval = np.linspace(*x_range, 200)
61+
y_range = [-0.012, 0.052]
62+
canvas = np.meshgrid(np.linspace(*x_range, 200),
63+
np.linspace(*reversed(y_range), 200))
64+
t_plus_samples = t_plus_range.copy()
65+
66+
fit_spline = []
67+
fit_spline_uncertainty = []
68+
fit_acq = []
69+
fit_discrepancy = []
70+
fit_acq_t_plus = []
71+
72+
prior = elfi.Prior('norm', 0.4, 0.02, name='t_+')
73+
elfi_simulator = elfi.Simulator(
74+
lambda *args, **_: model(args[0]) + 0.001 * ss.norm().rvs(size=1)[0],
75+
prior, observed=model(0.415)
76+
)
77+
processed_data = elfi.Summary(lambda data: data, elfi_simulator)
78+
distance = elfi.Distance('euclidean', processed_data)
79+
# log_distance = elfi.Operation(np.log, distance)
80+
81+
82+
class Animate_GP:
83+
def __init__(self, fig, ax, initial_evidence=0, frames=None):
84+
self.bolfi = elfi.BOLFI(
85+
distance,
86+
initial_evidence=initial_evidence,
87+
bounds={'t_+': t_plus_range},
88+
seed=seed,
89+
batch_size=10,
90+
)
91+
self.ax = ax
92+
self.ax.set_xlim(*x_range)
93+
self.ax.set_ylim(*y_range)
94+
self.ax.xaxis.set_ticks([])
95+
self.ax.yaxis.set_ticks([])
96+
self.ax.set_xlabel("model parameter")
97+
self.ax.set_ylabel("discrepancy")
98+
self.initial_evidence = initial_evidence
99+
self.line, = self.ax.plot([], [])
100+
self.acq, = self.ax.plot([], [])
101+
self.img = self.ax.imshow(
102+
0 * canvas[0],
103+
cmap='gist_yarg',
104+
vmin=0,
105+
vmax=1,
106+
aspect='auto',
107+
extent=[*x_range, *y_range]
108+
)
109+
self.pts, = self.ax.plot(
110+
[], [], lw=0, marker='o',
111+
color=plt.rcParams['axes.prop_cycle'].by_key()['color'][0]
112+
)
113+
trans = matplotlib.transforms.ScaledTranslation(
114+
240/72, -10/72, fig.dpi_scale_trans
115+
)
116+
self.txt = self.ax.text(
117+
0.0, 1.0, str(self.initial_evidence) + " samples ",
118+
transform=ax.transAxes + trans, verticalalignment='top'
119+
)
120+
self.frames = frames
121+
122+
def __call__(self, i):
123+
if self.frames is not None:
124+
n_evidence = self.initial_evidence + self.frames[i]
125+
else:
126+
n_evidence = self.initial_evidence + i
127+
self.bolfi.fit(n_evidence=n_evidence)
128+
mean, var = self.bolfi.target_model.predict(
129+
t_plus_eval, noiseless=True
130+
)
131+
self.line.set_data(t_plus_eval, mean)
132+
eta_squared = 2 * np.log(
133+
n_evidence**4 * np.pi**2 / 0.3
134+
)
135+
self.acq.set_data(t_plus_eval, mean - np.sqrt(eta_squared * var))
136+
unc = (
137+
np.exp(-(canvas[1] - mean.T)**2 / (2 * var.T))
138+
/ np.sqrt(2 * np.pi * var.T)
139+
)
140+
self.ax.imshow(
141+
unc,
142+
cmap='gist_yarg',
143+
vmin=0,
144+
vmax=np.max(unc),
145+
aspect='auto',
146+
extent=[*x_range, *y_range]
147+
)
148+
self.pts.set_data(
149+
self.bolfi.target_model._gp.X, self.bolfi.target_model._gp.Y
150+
)
151+
self.txt.set_text(str(n_evidence) + " samples")
152+
return self.line, self.acq, self.img, self.pts, self.txt
153+
154+
155+
initial_evidence = 3
156+
frames = np.array([3, 4, 13, 14]) - initial_evidence
157+
158+
fig, ax = plt.subplots(figsize=(6, 4))
159+
anim_gp = Animate_GP(fig, ax, initial_evidence=initial_evidence, frames=frames)
160+
anim = FuncAnimation(
161+
fig, anim_gp, frames=4, interval=200, blit=False, repeat=False
162+
)
163+
164+
bolfi = elfi.BOLFI(
165+
distance,
166+
initial_evidence=initial_evidence,
167+
bounds={'t_+': t_plus_range},
168+
seed=seed,
169+
batch_size=10,
170+
)
171+
172+
likelihood_range = [0.405, 0.425]
173+
likelihood_eval = np.linspace(*likelihood_range, 200)
174+
gps_at_each_frame = []
175+
176+
fig_static, axes = plt.subplots(figsize=(6, 4), nrows=2, ncols=2)
177+
178+
for i, ax in enumerate(axes.flatten()):
179+
ax.xaxis.set_ticks([])
180+
ax.yaxis.set_ticks([])
181+
ax.set_xlim(*x_range)
182+
ax.set_ylim(*y_range)
183+
if frames is not None:
184+
n_evidence = initial_evidence + frames[i]
185+
else:
186+
n_evidence = initial_evidence + i
187+
bolfi.fit(n_evidence=n_evidence)
188+
trans = matplotlib.transforms.ScaledTranslation(
189+
126/72, -5/72, fig.dpi_scale_trans
190+
)
191+
mean, var = bolfi.target_model.predict(t_plus_eval, noiseless=True)
192+
gps_at_each_frame.append(
193+
bolfi.target_model.predict(likelihood_eval, noiseless=True)
194+
)
195+
ax.plot(t_plus_eval, mean)
196+
eta_squared = 2 * np.log(
197+
n_evidence**4 * np.pi**2 / 0.3
198+
)
199+
ax.plot(t_plus_eval, mean - np.sqrt(eta_squared * var))
200+
unc = (
201+
np.exp(-(canvas[1] - mean.T)**2 / (2 * var.T))
202+
/ np.sqrt(2 * np.pi * var.T)
203+
)
204+
ax.imshow(
205+
unc,
206+
cmap='gist_yarg',
207+
vmin=0,
208+
vmax=np.max(unc),
209+
aspect='auto',
210+
extent=[*x_range, *y_range]
211+
)
212+
ax.scatter(
213+
bolfi.target_model._gp.X, bolfi.target_model._gp.Y
214+
)
215+
ax.text(
216+
0.0, 1.0, str(n_evidence) + " samples ",
217+
transform=ax.transAxes + trans,
218+
verticalalignment='top', horizontalalignment='right'
219+
)
220+
fig_static.supxlabel(r"Model parameter $\theta$")
221+
fig_static.supylabel("Model-data distance")
222+
fig_static.tight_layout()
223+
224+
posterior = bolfi.extract_posterior()
225+
threshold = posterior.threshold
226+
likelihood_yrange = [-0.0012, 0.0082]
227+
likelihood_canvas = np.meshgrid(
228+
np.linspace(*likelihood_range, 200),
229+
np.linspace(*reversed(likelihood_yrange), 200)
230+
)
231+
mean, var = bolfi.target_model.predict(likelihood_eval, noiseless=True)
232+
likelihood = ss.norm().cdf((threshold - mean) / np.sqrt(var))
233+
normalizing = np.sum(
234+
0.5
235+
* (likelihood[:-1] + likelihood[1:])
236+
* (t_plus_eval[1:] - t_plus_eval[:-1])
237+
)
238+
239+
fig_int, (ax_gp, ax_int) = plt.subplots(figsize=(6, 4), nrows=2)
240+
ax_gp.set_xlim(*likelihood_range)
241+
ax_int.set_xlim(*likelihood_range)
242+
ax_gp.xaxis.set_ticks([])
243+
ax_int.xaxis.set_ticks([])
244+
ax_gp.yaxis.set_ticks([])
245+
ax_int.yaxis.set_ticks([])
246+
ax_gp.set_ylabel(r"$\log||y_i(\theta)-y_i^\star||$")
247+
ax_int.set_ylabel(r"$L_K(\theta)$")
248+
ax_int.set_xlabel(r"Model parameter $\theta$")
249+
trans_int = matplotlib.transforms.ScaledTranslation(
250+
10/72, -5/72, fig_int.dpi_scale_trans
251+
)
252+
ax_gp.text(0.0, 1.0, '(a)', transform=ax_gp.transAxes + trans_int,
253+
verticalalignment='top', fontsize=20)
254+
ax_int.text(0.0, 1.0, '(b)', transform=ax_int.transAxes + trans_int,
255+
verticalalignment='top', fontsize=20)
256+
trans_samples = matplotlib.transforms.ScaledTranslation(
257+
162/72, -10/72, fig.dpi_scale_trans
258+
)
259+
ax_gp.text(
260+
0.0, 1.0, str(n_evidence) + " samples ",
261+
transform=ax_gp.transAxes + trans_samples, verticalalignment='top'
262+
)
263+
ax_gp.plot(likelihood_eval, mean)
264+
ax_gp.plot(likelihood_eval, mean - np.sqrt(eta_squared * var))
265+
ax_gp.plot(likelihood_eval, [threshold] * len(likelihood_eval))
266+
ax_gp.scatter(
267+
bolfi.target_model._gp.X, bolfi.target_model._gp.Y
268+
)
269+
truncated_unc = (
270+
np.exp(-(likelihood_canvas[1] - mean.T)**2 / (2 * var.T))
271+
/ np.sqrt(2 * np.pi * var.T)
272+
) / normalizing * (likelihood_canvas[1] < threshold)
273+
ax_gp.imshow(
274+
truncated_unc,
275+
cmap='gist_yarg',
276+
vmin=0,
277+
vmax=np.max(truncated_unc),
278+
aspect='auto',
279+
extent=[*likelihood_range, *likelihood_yrange]
280+
)
281+
ax_int.plot(
282+
likelihood_eval,
283+
likelihood / normalizing,
284+
color=plt.rcParams['axes.prop_cycle'].by_key()['color'][4]
285+
)
286+
287+
fig_int.tight_layout()
288+
289+
eps_min = -0.005
290+
eps_max = 0.04
291+
threshold_eval = np.linspace(eps_min, eps_max, 200)
292+
norm = matplotlib.colors.Normalize(eps_min, eps_max)
293+
cmap = plt.get_cmap('viridis')
294+
fig_eps, ax_eps = plt.subplots(
295+
figsize=(4 * 2**0.5, 4), constrained_layout=True)
296+
# mean, var = gps_at_each_frame[2]
297+
for eps in threshold_eval:
298+
likelihood_eps = ss.norm().cdf((eps - mean) / np.sqrt(var))
299+
normalizing_eps = np.sum(
300+
0.5
301+
* (likelihood_eps[:-1] + likelihood_eps[1:])
302+
* (t_plus_eval[1:] - t_plus_eval[:-1])
303+
)
304+
ax_eps.plot(
305+
likelihood_eval,
306+
likelihood_eps / normalizing_eps,
307+
color=cmap(norm(eps))
308+
)
309+
ax_eps.set_title("Normalized Likelihoods")
310+
fig_eps.colorbar(matplotlib.cm.ScalarMappable(
311+
norm=norm, cmap=cmap
312+
), ax=ax_eps, label="threshold")
313+
314+
plt.show()

0 commit comments

Comments
 (0)