|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# Copyright (c) Meta Platforms, Inc. and affiliates. |
| 3 | +# |
| 4 | +# This source code is licensed under the MIT license found in the |
| 5 | +# LICENSE file in the root directory of this source tree. |
| 6 | + |
| 7 | +r""" |
| 8 | +Acquisition function for joint entropy search (JES). The code utilizes the |
| 9 | +implementation designed for the multi-objective batch setting. |
| 10 | +
|
| 11 | +""" |
| 12 | + |
| 13 | +from __future__ import annotations |
| 14 | + |
| 15 | +from typing import Any, Optional |
| 16 | + |
| 17 | +from botorch.acquisition.multi_objective.joint_entropy_search import ( |
| 18 | + qLowerBoundMultiObjectiveJointEntropySearch, |
| 19 | +) |
| 20 | +from botorch.acquisition.multi_objective.utils import compute_sample_box_decomposition |
| 21 | +from botorch.models.model import Model |
| 22 | +from botorch.utils.transforms import concatenate_pending_points, t_batch_mode_transform |
| 23 | +from torch import Tensor |
| 24 | + |
| 25 | + |
| 26 | +class qLowerBoundJointEntropySearch(qLowerBoundMultiObjectiveJointEntropySearch): |
| 27 | + r"""The acquisition function for the Joint Entropy Search, where the batches |
| 28 | + `q > 1` are supported through the lower bound formulation. |
| 29 | +
|
| 30 | + This acquisition function computes the mutual information between the observation |
| 31 | + at a candidate point `X` and the optimal input-output pair. |
| 32 | +
|
| 33 | + See [Tu2022]_ for a discussion on the estimation procedure. |
| 34 | +
|
| 35 | + NOTES: |
| 36 | + (i) The estimated acquisition value could be negative. |
| 37 | +
|
| 38 | + (ii) The lower bound batch acquisition function might not be monotone in the |
| 39 | + sense that adding more elements to the batch does not necessarily increase the |
| 40 | + acquisition value. Specifically, the acquisition value can become smaller when |
| 41 | + more inputs are added. |
| 42 | + """ |
| 43 | + |
| 44 | + def __init__( |
| 45 | + self, |
| 46 | + model: Model, |
| 47 | + optimal_inputs: Tensor, |
| 48 | + optimal_outputs: Tensor, |
| 49 | + maximize: bool = True, |
| 50 | + hypercell_bounds: Tensor = None, |
| 51 | + X_pending: Optional[Tensor] = None, |
| 52 | + estimation_type: str = "LB", |
| 53 | + num_samples: int = 64, |
| 54 | + **kwargs: Any, |
| 55 | + ) -> None: |
| 56 | + r"""Joint entropy search acquisition function. |
| 57 | +
|
| 58 | + Args: |
| 59 | + model: A fitted single-outcome model. |
| 60 | + optimal_inputs: A `num_samples x d`-dim tensor containing the sampled |
| 61 | + optimal inputs of dimension `d`. We assume for simplicity that each |
| 62 | + sample only contains one optimal set of inputs. |
| 63 | + optimal_outputs: A `num_samples x 1`-dim Tensor containing the optimal |
| 64 | + set of objectives of dimension `1`. |
| 65 | + maximize: If true, we consider a maximization problem. |
| 66 | + hypercell_bounds: A `num_samples x 2 x J x 1`-dim Tensor containing the |
| 67 | + hyper-rectangle bounds for integration, where `J` is the number of |
| 68 | + hyper-rectangles. By default, the problem is assumed to be |
| 69 | + unconstrained and therefore the region of integration for a sample |
| 70 | + `(x*, y*)` is a `J=1` hyper-rectangle of the form `(-infty, y^*]` |
| 71 | + for a maximization problem and `[y^*, +infty)` for a minimization |
| 72 | + problem. In the constrained setting, the region of integration also |
| 73 | + includes the infeasible space. |
| 74 | + X_pending: A `m x d`-dim Tensor of `m` design points that have been |
| 75 | + submitted for function evaluation, but have not yet been evaluated. |
| 76 | + estimation_type: A string to determine which entropy estimate is |
| 77 | + computed: "0", "LB", "LB2", or "MC". In the single-objective |
| 78 | + setting, "LB" is equivalent to "LB2". |
| 79 | + num_samples: The number of Monte Carlo samples used for the Monte Carlo |
| 80 | + estimate. |
| 81 | + """ |
| 82 | + if hypercell_bounds is None: |
| 83 | + hypercell_bounds = compute_sample_box_decomposition( |
| 84 | + pareto_fronts=optimal_outputs.unsqueeze(-2), maximize=maximize |
| 85 | + ) |
| 86 | + |
| 87 | + super().__init__( |
| 88 | + model=model, |
| 89 | + pareto_sets=optimal_inputs.unsqueeze(-2), |
| 90 | + pareto_fronts=optimal_outputs.unsqueeze(-2), |
| 91 | + hypercell_bounds=hypercell_bounds, |
| 92 | + X_pending=X_pending, |
| 93 | + estimation_type=estimation_type, |
| 94 | + num_samples=num_samples, |
| 95 | + ) |
| 96 | + |
| 97 | + @concatenate_pending_points |
| 98 | + @t_batch_mode_transform() |
| 99 | + def forward(self, X: Tensor) -> Tensor: |
| 100 | + r"""Evaluates qLowerBoundJointEntropySearch at the design points `X`. |
| 101 | +
|
| 102 | + Args: |
| 103 | + X: A `batch_shape x q x d`-dim Tensor of `batch_shape` t-batches with `q` |
| 104 | + `d`-dim design points each. |
| 105 | +
|
| 106 | + Returns: |
| 107 | + A `batch_shape`-dim Tensor of acquisition values at the given design |
| 108 | + points `X`. |
| 109 | + """ |
| 110 | + |
| 111 | + return self._compute_lower_bound_information_gain(X) |
0 commit comments