Fast Multitask Net GP¶
In [1]:
Copied!
import fastgps
import torch
import numpy as np
import fastgps
import torch
import numpy as np
In [2]:
Copied!
torch.set_default_dtype(torch.float64)
torch.set_default_dtype(torch.float64)
True Function¶
In [3]:
Copied!
def f_ackley(x, a=20, b=0.2, c=2*np.pi, scaling=32.768):
# https://www.sfu.ca/~ssurjano/ackley.html
assert x.ndim==2
x = 2*scaling*x-scaling
t1 = a*torch.exp(-b*torch.sqrt(torch.mean(x**2,1)))
t2 = torch.exp(torch.mean(torch.cos(c*x),1))
t3 = a+np.exp(1)
y = -t1-t2+t3
return y
f_low_fidelity = lambda x: f_ackley(x,c=0)
f_high_fidelity = lambda x: f_ackley(x)
f_cos = lambda x: torch.cos(2*np.pi*x).sum(1)
fs = [f_low_fidelity,f_high_fidelity,f_cos]
d = 1 # dimension
rng = torch.Generator().manual_seed(17)
x = torch.rand((2**7,d),generator=rng) # random testing locations
y = torch.vstack([f(x) for f in fs]) # true values at random testing locations
z = torch.rand((2**8,d),generator=rng) # other random locations at which to evaluate covariance
print("x.shape = %s"%str(tuple(x.shape)))
print("y.shape = %s"%str(tuple(y.shape)))
print("z.shape = %s"%str(tuple(z.shape)))
def f_ackley(x, a=20, b=0.2, c=2*np.pi, scaling=32.768):
# https://www.sfu.ca/~ssurjano/ackley.html
assert x.ndim==2
x = 2*scaling*x-scaling
t1 = a*torch.exp(-b*torch.sqrt(torch.mean(x**2,1)))
t2 = torch.exp(torch.mean(torch.cos(c*x),1))
t3 = a+np.exp(1)
y = -t1-t2+t3
return y
f_low_fidelity = lambda x: f_ackley(x,c=0)
f_high_fidelity = lambda x: f_ackley(x)
f_cos = lambda x: torch.cos(2*np.pi*x).sum(1)
fs = [f_low_fidelity,f_high_fidelity,f_cos]
d = 1 # dimension
rng = torch.Generator().manual_seed(17)
x = torch.rand((2**7,d),generator=rng) # random testing locations
y = torch.vstack([f(x) for f in fs]) # true values at random testing locations
z = torch.rand((2**8,d),generator=rng) # other random locations at which to evaluate covariance
print("x.shape = %s"%str(tuple(x.shape)))
print("y.shape = %s"%str(tuple(y.shape)))
print("z.shape = %s"%str(tuple(z.shape)))
x.shape = (128, 1) y.shape = (3, 128) z.shape = (256, 1)
Construct Fast GP¶
In [4]:
Copied!
fgp = fastgps.FastGPDigitalNetB2(d,seed_for_seq=7,num_tasks=len(fs))
x_next = fgp.get_x_next(n=[2**6,2**3,2**8])
y_next = [fs[i](x_next[i]) for i in range(fgp.num_tasks)]
fgp.add_y_next(y_next)
assert len(x_next)==len(y_next)
for i in range(len(x_next)):
print("i = %d"%i)
print("\tx_next[%d].shape = %s"%(i,str(tuple(x_next[i].shape))))
print("\ty_next[%d].shape = %s"%(i,str(tuple(y_next[i].shape))))
fgp = fastgps.FastGPDigitalNetB2(d,seed_for_seq=7,num_tasks=len(fs))
x_next = fgp.get_x_next(n=[2**6,2**3,2**8])
y_next = [fs[i](x_next[i]) for i in range(fgp.num_tasks)]
fgp.add_y_next(y_next)
assert len(x_next)==len(y_next)
for i in range(len(x_next)):
print("i = %d"%i)
print("\tx_next[%d].shape = %s"%(i,str(tuple(x_next[i].shape))))
print("\ty_next[%d].shape = %s"%(i,str(tuple(y_next[i].shape))))
i = 0 x_next[0].shape = (64, 1) y_next[0].shape = (64,) i = 1 x_next[1].shape = (8, 1) y_next[1].shape = (8,) i = 2 x_next[2].shape = (256, 1) y_next[2].shape = (256,)
In [5]:
Copied!
pmean = fgp.post_mean(x)
print("pmean.shape = %s"%str(tuple(pmean.shape)))
print("l2 relative error =",(torch.linalg.norm(y-pmean,dim=1)/torch.linalg.norm(y,dim=1)))
pmean = fgp.post_mean(x)
print("pmean.shape = %s"%str(tuple(pmean.shape)))
print("l2 relative error =",(torch.linalg.norm(y-pmean,dim=1)/torch.linalg.norm(y,dim=1)))
pmean.shape = (3, 128) l2 relative error = tensor([0.0413, 0.1572, 0.0591])
In [6]:
Copied!
data = fgp.fit()
list(data.keys())
data = fgp.fit()
list(data.keys())
iter of 5.0e+03 | loss | term1 | term2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0.00e+00 | 4.64e+02 | 8.46e+02 | -5.21e+02 5.00e+00 | 1.40e+02 | 1.73e+02 | -4.95e+02 1.00e+01 | -1.21e+02 | 1.30e+02 | -9.74e+02 1.50e+01 | -2.76e+02 | 2.51e+02 | -1.41e+03 2.00e+01 | -2.85e+02 | 3.24e+02 | -1.50e+03 2.50e+01 | -2.89e+02 | 3.32e+02 | -1.51e+03 3.00e+01 | -2.92e+02 | 3.29e+02 | -1.52e+03 3.50e+01 | -2.93e+02 | 3.30e+02 | -1.52e+03 4.00e+01 | -2.93e+02 | 3.29e+02 | -1.52e+03 4.50e+01 | -2.93e+02 | 3.37e+02 | -1.53e+03
5.00e+01 | -2.94e+02 | 3.31e+02 | -1.52e+03 5.50e+01 | -2.94e+02 | 3.31e+02 | -1.52e+03 6.00e+01 | -2.94e+02 | 3.29e+02 | -1.52e+03 6.50e+01 | -2.94e+02 | 3.32e+02 | -1.52e+03 7.00e+01 | -2.94e+02 | 3.33e+02 | -1.52e+03 7.50e+01 | -2.94e+02 | 3.29e+02 | -1.52e+03 8.00e+01 | -2.94e+02 | 3.31e+02 | -1.52e+03 8.50e+01 | -2.94e+02 | 3.28e+02 | -1.52e+03 9.00e+01 | -2.94e+02 | 3.30e+02 | -1.52e+03 9.50e+01 | -2.94e+02 | 3.29e+02 | -1.52e+03 1.00e+02 | -2.94e+02 | 3.30e+02 | -1.52e+03 1.05e+02 | -2.94e+02 | 3.28e+02 | -1.52e+03
1.10e+02 | -2.94e+02 | 3.30e+02 | -1.52e+03 1.15e+02 | -2.95e+02 | 3.30e+02 | -1.52e+03 1.20e+02 | -2.95e+02 | 3.32e+02 | -1.52e+03 1.25e+02 | -2.95e+02 | 3.31e+02 | -1.52e+03 1.30e+02 | -2.95e+02 | 3.30e+02 | -1.52e+03 1.35e+02 | -2.95e+02 | 3.28e+02 | -1.52e+03 1.40e+02 | -2.95e+02 | 3.29e+02 | -1.52e+03 1.45e+02 | -2.95e+02 | 3.31e+02 | -1.52e+03 1.50e+02 | -2.95e+02 | 3.32e+02 | -1.52e+03 1.52e+02 | -2.95e+02 | 3.28e+02 | -1.52e+03
Out[6]:
['iterations']
In [7]:
Copied!
pmean,pvar,q,ci_low,ci_high = fgp.post_ci(x,confidence=0.99)
print("pmean.shape = %s"%str(tuple(pmean.shape)))
print("pvar.shape = %s"%str(tuple(pvar.shape)))
print("q = %.2f"%q)
print("ci_low.shape = %s"%str(tuple(ci_low.shape)))
print("ci_high.shape = %s"%str(tuple(ci_high.shape)))
print("l2 relative error =",(torch.linalg.norm(y-pmean,dim=1)/torch.linalg.norm(y,dim=1)))
pcov = fgp.post_cov(x,x)
print("pcov.shape = %s"%str(tuple(pcov.shape)))
_range0,_rangen1 = torch.arange(pcov.size(0)),torch.arange(pcov.size(-1))
assert torch.allclose(pcov[_range0,_range0][:,_rangen1,_rangen1],pvar) and (pvar>=0).all()
pcov2 = fgp.post_cov(x,z)
print("pcov2.shape = %s"%str(tuple(pcov2.shape)))
pmean,pvar,q,ci_low,ci_high = fgp.post_ci(x,confidence=0.99)
print("pmean.shape = %s"%str(tuple(pmean.shape)))
print("pvar.shape = %s"%str(tuple(pvar.shape)))
print("q = %.2f"%q)
print("ci_low.shape = %s"%str(tuple(ci_low.shape)))
print("ci_high.shape = %s"%str(tuple(ci_high.shape)))
print("l2 relative error =",(torch.linalg.norm(y-pmean,dim=1)/torch.linalg.norm(y,dim=1)))
pcov = fgp.post_cov(x,x)
print("pcov.shape = %s"%str(tuple(pcov.shape)))
_range0,_rangen1 = torch.arange(pcov.size(0)),torch.arange(pcov.size(-1))
assert torch.allclose(pcov[_range0,_range0][:,_rangen1,_rangen1],pvar) and (pvar>=0).all()
pcov2 = fgp.post_cov(x,z)
print("pcov2.shape = %s"%str(tuple(pcov2.shape)))
pmean.shape = (3, 128) pvar.shape = (3, 128) q = 2.58 ci_low.shape = (3, 128) ci_high.shape = (3, 128) l2 relative error = tensor([0.0405, 0.0643, 0.0121])
pcov.shape = (3, 3, 128, 128) pcov2.shape = (3, 3, 128, 256)
In [8]:
Copied!
pcmean,pcvar,q,cci_low,cci_high = fgp.post_cubature_ci(confidence=0.99)
print("pcmean =",pcmean)
print("pcvar =",pcvar)
print("cci_low =",cci_low)
print("cci_high",cci_high)
pcmean,pcvar,q,cci_low,cci_high = fgp.post_cubature_ci(confidence=0.99)
print("pcmean =",pcmean)
print("pcvar =",pcvar)
print("cci_low =",cci_low)
print("cci_high",cci_high)
pcmean = tensor([ 1.7083e+01, 1.8070e+01, -1.3444e-04]) pcvar = tensor([1.6682e-01, 2.4426e-01, 9.3850e-05]) cci_low = tensor([16.0311, 16.7967, -0.0251]) cci_high tensor([18.1353, 19.3428, 0.0248])
Project and Increase Sample Size¶
In [9]:
Copied!
n_new = fgp.n*torch.tensor([4,2,8])
pcov_future = fgp.post_cov(x,z,n=n_new)
pvar_future = fgp.post_var(x,n=n_new)
pcvar_future = fgp.post_cubature_var(n=n_new)
n_new = fgp.n*torch.tensor([4,2,8])
pcov_future = fgp.post_cov(x,z,n=n_new)
pvar_future = fgp.post_var(x,n=n_new)
pcvar_future = fgp.post_cubature_var(n=n_new)
In [10]:
Copied!
x_next = fgp.get_x_next(n_new)
y_next = [fs[i](x_next[i]) for i in range(fgp.num_tasks)]
for _y in y_next:
print(_y.shape)
fgp.add_y_next(y_next)
print("l2 relative error =",(torch.linalg.norm(y-fgp.post_mean(x),dim=1)/torch.linalg.norm(y,dim=1)))
assert torch.allclose(fgp.post_cov(x,z),pcov_future)
assert torch.allclose(fgp.post_var(x),pvar_future)
assert torch.allclose(fgp.post_cubature_var(),pcvar_future)
x_next = fgp.get_x_next(n_new)
y_next = [fs[i](x_next[i]) for i in range(fgp.num_tasks)]
for _y in y_next:
print(_y.shape)
fgp.add_y_next(y_next)
print("l2 relative error =",(torch.linalg.norm(y-fgp.post_mean(x),dim=1)/torch.linalg.norm(y,dim=1)))
assert torch.allclose(fgp.post_cov(x,z),pcov_future)
assert torch.allclose(fgp.post_var(x),pvar_future)
assert torch.allclose(fgp.post_cubature_var(),pcvar_future)
torch.Size([192]) torch.Size([8]) torch.Size([1792]) l2 relative error = tensor([0.0124, 0.0569, 0.0014])
In [11]:
Copied!
data = fgp.fit(verbose=False)
print("l2 relative error =",(torch.linalg.norm(y-fgp.post_mean(x),dim=1)/torch.linalg.norm(y,dim=1)))
data = fgp.fit(verbose=False)
print("l2 relative error =",(torch.linalg.norm(y-fgp.post_mean(x),dim=1)/torch.linalg.norm(y,dim=1)))
l2 relative error = tensor([0.0110, 0.0590, 0.0014])
In [12]:
Copied!
n_new = fgp.n*torch.tensor([4,8,2])
pcov_new = fgp.post_cov(x,z,n=n_new)
pvar_new = fgp.post_var(x,n=n_new)
pcvar_new = fgp.post_cubature_var(n=n_new)
x_next = fgp.get_x_next(n_new)
y_next = [fs[i](x_next[i]) for i in range(fgp.num_tasks)]
fgp.add_y_next(y_next)
assert torch.allclose(fgp.post_cov(x,z),pcov_new)
assert torch.allclose(fgp.post_var(x),pvar_new)
assert torch.allclose(fgp.post_cubature_var(),pcvar_new)
n_new = fgp.n*torch.tensor([4,8,2])
pcov_new = fgp.post_cov(x,z,n=n_new)
pvar_new = fgp.post_var(x,n=n_new)
pcvar_new = fgp.post_cubature_var(n=n_new)
x_next = fgp.get_x_next(n_new)
y_next = [fs[i](x_next[i]) for i in range(fgp.num_tasks)]
fgp.add_y_next(y_next)
assert torch.allclose(fgp.post_cov(x,z),pcov_new)
assert torch.allclose(fgp.post_var(x),pvar_new)
assert torch.allclose(fgp.post_cubature_var(),pcvar_new)