id | title |
---|---|
objectives |
Objectives |
In BoTorch, an objective is a module that allows for convenient transformation of model outputs into a scalar function to be optimized. Typical use cases for this are the scalarization of outputs for a multi-output model (see e.g. 1), or optimization subject to outcome constraints, which can be achieved by weighting the objective by the probability of feasibility 2.
When using classical analytic formulations of acquisition functions, one needs to be careful that the transformation results in a posterior distribution of the transformed outputs that still satisfies the assumptions of the analytic formulation. For instance, to use standard Expected Improvement on a transformed output of a model, the transformation needs to be affine (because Gaussians are closed under affine transformations). When using MC-based acquisition functions, however, fewer assumptions are required, and one can apply general transformations to the model outputs with relative impunity so long gradients can be back-propagated through the transformation.
All BoTorch objectives are derived from
MCAcquisitionObjective
.
BoTorch implements several MC-based objectives, including
LinearMCObjective
for linear
combinations of model outputs, and
ConstrainedMCObjective
for
constrained objectives (using a sigmoid approximation for the constraints).
The GenericMCObjective
allows
simply using a generic callable to implement an ad-hoc objective. The callable
is expected to map a sample_shape x batch_shape x q x o
-dimensional tensor of
posterior samples and an (optional) batch_shape x q x d
-dimensional tensor of
inputs to a sample_shape x batch_shape x q
-dimensional tensor of sampled
objective values.
For instance, say you have a multi-output model with
obj = lambda xi, X: 1 - torch.norm(xi - y_0, dim=-1)
mc_objective = GenericMCObjective(obj)
Instead of using GenericMCObjective
, you can also implement your own
MCAcquisitionObjective
modules to make them easier to re-use, or support
more complex logic. The only thing required to implement
is a forward
method that takes in a
sample_shape x batch_shape x q x o
-dimensional tensor of
posterior samples and maps it to a
sample_shape x batch_shape x q
-dimensional tensor of sampled objective values.
A custom objective module of the above example would be
class MyCustomObjective(MCAcquisitionObjective):
def forward(self, samples, X=None):
return 1 - torch.norm(samples - y_0, dim=-1)