import math import torch from gpytorch.priors import Prior from torch.distributions import HalfCauchy,HalfNormal,constraints from torch.distributions.utils import broadcast_all from numbers import Number class LogHalfHorseshoePrior(Prior): """Prior for the log-noise variance hyperparameter for GPs. This is parameterized by `scale` and `lb`. `lb` is the lower bound on the noise variance. The `scale` parameter is more important. The default value for `scale` - 0.01 - works well for deterministic and low-noise situations. A larger value may be need in noisy sitations and small training datasets. A larger scale implies more noisy data as the prior. To change the scale for this prior for a model to say 0.1, >>> model.likelihood.register( >>> 'noise_prior',LogHalfHorseshoePrior(0.1,model.likelihood.noise_prior.lb), >>> 'raw_noise' >>> ) .. note:: The `log_prob` method is only approximate and unnormalized. There is no closed form expression for the underlying horseshoe distribution. The lower and upper bounds on its' density are, however, known. Here, we use the same approximate density value that the spearmint package uses. :param scale: scale parameter of the Horseshoe distribution :type scale: float or torch.Tensor :param lb: lower bound on the original scale. Defaults to 1e-6 :type lb: float or torch.Tensor, optional """ arg_constraints = {"scale": constraints.positive,"lb":constraints.positive} support = constraints.real def __init__(self, scale, lb=1e-6,validate_args=None): self.scale,self.lb = broadcast_all(scale,lb) if isinstance(scale,Number): batch_shape = torch.Size() else: batch_shape = self.scale.size() super().__init__(batch_shape,validate_args=validate_args) def transform(self, x): return self.lb + torch.exp(x) def log_prob(self, X): # first term is the density in the original scale # the second term is for the transformation return torch.log(torch.log(1+3*(self.scale / self.transform(X)) ** 2))+ X def rsample(self, sample_shape=torch.Size([])): local_shrinkage = HalfCauchy(1).rsample(self.scale.shape).to(self.lb) param_sample = HalfNormal(local_shrinkage * self.scale).rsample(sample_shape).to(self.lb) if len(self.lb) > 1: param_sample[param_sample