Skip to content

BQ for estimating the expectation of a function estimated by a GP #854

@neildhir

Description

@neildhir

Is your feature request related to a problem? Please describe.

This is not quite a feature request (nor a bug report), but more of a request for information of how to perform BQ, using probnum to estimate an expectation of a function estimate i.e. $\mathbb{E}[\hat{f}(x)]$.

Give an example use case.

Using a Gaussian process we can estimate the relationship between variables $x$ and $y$ and then use BQ to get the expectation of the estimate at some test value.

We are interested in:

$\mathbb{E} [ \hat{f}(x) ] = \int \hat{f}(x) p(x) \text{d}x$

The relationship between $x$ and $y$ is estimated using a GP yielding estimator $\hat{f}$. Where the likelihood of a new test point is then modelled by a 1D gaussian density with parameters $\hat{\mu}, \hat{\Sigma}$ - fitted to samples from $f$.

MWE

from botorch.models import SingleTaskGP # wraps a GPyTorch ExactGP
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from gpytorch.mlls import ExactMarginalLogLikelihood
from torch import ones, linspace, no_grad
from botorch.fit import fit_gpytorch_mll
import numpy as np

# Function generates noisy samples from the linear relationship x = y, it then standardised and normalises these samples for downstream usage in a GPyTorch GP
def sample_f(n, noise_std):
    x = np.linspace(0, 10, n)
    noise = np.random.normal(0, noise_std, n)
    y = x + noise

    # Scale the data to the unit cube
    scaler1 = MinMaxScaler()
    scaler2 = StandardScaler()
    x_scaled = scaler1.fit_transform(x.reshape(-1, 1))
    y_scaled = scaler2.fit_transform(y.reshape(-1, 1))

    return tensor(x_scaled), tensor(y_scaled)

def get_fitted_model(train_X:tensor, train_Y:tensor) -> SingleTaskGP:
    model = SingleTaskGP(train_X=train_X, train_Y=train_Y)
    mll = ExactMarginalLogLikelihood(likelihood=model.likelihood, model=model)
    fit_gpytorch_mll(mll)
    return model

x, y = sample_f(10, 1)
model = get_fitted_model(x, y)

def my_fun(x):
    with no_grad():
        f_preds = model(x)
        return f_preds.mean * model.likelihood(f_preds.mean) # integrand

# BQ
measure = LebesgueMeasure(input_dim=1, domain=(0, 1))
qp = QuadratureProblem(fun=my_fun, measure=measure, solution=None)

Describe the solution you'd like.
Explanation or correction whether or not this is the correct way to approach BQ for this problem setting.

Presently qp.solution is empty. Consequently I believe I have done something wrong or misunderstood BQ for expectation estimation.

Additional context
A plot of some sample data, true function and GP approximation of the true function.

import matplotlib.pyplot as plt
plt.scatter(x, y, color='black', label='noisy samples from true model')
plt.plot(x, x, color='red', label='y=x (true unscaled function)')
plt.xlabel('x')
plt.ylabel('y')
plt.title('Plot of (x, y) pairs')

# Plot the GP model
x_pred = linspace(0, 1, 100)
with no_grad():
    y_pred = model.posterior(x_pred.unsqueeze(1)).mean
plt.plot(x_pred, y_pred, color='blue', label='GP model')

plt.legend()
plt.show()
Screenshot 2024-02-21 at 12 46 48

Metadata

Metadata

Assignees

No one assigned

    Labels

    quadIssues related to quadraturequestionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions