Skip to content

[Documentation] Incomplete documentation for implementing custom models #2427

Open
@slishak-PX

Description

@slishak-PX

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions