Open
Description
The Implementing Custom Models section of the documentation makes it sound a lot more straightforward to use a custom model than it really is. So far, I've found the following extra conditions that should be mentioned (in this instance, when using qNoisyExpectedImprovement
):
The posterior
method must accept a posterior_transform
kwarg, otherwise the following error appears:
Stack trace
File .../python3.11/site-packages/botorch/acquisition/monte_carlo.py:500, in qNoisyExpectedImprovement.__init__(self, model, X_baseline, sampler, objective, posterior_transform, X_pending, prune_baseline, cache_root, constraints, eta, marginalize_dim)
496 CachedCholeskyMCSamplerMixin.__init__(
497 self, model=model, cache_root=cache_root, sampler=sampler
498 )
499 if prune_baseline:
--> 500 X_baseline = prune_inferior_points(
501 model=model,
502 X=X_baseline,
503 objective=objective,
504 posterior_transform=posterior_transform,
505 constraints=self._constraints,
506 marginalize_dim=marginalize_dim,
507 )
508 self.register_buffer("X_baseline", X_baseline)
509 # registering buffers for _get_samples_and_objectives in the next `if` block
File .../python3.11/site-packages/botorch/acquisition/utils.py:306, in prune_inferior_points(model, X, objective, posterior_transform, constraints, num_samples, max_frac, sampler, marginalize_dim)
304 raise ValueError(f"max_frac must take values in (0, 1], is {max_frac}")
305 with torch.no_grad():
--> 306 posterior = model.posterior(X=X, posterior_transform=posterior_transform)
307 if sampler is None:
308 sampler = get_sampler(
309 posterior=posterior, sample_shape=torch.Size([num_samples])
310 )
TypeError: Model.posterior() got an unexpected keyword argument 'posterior_transform'
The model additionally requires a num_outputs
attribute, otherwise the following error appears (related to #354):
Stack trace
File .../python3.11/site-packages/botorch/acquisition/monte_carlo.py:91, in MCAcquisitionFunction.__init__(self, model, sampler, objective, posterior_transform, X_pending)
89 super().__init__(model=model)
90 MCSamplerMixin.__init__(self, sampler=sampler)
---> 91 if objective is None and model.num_outputs != 1:
92 if posterior_transform is None:
93 raise UnsupportedError(
94 "Must specify an objective or a posterior transform when using "
95 "a multi-output model."
96 )
File .../python3.11/site-packages/torch/nn/modules/module.py:1688, in Module.__getattr__(self, name)
1686 if name in modules:
1687 return modules[name]
-> 1688 raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'")
AttributeError: 'Model' object has no attribute 'num_outputs'
A posterior sampler must be registered using @GetSampler.register(object)
, otherwise the following error appears:
Stack trace
File .../python3.11/site-packages/botorch/acquisition/monte_carlo.py:500, in qNoisyExpectedImprovement.__init__(self, model, X_baseline, sampler, objective, posterior_transform, X_pending, prune_baseline, cache_root, constraints, eta, marginalize_dim)
496 CachedCholeskyMCSamplerMixin.__init__(
497 self, model=model, cache_root=cache_root, sampler=sampler
498 )
499 if prune_baseline:
--> 500 X_baseline = prune_inferior_points(
501 model=model,
502 X=X_baseline,
503 objective=objective,
504 posterior_transform=posterior_transform,
505 constraints=self._constraints,
506 marginalize_dim=marginalize_dim,
507 )
508 self.register_buffer("X_baseline", X_baseline)
509 # registering buffers for _get_samples_and_objectives in the next `if` block
File .../python3.11/site-packages/botorch/acquisition/utils.py:308, in prune_inferior_points(model, X, objective, posterior_transform, constraints, num_samples, max_frac, sampler, marginalize_dim)
306 posterior = model.posterior(X=X, posterior_transform=posterior_transform)
307 if sampler is None:
--> 308 sampler = get_sampler(
309 posterior=posterior, sample_shape=torch.Size([num_samples])
310 )
311 samples = sampler(posterior)
312 if objective is None:
File .../python3.11/site-packages/botorch/sampling/get_sampler.py:67, in get_sampler(posterior, sample_shape, **kwargs)
51 r"""Get the sampler for the given posterior.
52
53 The sampler can be used as `sampler(posterior)` to produce samples
(...)
64 The `MCSampler` object for the given posterior.
65 """
66 kwargs["sample_shape"] = sample_shape
---> 67 return GetSampler(posterior, **kwargs)
File .../python3.11/site-packages/botorch/utils/dispatcher.py:93, in Dispatcher.__call__(self, *args, **kwargs)
91 func = self.__getitem__(types=types)
92 try:
---> 93 return func(*args, **kwargs)
94 except MDNotImplementedError:
95 # Traverses registered methods in order, yields whenever a match is found
96 funcs = self.dispatch_iter(*types)
File .../python3.11/site-packages/botorch/sampling/get_sampler.py:132, in _not_found_error(posterior, sample_shape, **kwargs)
128 @GetSampler.register(object)
129 def _not_found_error(
130 posterior: Posterior, sample_shape: torch.Size, **kwargs: Any
131 ) -> None:
--> 132 raise NotImplementedError(
133 f"A registered `MCSampler` for posterior {posterior} is not found. You can "
134 "implement and register one using `@GetSampler.register`."
135 )
NotImplementedError: A registered `MCSampler` for posterior <__main__.ModelPosterior object at 0x7fb28dc8ed10> is not found. You can implement and register one using `@GetSampler.register`.
Furthermore, when not using stochastic sampling, the Posterior
object must also implement base_sample_shape
, batch_range
and potentially more.