Source code for nubo.acquisition.analytical
import torch
from torch import Tensor
from torch.distributions.normal import Normal
from gpytorch.models import GP
from .acquisition_function import AcquisitionFunction
from typing import Optional
[docs]
class ExpectedImprovement(AcquisitionFunction):
r"""
Expected improvement acquisition function:
.. math::
\alpha_{EI} (\boldsymbol X_*) = \left(\mu_n(\boldsymbol X_*) - y^{best} \right) \Phi(z) + \sigma_n(\boldsymbol X_*) \phi(z),
where :math:`z = \frac{\mu_n(\boldsymbol X_*) - y^{best}}{\sigma_n(\boldsymbol X_*)}`,
:math:`\mu_n(\cdot)` and :math:`\sigma_n(\cdot)` are the mean and the
standard deviation of the posterior distribution of the Gaussian process,
:math:`y^{best}` is the current best observation, and :math:`\Phi (\cdot)`
and :math:`\phi (\cdot)` are the cumulative distribution function and the
probability density function of the standard normal distribution.
Attributes
----------
gp : ``gpytorch.models.GP``
Gaussian Process model.
y_best : ``torch.Tensor``
(size 1) Best output of training data.
"""
def __init__(self,
gp: GP,
y_best: Tensor) -> None:
"""
Parameters
----------
gp : ``gpytorch.models.GP``
Gaussian Process model.
y_best : ``torch.Tensor``
(size 1) Best output of training data.
"""
self.gp = gp
self.y_best = y_best
[docs]
def eval(self, x: Tensor) -> Tensor:
"""
Computes the (negative) expected improvement for some test point `x`
analytically.
Parameters
----------
x : ``torch.Tensor``
(size 1 x d) Test point.
Returns
-------
``torch.Tensor``
(size 1) (Negative) expected improvement of `x`.
"""
# check that only one point is queried
if x.size(0) != 1:
raise ValueError("Only one point (size 1 x d) can be computed at a time.")
# set Gaussian Process to eval mode
self.gp.eval()
# make predictions
pred = self.gp(x)
mean = pred.mean
variance = pred.variance.clamp_min(1e-10)
std = torch.sqrt(variance)
# compute Expected Improvement
norm = Normal(torch.tensor([0.0]), torch.tensor([1.0]))
z = (mean - self.y_best)/std
ei = (mean - self.y_best)*norm.cdf(z) + std*torch.exp(norm.log_prob(z))
ei = ei.clamp_min(0.)
return -ei
[docs]
class UpperConfidenceBound(AcquisitionFunction):
r"""
Upper confidence bound acquisition function:
.. math::
\alpha_{UCB} (\boldsymbol X_*) = \mu_n(\boldsymbol X_*) + \sqrt{\beta} \sigma_n(\boldsymbol X_*),
where :math:`\beta` is a predefined trade-off parameter, and
:math:`\mu_n(\cdot)` and :math:`\sigma_n(\cdot)` are the mean and the
standard deviation of the posterior distribution of the Gaussian process.
Attributes
----------
gp : ``gpytorch.models.GP``
Gaussian Process model.
beta : ``float``
Trade-off parameter, default is 4.0.
"""
def __init__(self,
gp: GP,
beta: Optional[float]=4.0) -> None:
"""
Parameters
----------
gp : ``gpytorch.models.GP``
Gaussian Process model.
beta : ``float``, optional
Trade-off parameter, default is 4.0.
"""
self.gp = gp
self.beta = beta
[docs]
def eval(self, x: Tensor) -> Tensor:
"""
Computes the (negative) upper confidence bound for some test point
`x` analytically.
Parameters
----------
x : ``torch.Tensor``
(size 1 x d) Test point.
Returns
-------
``torch.Tensor``
(size 1) (Negative) upper confidence bound of `x`.
"""
# check that only one point is queried
if x.size(0) != 1:
raise ValueError("Only one point (size 1 x d) can be computed at a time.")
# set Gaussian Process to eval mode
self.gp.eval()
# make predictions
pred = self.gp(x)
mean = pred.mean
variance = pred.variance.clamp_min(1e-10)
std = torch.sqrt(variance)
# compute Upper Confidence Bound
ucb = mean + torch.sqrt(Tensor([self.beta]))*std
return -ucb