FVGP MULTI Task Notebook

In this notebook we will go through many features of FVGP. We will be primarily concerned with regression over a single dimension output and multiple tasks.

This first cell has nothing to do with gpCAM, it’s just a function to plot some results later

import plotly.graph_objects as go
import numpy as np
def plot(x,y,z,data = None):
    fig = go.Figure()
    fig.add_trace(go.Surface(x = x, y = y,z=z))
    if data is not None: 
        fig.add_trace(go.Scatter3d(x=data[:,0], y=data[:,1], z=data[:,2],
                                   mode='markers'))

    fig.update_layout(title='Posterior Mean', autosize=True,
                  width=800, height=800,
                  margin=dict(l=65, r=50, b=65, t=90))


    fig.show()

Import fvgp and relevant libraries

import fvgp
from fvgp import gp, fvgp
import numpy as np
import matplotlib.pyplot as plt

Defining some input data and testing points

def function(x):
    data_1 = 100*np.sin(x)+np.cos(x)
    data_2 = 5*np.ones(x.shape)
    data_3 = 1*np.cos(x/10 + 5)
    data_4 = 5*np.sin(x/200)
    data_5 = 10*np.cos(x)
    
    return np.column_stack((data_1, data_2, data_3, data_4, data_5))
x_data = np.linspace(-2*np.pi, 10*np.pi,100).reshape(-1,1)
y_data = function(x_data)
x_pred = np.linspace(3*np.pi, 4*np.pi, 100)

Setting up the fvgp multi task object

obj = fvgp.fvGP(1,1,5,x_data,y_data,
               init_hyperparameters = np.array([10,10,10]))

Training our gaussian process regression on given data

hyper_param_bounds = np.array([[0.0001, 1000],[ 0.0001, 1000],[ 0.0001, 1000]])
obj.train(hyper_param_bounds)
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
Cell In[8], line 2
      1 hyper_param_bounds = np.array([[0.0001, 1000],[ 0.0001, 1000],[ 0.0001, 1000]])
----> 2 obj.train(hyper_param_bounds)

File ~/checkouts/readthedocs.org/user_builds/fvgp/envs/stable/lib/python3.8/site-packages/fvgp/gp.py:279, in GP.train(self, hyperparameter_bounds, init_hyperparameters, method, pop_size, tolerance, max_iter, local_optimizer, global_optimizer, constraints, deflation_radius, dask_client)
    276 if init_hyperparameters is None:
    277     init_hyperparameters = np.array(self.hyperparameters)
--> 279 self.hyperparameters = self._optimize_log_likelihood(
    280     init_hyperparameters,
    281     np.array(hyperparameter_bounds),
    282     method,
    283     max_iter,
    284     pop_size,
    285     tolerance,
    286     constraints,
    287     local_optimizer,
    288     global_optimizer,
    289     deflation_radius,
    290     dask_client
    291     )
    292 self._compute_prior_fvGP_pdf()

File ~/checkouts/readthedocs.org/user_builds/fvgp/envs/stable/lib/python3.8/site-packages/fvgp/gp.py:476, in GP._optimize_log_likelihood(self, starting_hps, hp_bounds, method, max_iter, pop_size, tolerance, constraints, local_optimizer, global_optimizer, deflation_radius, dask_client)
    474 logger.debug("termination tolerance: {}", tolerance)
    475 logger.debug("bounds: {}", hp_bounds)
--> 476 res = differential_evolution(
    477     self.neg_log_likelihood,
    478     hp_bounds,
    479     maxiter=max_iter,
    480     popsize = pop_size,
    481     tol = tolerance,
    482     constraints = constraints,
    483     workers = 1,
    484 )
    485 hyperparameters = np.array(res["x"])
    486 Eval = self.neg_log_likelihood(hyperparameters)

File ~/checkouts/readthedocs.org/user_builds/fvgp/envs/stable/lib/python3.8/site-packages/scipy/optimize/_differentialevolution.py:397, in differential_evolution(func, bounds, args, strategy, maxiter, popsize, tol, mutation, recombination, seed, callback, disp, polish, init, atol, updating, workers, constraints, x0, integrality, vectorized)
    380 # using a context manager means that any created Pool objects are
    381 # cleared up.
    382 with DifferentialEvolutionSolver(func, bounds, args=args,
    383                                  strategy=strategy,
    384                                  maxiter=maxiter,
   (...)
    395                                  integrality=integrality,
    396                                  vectorized=vectorized) as solver:
--> 397     ret = solver.solve()
    399 return ret

File ~/checkouts/readthedocs.org/user_builds/fvgp/envs/stable/lib/python3.8/site-packages/scipy/optimize/_differentialevolution.py:998, in DifferentialEvolutionSolver.solve(self)
    995 for nit in range(1, self.maxiter + 1):
    996     # evolve the population by a generation
    997     try:
--> 998         next(self)
    999     except StopIteration:
   1000         warning_flag = True

File ~/checkouts/readthedocs.org/user_builds/fvgp/envs/stable/lib/python3.8/site-packages/scipy/optimize/_differentialevolution.py:1385, in DifferentialEvolutionSolver.__next__(self)
   1383     feasible = True
   1384     cv = np.atleast_2d([0.])
-> 1385     energy = self.func(parameters)
   1386     self._nfev += 1
   1388 # compare trial and population member

File ~/checkouts/readthedocs.org/user_builds/fvgp/envs/stable/lib/python3.8/site-packages/scipy/_lib/_util.py:372, in _FunctionWrapper.__call__(self, x)
    371 def __call__(self, x):
--> 372     return self.f(x, *self.args)

File ~/checkouts/readthedocs.org/user_builds/fvgp/envs/stable/lib/python3.8/site-packages/fvgp/gp.py:587, in GP.neg_log_likelihood(self, hyperparameters)
    585 mean = self.mean_function(self.x_data,hyperparameters,self)
    586 if mean.ndim > 1: raise Exception("Your mean function did not return a 1d numpy array!")
--> 587 x,K = self._compute_covariance_value_product(hyperparameters,self.y_data, self.variances, mean)
    588 y = self.y_data - mean
    589 sign, logdet = self.slogdet(K)

File ~/checkouts/readthedocs.org/user_builds/fvgp/envs/stable/lib/python3.8/site-packages/fvgp/gp.py:709, in GP._compute_covariance_value_product(self, hyperparameters, values, variances, mean)
    708 def _compute_covariance_value_product(self, hyperparameters,values, variances, mean):
--> 709     K = self._compute_covariance(hyperparameters, variances)
    710     y = values - mean
    711     x = self.solve(K, y)

File ~/checkouts/readthedocs.org/user_builds/fvgp/envs/stable/lib/python3.8/site-packages/fvgp/gp.py:717, in GP._compute_covariance(self, hyperparameters, variances)
    715 def _compute_covariance(self, hyperparameters, variances):
    716     """computes the covariance matrix from the kernel"""
--> 717     CoVariance = self.kernel(
    718         self.x_data, self.x_data, hyperparameters, self)
    719     self.add_to_diag(CoVariance, variances)
    720     return CoVariance

File ~/checkouts/readthedocs.org/user_builds/fvgp/envs/stable/lib/python3.8/site-packages/fvgp/gp.py:1718, in GP.default_kernel(self, x1, x2, hyperparameters, obj)
   1716     distance_matrix += abs(np.subtract.outer(x1[:,i],x2[:,i])/hps[1+i])**2
   1717 distance_matrix = np.sqrt(distance_matrix)
-> 1718 return   hps[0] * obj.matern_kernel_diff1(distance_matrix,1)

File ~/checkouts/readthedocs.org/user_builds/fvgp/envs/stable/lib/python3.8/site-packages/fvgp/gp.py:1492, in GP.matern_kernel_diff1(self, distance, length)
   1473 def matern_kernel_diff1(self, distance, length):
   1474     """
   1475     Function for the matern kernel, order of differentiablity = 1.
   1476     kernel = (1.0 + ((np.sqrt(3.0) * distance) / (length))) * np.exp(
   (...)
   1488     A structure of the shape of the distance input parameter : float or np.ndarray
   1489     """
   1491     kernel = (1.0 + ((np.sqrt(3.0) * distance) / (length))) * np.exp(
-> 1492         -(np.sqrt(3.0) * distance) / length
   1493     )
   1494     return kernel

KeyboardInterrupt: 

Looking at the posterior mean at the test points (remember that we did not define a particularly good kernel)

task_idx = 1
x_linspace = np.linspace(3*np.pi, 4*np.pi,100)
y_linspace = np.linspace(0,4,100)
x_grid, y_grid = np.meshgrid(x_linspace, y_linspace)
post_mean= obj.posterior_mean(np.column_stack((x_pred, task_idx*np.ones(x_pred.shape))))
posterior_mean = obj.posterior_mean(np.column_stack((x_grid.flatten(), y_grid.flatten())))
fig = plt.figure(figsize = (10,10))
ax = fig.add_subplot(projection='3d')


ax.scatter(post_mean['x'][:,0], np.ones(100)*0,y_data[:,0])
ax.scatter(post_mean['x'][:,0], np.ones(100)*1,y_data[:,1])
ax.scatter(post_mean['x'][:,0], np.ones(100)*2,y_data[:,2])
ax.scatter(post_mean['x'][:,0], np.ones(100)*3,y_data[:,3])
ax.scatter(post_mean['x'][:,0], np.ones(100)*4,y_data[:,4])
ax.plot_surface(x_grid, y_grid, posterior_mean['f(x)'].reshape(100,100), rstride=1, cstride=1,cmap='inferno')
<mpl_toolkits.mplot3d.art3d.Poly3DCollection at 0x7f3a2804daf0>
../_images/bcfbaecb52f1f2782f74347c072eed9516a60858946064eef71eef61e9ad1159.png