-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsamplingutils.py
More file actions
128 lines (79 loc) · 4.52 KB
/
Copy pathsamplingutils.py
File metadata and controls
128 lines (79 loc) · 4.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import torch
import gpytorch
from botorch.models.gp_regression import SingleTaskGP
from botorch.sampling.pathwise.prior_samplers import draw_bayes_linear_paths
def draw_quad_kernel_prior_paths(quad_kernel, n_samples): #quad_kernel is a scaled polynomial(power=2) kernel
c = quad_kernel.offset
ws = torch.randn(size=[n_samples,1,3])
def paths(xs):
if len(xs.shape) == 2 and xs.shape[1] == 1: #xs must be n_samples x npoints x 1 dim
xs = xs.repeat(n_samples,1,1) #duplicate over batch (sample) dim
X = torch.concat([xs * xs, (2 * c).sqrt() * xs, c.expand(*xs.shape)], dim=2)
W = ws.repeat(1,xs.shape[1],1) #ws is n_samples x 1 x 3 dim
phis = W*X
return torch.sum(phis, dim=-1) #result tensor is shape n_samples x npoints
return paths
def draw_product_kernel_prior_paths(model, n_samples):
ndim = model.train_inputs[0].shape[1]
matern_covar_module = model.covar_module.base_kernel.kernels[0] #expects ProductKernel (Matern x Polynomial(dim=2))
matern_covar_module = gpytorch.kernels.ScaleKernel(matern_covar_module)
matern_covar_module.outputscale = model.covar_module.outputscale.detach()
mean_module = gpytorch.means.ZeroMean()
likelihood = gpytorch.likelihoods.GaussianLikelihood()
likelihood.noise = model.likelihood.noise.detach()
outcome_transform = None
input_transform = None
########################################
#build zero-mean (ndim-1)-dimensional GP called matern_model
#with kernel matched to the Matern component of the passed model
matern_model = SingleTaskGP(train_X = torch.tensor([[0.]*(ndim-1)]),
train_Y = torch.tensor([[0.]]),
likelihood = likelihood,
mean_module = mean_module,
covar_module = matern_covar_module,
outcome_transform = outcome_transform,
input_transform = input_transform
)
########################################
matern_prior_paths = draw_bayes_linear_paths(
model=matern_model,
sample_shape=torch.Size([n_samples]),
output_transform=None
)
quad_kernel = model.covar_module.base_kernel.kernels[1]
quad_prior_paths = draw_quad_kernel_prior_paths(quad_kernel, n_samples)
def product_kernel_prior_paths(xs):
return (matern_prior_paths(xs[:,:-1].float()).reshape(n_samples,-1) * quad_prior_paths(xs[:,-1:].float())).double()
return product_kernel_prior_paths
def draw_product_kernel_post_paths(model, n_samples, cpu=True):
product_kernel_prior_paths = draw_product_kernel_prior_paths(model, n_samples=n_samples)
train_x = model.train_inputs[0]
# if model.input_transform is not None:
# train_x = model.input_transform.untransform(train_x)
train_y = model.train_targets.reshape(-1,1)
# if model.outcome_transform is not None:
# train_y = model.outcome_transform.untransform(train_y)[0]
train_y = train_y - model.mean_module(train_x).reshape(train_y.shape)
# Knn = model.covar_module.forward(train_x, train_x) #remove forward
Knn = model.covar_module(train_x, train_x)
sigma = torch.sqrt(model.likelihood.noise[0])
K = Knn + sigma**2*torch.eye(Knn.shape[0])
prior_residual = train_y.repeat(n_samples,1,1).reshape(n_samples,-1) - product_kernel_prior_paths(train_x)
prior_residual -= sigma*torch.randn_like(prior_residual)
# v = K.inv_matmul(prior_residual)
v = torch.linalg.solve(torch.block_diag(*[K.to_dense()]*n_samples), prior_residual.reshape(-1,1)) #replace with cholesky approach
v = v.reshape(n_samples,-1,1)
def post_paths(xs):
if model.input_transform is not None:
xs = model.input_transform(xs)
# K_update = model.covar_module.forward(train_x, xs.double()) #remove forward
K_update = model.covar_module(train_x, xs.double()) #remove forward
v_t = v.transpose(1,2)
update = torch.matmul(v_t, K_update)
update = update.reshape(n_samples,-1)
prior = product_kernel_prior_paths(xs)
post = prior + update + (model.mean_module(xs).reshape(1,-1)).repeat(n_samples,1)
if model.outcome_transform is not None:
post = model.outcome_transform.untransform(post)[0]
return post
return post_paths