How to set priors
HaoLiu56 opened this issue · comments
Issue description
Hi, I'm new to BoTorch. I wonder how to set custom priors in SingleTaskGP
Code example
I tried to build a model and set priors by myself, I'll encounter the below errors, could you help me see how to set these priors?
Code example:
model = SingleTaskGP(train_X=init_x, train_Y=init_y,
input_transform=Normalize(d=7),
outcome_transform=Standardize(m=1)
model.likelihood.noise_covar.register_prior(
"noise_prior",
GammaPrior(concentration=2.0, rate=4.0),
lambda: model.likelihood.noise_covar.noise,
lambda v: model.likelihood.noise_covar._set_noise(v),
)
model.covar_module.register_prior(
"outputscale_prior",
GammaPrior(concentration=2.0, rate=4.0),
lambda: model.covar_module.outputscale,
lambda v: model.covar_module._set_outputscale(v),
)
model.covar_module.base_kernel.register_prior(
"lengthscale_prior",
GammaPrior(concentration=2.0, rate=0.2),
lambda: model.covar_module.base_kernel.lengthscale,
lambda v: model.covar_module.base_kernel._set_lengthscale(v),
)
mll = ExactMarginalLogLikelihood(model.likelihood, model)
fit_gpytorch_mll(mll);
Error message:
ValueError Traceback (most recent call last)
Cell In[96], line 17
3 model = SingleTaskGP(train_X=init_x, train_Y=init_y,
4 input_transform=Normalize(d=7),
5 outcome_transform=Standardize(m=1))
7 # new_noise_prior = GammaPrior(concentration=0.5, rate=0.1)
8
9 # noise_covar = model.likelihood.noise_covar
(...)
14 # lambda v: noise_covar._set_noise(v),
15 # )
---> 17 model.likelihood.noise_covar.register_prior(
18 "noise_prior",
19 GammaPrior(concentration=2.0, rate=4.0),
20 lambda: model.likelihood.noise_covar.noise,
21 lambda v: model.likelihood.noise_covar._set_noise(v),
22 )
24 model.covar_module.register_prior(
25 "outputscale_prior",
26 GammaPrior(concentration=2.0, rate=4.0),
27 lambda: model.covar_module.outputscale,
28 lambda v: model.covar_module._set_outputscale(v),
29 )
30 model.covar_module.base_kernel.register_prior(
31 "lengthscale_prior",
32 GammaPrior(concentration=2.0, rate=0.2),
33 lambda: model.covar_module.base_kernel.lengthscale,
34 lambda v: model.covar_module.base_kernel._set_lengthscale(v),
35 )
File ~/anaconda3/envs/ActiveLearning/lib/python3.11/site-packages/gpytorch/module.py:247, in Module.register_prior(self, name, prior, param_or_closure, setting_closure)
245 else:
246 if len(inspect.signature(param_or_closure).parameters) == 0:
--> 247 raise ValueError(
248 """As of version 1.4, param_or_closure
must operate on a module instance. For example:
249
250 likelihood.noise_covar.register_prior(
251 "noise_std_prior",
252 gpytorch.priors.NormalPrior(0, 1),
253 lambda module: module.noise.sqrt()
254 )
255 """
256 )
257 if inspect.isfunction(setting_closure) and len(inspect.signature(setting_closure).parameters) < 2:
258 raise ValueError(
259 """As of version 1.4, setting_closure
must operate on a module instance and a tensor. For example:
260
(...)
267 """
268 )
ValueError: As of version 1.4, param_or_closure
must operate on a module instance. For example:
likelihood.noise_covar.register_prior(
"noise_std_prior",
gpytorch.priors.NormalPrior(0, 1),
lambda module: module.noise.sqrt()
)
System Info
Please provide information about your setup, including
- BoTorch Version (0.10.0)
- GPyTorch Version (1.11)
- PyTorch Version (2.2.0.post100)
- Computer OS: mac OS Sonoma
Hi, thanks for reaching out. SingleTaskGP
uses a Matern kernel with a Gamma prior by default, but if you want to change the parameters of the Gamma distribution, you can do it like so:
from botorch.models.gp_regression import SingleTaskGP
from botorch.models.transforms.input import Normalize
from botorch.models.transforms.outcome import Standardize
from gpytorch.priors.torch_priors import GammaPrior
from gpytorch.mlls import ExactMarginalLogLikelihood
from botorch.fit import fit_gpytorch_mll
from botorch.models.utils.gpytorch_modules import get_matern_kernel_with_gamma_prior
from gpytorch.kernels import MaternKernel, ScaleKernel
import torch
m = 1
d = 7
n = 3
batch_shape = []
init_x = torch.rand((*batch_shape, n, d), dtype=torch.float64)
init_y = torch.rand((*batch_shape, n, m), dtype=torch.float64)
covar_module = ScaleKernel(
base_kernel=MaternKernel(
nu=2.5,
ard_num_dims=d,
batch_shape=torch.Size(batch_shape),
lengthscale_prior=GammaPrior(3.0, 6.0),
),
batch_shape=torch.Size(batch_shape),
outputscale_prior=GammaPrior(2.0, 0.15),
)
model = SingleTaskGP(
train_X=init_x,
train_Y=init_y,
input_transform=Normalize(d=d),
outcome_transform=Standardize(m=m),
covar_module=covar_module
)
mll = ExactMarginalLogLikelihood(model.likelihood, model)
fit_gpytorch_mll(mll)
Thank you very much! Could you also show me how to self define the 'noise prior'?
And Can I ask what is batch_shape
mean here?
Does it means the repetition of my data? (e.g. I replicate my experiment twice, then batch_shape=2)
Or it means different data batch from different experiment?
Could you also show me how to self define the 'noise prior'?
Noise prior is a part of the model's likelihood
. You can define a custom likelihood in the same way and pass it in. The default likelihood module is costructed by this helper:
def get_gaussian_likelihood_with_gamma_prior(
batch_shape: Optional[torch.Size] = None,
) -> GaussianLikelihood:
r"""Constructs the GaussianLikelihood that is used by default by
several models. This uses a Gamma(1.1, 0.05) prior and constrains the
noise level to be greater than MIN_INFERRED_NOISE_LEVEL (=1e-4).
"""
batch_shape = torch.Size() if batch_shape is None else batch_shape
noise_prior = GammaPrior(1.1, 0.05)
noise_prior_mode = (noise_prior.concentration - 1) / noise_prior.rate
return GaussianLikelihood(
noise_prior=noise_prior,
batch_shape=batch_shape,
noise_constraint=GreaterThan(
MIN_INFERRED_NOISE_LEVEL,
transform=None,
initial_value=noise_prior_mode,
),
)
And Can I ask what is batch_shape mean here?
The batch_shape
is the output dimension augmented batch shape of the underlying GPyTorch model. If your train_Y
has shape batch x n x m
, it'll be batch + m
if m>1
and batch
when m=1
. We use this helper to infer it from the training data:
def get_batch_dimensions(
train_X: Tensor, train_Y: Tensor
) -> Tuple[torch.Size, torch.Size]:
r"""Get the raw batch shape and output-augmented batch shape of the inputs.
Args:
train_X: A `n x d` or `batch_shape x n x d` (batch mode) tensor of training
features.
train_Y: A `n x m` or `batch_shape x n x m` (batch mode) tensor of
training observations.
Returns:
2-element tuple containing
- The `input_batch_shape`
- The output-augmented batch shape: `input_batch_shape x (m)`
"""
input_batch_shape = train_X.shape[:-2]
aug_batch_shape = input_batch_shape
num_outputs = train_Y.shape[-1]
if num_outputs > 1:
aug_batch_shape += torch.Size([num_outputs])
return input_batch_shape, aug_batch_shape
Thanks for clarifying!
Closing since this seems to have been answered, but feel free to ask more questions.