Multi-Task Test#

At first we have to install the newest version of fvGP

##First, install the newest version of fvgp
#!pip install fvgp~=4.8.6
#!pip install plotly
#pip install --upgrade kaleido

Setup#

import numpy as np
import matplotlib.pyplot as plt
from fvgp import GP
import plotly.graph_objects as go
from itertools import product
import plotly.io as pio
pio.renderers.default = "png"
%load_ext autoreload
%autoreload 2

Simple 1d Example#

Data#

def f1(x): return 0.5 * x
def f2(x): return (-.25 * x) - 1.

x_pred1d = np.linspace(0,1,50)
plt.plot(x_pred1d,f1(x_pred1d))
plt.plot(x_pred1d,f2(x_pred1d))
x_data = np.random.rand(10)
y_data1 = f1(x_data) + np.random.uniform(low = -0.01, high = 0.01, size =len(x_data))
y_data2 = f2(x_data) + np.random.uniform(low = -0.01, high = 0.01, size =len(x_data))
plt.scatter(x_data,y_data1) 
plt.scatter(x_data,y_data2) 
plt.show()
../_images/02a065083199bc4c3190f7dc717e4e87af0e35c0277a970fcb2cf9ff874aff84.png

GP initialization#

from fvgp import fvGP

my_gp2 = fvGP(x_data.reshape(len(x_data),1), np.column_stack([y_data1, y_data2]))
print("Global Training in progress")
my_gp2.train(max_iter = 20, info=True)
Global Training in progress
Starting likelihood. f(x)=  31.507854514037824
Finished  10  out of  20  iterations. f(x)=  43.90229304384373
/home/marcus/Coding/fvGP/fvgp/gp.py:500: UserWarning: Hyperparameters initialized to a vector of ones.
  warnings.warn("Hyperparameters initialized to a vector of ones.")
/home/marcus/Coding/fvGP/fvgp/gp.py:536: UserWarning: No noise function or measurement noise provided. Noise variances will be set to (0.01 * mean(|y_data|))^2.
  self.likelihood = GPlikelihood(self.data,
/home/marcus/Coding/fvGP/fvgp/gp.py:1021: UserWarning: Default hyperparameter_bounds initialized because none were provided. This will fail for custom kernel, mean, or noise functions
  warnings.warn("Default hyperparameter_bounds initialized because none were provided. "
array([0.92849284, 6.60077476, 1.45475153])
print("Data as seen by fvgp:")
print(my_gp2.fvgp_x_data)
print(my_gp2.fvgp_y_data)

print("Transformed data for the GP:")
print(my_gp2.x_data)
print(my_gp2.y_data)
Data as seen by fvgp:
[[0.55496274]
 [0.54980083]
 [0.73855146]
 [0.51203224]
 [0.22668151]
 [0.09026322]
 [0.01267208]
 [0.59715033]
 [0.14257962]
 [0.1684044 ]]
[[ 0.27415257 -1.13294602]
 [ 0.28336197 -1.13220687]
 [ 0.36511105 -1.17771369]
 [ 0.24927794 -1.1323592 ]
 [ 0.1051445  -1.05950872]
 [ 0.05075115 -1.03151234]
 [ 0.00370759 -0.99451728]
 [ 0.29506668 -1.15926706]
 [ 0.06531947 -1.02623569]
 [ 0.08211646 -1.03361486]]
Transformed data for the GP:
[[0.55496274 0.        ]
 [0.54980083 0.        ]
 [0.73855146 0.        ]
 [0.51203224 0.        ]
 [0.22668151 0.        ]
 [0.09026322 0.        ]
 [0.01267208 0.        ]
 [0.59715033 0.        ]
 [0.14257962 0.        ]
 [0.1684044  0.        ]
 [0.55496274 1.        ]
 [0.54980083 1.        ]
 [0.73855146 1.        ]
 [0.51203224 1.        ]
 [0.22668151 1.        ]
 [0.09026322 1.        ]
 [0.01267208 1.        ]
 [0.59715033 1.        ]
 [0.14257962 1.        ]
 [0.1684044  1.        ]]
[[ 0.27415257]
 [ 0.28336197]
 [ 0.36511105]
 [ 0.24927794]
 [ 0.1051445 ]
 [ 0.05075115]
 [ 0.00370759]
 [ 0.29506668]
 [ 0.06531947]
 [ 0.08211646]
 [-1.13294602]
 [-1.13220687]
 [-1.17771369]
 [-1.1323592 ]
 [-1.05950872]
 [-1.03151234]
 [-0.99451728]
 [-1.15926706]
 [-1.02623569]
 [-1.03361486]]

Predictions#

y_test = np.hstack([f1(x_pred1d).reshape(len(x_pred1d),1),f2(x_pred1d).reshape(len(x_pred1d),1)])
print("RMSE:              ", my_gp2.rmse(x_pred1d.reshape(len(x_pred1d),1),y_test))
print("NLPD:              ", my_gp2.nlpd(x_pred1d.reshape(len(x_pred1d),1),y_test))
print("R2:                ", my_gp2.r2(x_pred1d.reshape(len(x_pred1d),1),y_test))
print("CRPS (mean, std):  ", my_gp2.crps(x_pred1d.reshape(len(x_pred1d),1),y_test))
RMSE:               0.010609817928863252
NLPD:               -3.8817623356303104
R2:                 0.999768477462133
CRPS (mean, std):   (np.float64(0.004232198868484882), np.float64(0.005020593676119593))
#mean and standard deviation
mean = my_gp2.posterior_mean(x_pred=x_pred1d.reshape(50,1))["m(x)"]
std = np.sqrt(my_gp2.posterior_covariance(x_pred=x_pred1d.reshape(50,1), x_out=np.array([0,1]))["v(x)"])


plt.plot(x_pred1d.reshape(50,1),mean[:,0], label = "mean task 1")
plt.plot(x_pred1d.reshape(50,1),mean[:,1], label = "mean task 2")
plt.scatter(x_data,y_data1) 
plt.scatter(x_data,y_data2) 
plt.plot(x_pred1d,f1(x_pred1d), label = "task 1 ground truth")
plt.plot(x_pred1d,f2(x_pred1d), label = "task 2 ground truth")
plt.fill_between(x_pred1d, mean[:,0] - 3. * std[:,0], mean[:,0] + 3. * std[:,0], alpha = 0.5, color = "grey")
plt.fill_between(x_pred1d, mean[:,1] - 3. * std[:,1], mean[:,1] + 3. * std[:,1], alpha = 0.5, color = "grey")
plt.legend()
plt.show()
../_images/dccd77a3028138b4d747bdd49c1af80637ff0175fbbafb61df46aa66ab712265.png
#mean gradient and variance gradient
mean_grad = my_gp2.posterior_mean_grad(x_pred=x_pred1d.reshape(50,1), x_out=np.array([0,1]))["dm/dx"]
var_grad = my_gp2.posterior_covariance_grad(x_pred=x_pred1d.reshape(50,1), x_out=np.array([0,1]))["dv/dx"]

plt.plot(x_pred1d.reshape(50,1),mean_grad[:,0,0], label = "mean gradient task 1")
plt.plot(x_pred1d.reshape(50,1),mean_grad[:,0,1], label = "mean gradient task 2")
plt.plot(x_pred1d,np.gradient(f1(x_pred1d), 1./50.), label = "grad task 1 ground truth")
plt.plot(x_pred1d,np.gradient(f2(x_pred1d), 1./50.), label = "grad task 2 ground truth")
plt.plot(x_pred1d.reshape(50,1),var_grad[:,0,0], label = "var gradient task 1")
plt.plot(x_pred1d.reshape(50,1),var_grad[:,0,1], label = "var gradient task 2")
plt.legend()
plt.show()
../_images/fcddad81de8a33e8ec8733695982d13b8b79bb16c15252b457c8af5f0348dfed.png

What if some tasks are missing from the data#

It works just fine, but we have to insert np.nan at positions of missing data, both for y and the variances.#

y_data = np.column_stack([y_data1, y_data2])
noise_variances = np.zeros(y_data.shape) + 0.01
y_data[2,0] = np.nan
noise_variances[2,0] = np.nan

y_data[6,1] = np.nan
noise_variances[6,1] = np.nan

my_gp2 = fvGP(x_data.reshape(len(x_data),1), y_data, noise_variances=noise_variances)
print("Global Training in progress")
my_gp2.train(max_iter = 20)
Global Training in progress
array([0.12779334, 1.76233351, 0.05770436])

3d Example#

Data#

data = np.load("./data/sim_variable_mod.npy")
sparsification = 4

x_data3 = data[:,5:][::sparsification]
y_data3 = data[:,0:2][::sparsification]

#it is good practice to check the format of the data
print(x_data3.shape)
print(y_data3.shape)
(1583, 3)
(1583, 2)
index = np.where(x_data3[:,2] == 1200.)[0]
x_data3=x_data3[index,0:2]
y_data3=y_data3[index]

for i in range(x_data3.shape[1]):
    x_data3[:,i] = x_data3[:,i] - np.min(x_data3[:,i])
    x_data3[:,i] = x_data3[:,i] / np.max(x_data3[:,i])
x = np.linspace(0,1,100)
y = np.linspace(0,1,100)
x_pred3D = np.asarray(list(product(x, y)))
def scatter(x,y,z,size=3, color = 1):
    #if not color: color = z
    fig = go.Figure()
    fig.add_trace(go.Scatter3d(x=x, y=y, z=z,mode='markers',marker=dict(color=color, size = size)))
    
    
    fig.update_layout(autosize=False,
                  width=800, height=800,
                  font=dict(size=18,),
                  margin=dict(l=0, r=0, b=0, t=0))
    fig.show()
scatter(x_data3[:,0],x_data3[:,1],y_data3[:,0], size = 5, color = y_data3[:,0])
scatter(x_data3[:,0],x_data3[:,1],y_data3[:,1], size = 5, color = y_data3[:,1])
../_images/857f088e7c72b239c9c96a86393dfd5c1c3d4ffca5f08ae7124ce82baedbc009.png ../_images/18d0f2d968a0d3a350e4aab323320571f07e8fd23b60d89685276a653a9bd108.png

Initialization#

(a) Default behavior — minimal#

from fvgp import fvGP

my_gp2 = fvGP(x_data3,y_data3)
print("Global Training in progress")
my_gp2.train(max_iter = 2)
Global Training in progress
/home/marcus/Coding/fvGP/fvgp/gp.py:500: UserWarning: Hyperparameters initialized to a vector of ones.
  warnings.warn("Hyperparameters initialized to a vector of ones.")
/home/marcus/Coding/fvGP/fvgp/gp.py:536: UserWarning: No noise function or measurement noise provided. Noise variances will be set to (0.01 * mean(|y_data|))^2.
  self.likelihood = GPlikelihood(self.data,
/home/marcus/Coding/fvGP/fvgp/gp.py:1021: UserWarning: Default hyperparameter_bounds initialized because none were provided. This will fail for custom kernel, mean, or noise functions
  warnings.warn("Default hyperparameter_bounds initialized because none were provided. "
array([0.16782057, 5.9472849 , 9.11743636, 4.47873019])

(b) Custom kernel#

It is vital in the multi-task case to think hard about kernel design. The kernel is now a function over X x X x T x T, where X is the input and T is the output space. Print the input of the kernel, it will have the dimensionality of this cartesian product space. The default kernel in fvgp is just a Matern kernel operating in this new space.

#A simple kernel that won't lead to good performance because it's stationary
from fvgp.kernels import *
def mkernel(x1,x2,hps):
    d = get_distance_matrix(x1,x2)
    return hps[0] * matern_kernel_diff1(d,hps[1])
my_gp2 = fvGP(x_data3,y_data3,
              init_hyperparameters=np.ones((2)), kernel_function=mkernel
             )
print("MCMC Training in progress")


bounds = np.array([[0.01,1.],[0.01,1.]])
my_gp2.train(hyperparameter_bounds=bounds,max_iter = 20)
MCMC Training in progress
array([0.87816069, 0.58556637])

(c) A custom deep kernel#

from fvgp.deep_kernel_network import *
from fvgp.kernels import *
iset_dim = 3
gp_deep_kernel_layer_width = 5
n = Network(iset_dim, gp_deep_kernel_layer_width)
print(n.number_of_hps)

def deep_multi_task_kernel(x1, x2, hps):  # pragma: no cover
    signal_var = hps[0]
    length_scale = hps[1]
    hps_nn = hps[2:]
    w1_indices = np.arange(0, gp_deep_kernel_layer_width * iset_dim)
    last = gp_deep_kernel_layer_width * iset_dim
    w2_indices = np.arange(last, last + gp_deep_kernel_layer_width ** 2)
    last = last + gp_deep_kernel_layer_width ** 2
    w3_indices = np.arange(last, last + gp_deep_kernel_layer_width * iset_dim)
    last = last + gp_deep_kernel_layer_width * iset_dim
    b1_indices = np.arange(last, last + gp_deep_kernel_layer_width)
    last = last + gp_deep_kernel_layer_width
    b2_indices = np.arange(last, last + gp_deep_kernel_layer_width)
    last = last + gp_deep_kernel_layer_width
    b3_indices = np.arange(last, last + iset_dim)

    n.set_weights(hps_nn[w1_indices].reshape(gp_deep_kernel_layer_width, iset_dim),
                  hps_nn[w2_indices].reshape(gp_deep_kernel_layer_width, gp_deep_kernel_layer_width),
                  hps_nn[w3_indices].reshape(iset_dim, gp_deep_kernel_layer_width))
    n.set_biases(hps_nn[b1_indices].reshape(gp_deep_kernel_layer_width),
                 hps_nn[b2_indices].reshape(gp_deep_kernel_layer_width),
                 hps_nn[b3_indices].reshape(iset_dim))
    x1_nn = n.forward(x1)
    x2_nn = n.forward(x2)
    d = get_distance_matrix(x1_nn, x2_nn)
    k = signal_var * matern_kernel_diff1(d, length_scale)
    return k


my_gp2 = fvGP(x_data3,y_data3,
              init_hyperparameters=np.ones((n.number_of_hps+2))*0.1, kernel_function=deep_multi_task_kernel
             )

print("MCMC Training in progress")
bounds = np.zeros((n.number_of_hps+2,2))
bounds[0] = np.array([0.01,1.])
bounds[1] = np.array([0.1,1.])
bounds[2:] = np.array([-1,1])
my_gp2.train(hyperparameter_bounds=bounds,max_iter = 300, method = "mcmc", info = True)
68
MCMC Training in progress
Starting likelihood. f(x)=  -204924.16723757322
/home/marcus/Coding/fvGP/fvgp/gp.py:536: UserWarning: No noise function or measurement noise provided. Noise variances will be set to (0.01 * mean(|y_data|))^2.
  self.likelihood = GPlikelihood(self.data,
Finished  10  out of  300  iterations. f(x)=  -2014.3176487834087
Finished  20  out of  300  iterations. f(x)=  -738.365549087808
Finished  30  out of  300  iterations. f(x)=  -738.365549087808
Finished  40  out of  300  iterations. f(x)=  -738.365549087808
Finished  50  out of  300  iterations. f(x)=  -350.78515724388916
Finished  60  out of  300  iterations. f(x)=  62.80042041768576
Finished  70  out of  300  iterations. f(x)=  297.6517366030599
Finished  80  out of  300  iterations. f(x)=  351.78608632540823
Finished  90  out of  300  iterations. f(x)=  671.1634231780963
Finished  100  out of  300  iterations. f(x)=  856.3724746635505
Finished  110  out of  300  iterations. f(x)=  856.3724746635505
Finished  120  out of  300  iterations. f(x)=  900.0185671570468
Finished  130  out of  300  iterations. f(x)=  900.0185671570468
Finished  140  out of  300  iterations. f(x)=  902.1095666763365
Finished  150  out of  300  iterations. f(x)=  908.4551669613095
Finished  160  out of  300  iterations. f(x)=  908.4551669613095
Finished  170  out of  300  iterations. f(x)=  914.5271251575653
Finished  180  out of  300  iterations. f(x)=  927.6184482883712
Finished  190  out of  300  iterations. f(x)=  927.6184482883712
Finished  200  out of  300  iterations. f(x)=  932.9295086565519
Finished  210  out of  300  iterations. f(x)=  937.7466958752291
Finished  220  out of  300  iterations. f(x)=  937.7466958752291
Finished  230  out of  300  iterations. f(x)=  937.7466958752291
Finished  240  out of  300  iterations. f(x)=  937.7466958752291
Finished  250  out of  300  iterations. f(x)=  942.5304816928926
Finished  260  out of  300  iterations. f(x)=  942.5304816928926
Finished  270  out of  300  iterations. f(x)=  942.5304816928926
Finished  280  out of  300  iterations. f(x)=  942.5304816928926
Finished  290  out of  300  iterations. f(x)=  943.4724928195747
array([ 0.25437111,  0.10116515, -0.04178066, -0.6739599 ,  0.38963764,
       -0.11114264, -0.30660413, -0.27323933, -0.21130059,  0.22761933,
        0.06489414, -0.36969247,  0.19846411,  0.61983991,  0.46212535,
        0.21324786, -0.04935924, -0.1820413 , -0.78757663,  0.14636997,
        0.02496616,  0.13003899,  0.07516544,  0.93365117, -0.0682337 ,
       -0.09693454,  0.30227051, -0.06500306,  0.32356108,  0.10489028,
        0.30111028, -0.51734482,  0.25470617,  0.36258342,  0.25175426,
        0.42536017,  0.21826459,  0.18263785,  0.65670512, -0.27412586,
        0.69986775,  0.95709718,  0.48286612,  0.10761125,  0.69169167,
        0.23008218, -0.21289665,  0.02511654,  0.47261045, -0.28088074,
       -0.0625802 ,  0.40291708, -0.67251631, -0.1793064 , -0.33292806,
        0.80448875,  0.54553336, -0.44180672,  0.11166209,  0.25168685,
        0.1645877 ,  0.43237351,  0.28575278, -0.28132167,  0.96462488,
        0.52930974,  0.15588001,  0.80152634, -0.66054458,  0.60861895])

Prediction#

mean = my_gp2.posterior_mean(x_pred3D)["m(x)"]
var =  my_gp2.posterior_covariance(x_pred3D)["v(x)"]
fig = go.Figure()
fig.add_trace(go.Scatter3d(x=x_pred3D[:,0],y=x_pred3D[:,1], z=mean[:,0],
                             mode='markers',marker=dict(color=mean[:,0], size = 5)))
fig.add_trace(go.Scatter3d(x=x_data3[:,0], y=x_data3[:,1] , z=y_data3[:,0],
                           mode='markers',marker=dict(color=y_data3[:,0], size = 5)))
fig.update_layout(autosize=False,
                  width=800, height=800,
                  font=dict(size=18,),
                  margin=dict(l=0, r=0, b=0, t=0))
fig.show()



fig = go.Figure()
fig.add_trace(go.Scatter3d(x=x_pred3D[:,0],y=x_pred3D[:,1], z=mean[:,1],
                             mode='markers',marker=dict(color=mean[:,0], size = 5)))
fig.add_trace(go.Scatter3d(x=x_data3[:,0], y=x_data3[:,1] , z=y_data3[:,1],
                           mode='markers',marker=dict(color=y_data3[:,1], size = 5)))
fig.update_layout(autosize=False,
                  width=800, height=800,
                  font=dict(size=18,),
                  margin=dict(l=0, r=0, b=0, t=0))
fig.show()
../_images/8b6d99521214d42a40b95fb7490c79a80ca652c1f9f197953abd56c8f7ecd80e.png ../_images/e9e03c8a7ee0dbd97561008c6cafad905c44a37bf15870fde9521fd25bb3c2c7.png