Ejemplo n.º 1
0
 def test_affine_acquisition_objective(self, cuda=False):
     device = torch.device("cuda") if cuda else torch.device("cpu")
     for dtype in (torch.float, torch.double):
         offset = torch.rand(1).item()
         for batch_shape in ([], [3]):
             for o in (1, 2):
                 weights = torch.randn(o, device=device, dtype=dtype)
                 obj = ScalarizedObjective(weights=weights, offset=offset)
                 posterior = _get_test_posterior(batch_shape,
                                                 device,
                                                 dtype,
                                                 o=o)
                 mean, covar = posterior.mvn.mean, posterior.mvn.covariance_matrix
                 new_posterior = obj(posterior)
                 exp_size = torch.Size(batch_shape + [1, 1])
                 self.assertEqual(new_posterior.mean.shape, exp_size)
                 new_mean_exp = offset + mean @ weights
                 self.assertTrue(
                     torch.allclose(new_posterior.mean[..., -1],
                                    new_mean_exp))
                 self.assertEqual(new_posterior.variance.shape, exp_size)
                 new_covar_exp = ((covar @ weights) @ weights).unsqueeze(-1)
                 self.assertTrue(
                     torch.allclose(new_posterior.variance[..., -1],
                                    new_covar_exp))
                 # test error
                 with self.assertRaises(ValueError):
                     ScalarizedObjective(weights=torch.rand(2, o))
Ejemplo n.º 2
0
 def test_affine_acquisition_objective(self):
     for batch_shape, m, dtype in itertools.product(
         ([], [3]), (1, 2), (torch.float, torch.double)
     ):
         offset = torch.rand(1).item()
         weights = torch.randn(m, device=self.device, dtype=dtype)
         obj = ScalarizedObjective(weights=weights, offset=offset)
         posterior = _get_test_posterior(
             batch_shape, m=m, device=self.device, dtype=dtype
         )
         mean, covar = posterior.mvn.mean, posterior.mvn.covariance_matrix
         new_posterior = obj(posterior)
         exp_size = torch.Size(batch_shape + [1, 1])
         self.assertEqual(new_posterior.mean.shape, exp_size)
         new_mean_exp = offset + mean @ weights
         self.assertTrue(torch.allclose(new_posterior.mean[..., -1], new_mean_exp))
         self.assertEqual(new_posterior.variance.shape, exp_size)
         new_covar_exp = ((covar @ weights) @ weights).unsqueeze(-1)
         self.assertTrue(
             torch.allclose(new_posterior.variance[..., -1], new_covar_exp)
         )
         # test error
         with self.assertRaises(ValueError):
             ScalarizedObjective(weights=torch.rand(2, m))
         # test evaluate
         Y = torch.rand(2, m, device=self.device, dtype=dtype)
         val = obj.evaluate(Y)
         val_expected = offset + Y @ weights
         self.assertTrue(torch.equal(val, val_expected))
Ejemplo n.º 3
0
    def test_expected_improvement_batch(self, cuda=False):
        device = torch.device("cuda") if cuda else torch.device("cpu")
        for dtype in (torch.float, torch.double):
            mean = torch.tensor([-0.5, 0.0, 0.5], device=device, dtype=dtype).view(
                3, 1, 1
            )
            variance = torch.ones(3, 1, 1, device=device, dtype=dtype)
            mm = MockModel(MockPosterior(mean=mean, variance=variance))
            module = ExpectedImprovement(model=mm, best_f=0.0)
            X = torch.empty(3, 1, 1, device=device, dtype=dtype)  # dummy
            ei = module(X)
            ei_expected = torch.tensor(
                [0.19780, 0.39894, 0.69780], device=device, dtype=dtype
            )
            self.assertTrue(torch.allclose(ei, ei_expected, atol=1e-4))
            # check for proper error if multi-output model
            mean2 = torch.rand(3, 1, 2, device=device, dtype=dtype)
            variance2 = torch.rand(3, 1, 2, device=device, dtype=dtype)
            mm2 = MockModel(MockPosterior(mean=mean2, variance=variance2))
            module2 = ExpectedImprovement(model=mm2, best_f=0.0)
            with self.assertRaises(UnsupportedError):
                module2(X)

            # test objective (single-output)
            mean = torch.tensor([[[0.5]], [[0.25]]], device=device, dtype=dtype)
            covar = torch.tensor([[[[0.16]]], [[[0.125]]]], device=device, dtype=dtype)
            mvn = MultivariateNormal(mean, covar)
            p = GPyTorchPosterior(mvn)
            mm = MockModel(p)
            weights = torch.tensor([0.5], device=device, dtype=dtype)
            obj = ScalarizedObjective(weights)
            ei = ExpectedImprovement(model=mm, best_f=0.0, objective=obj)
            X = torch.rand(2, 1, 2, device=device, dtype=dtype)
            ei_expected = torch.tensor([[0.2601], [0.1500]], device=device, dtype=dtype)
            torch.allclose(ei(X), ei_expected, atol=1e-4)

            # test objective (multi-output)
            mean = torch.tensor(
                [[[-0.25, 0.5]], [[0.2, -0.1]]], device=device, dtype=dtype
            )
            covar = torch.tensor(
                [[[0.5, 0.125], [0.125, 0.5]], [[0.25, -0.1], [-0.1, 0.25]]],
                device=device,
                dtype=dtype,
            )
            mvn = MultitaskMultivariateNormal(mean, covar)
            p = GPyTorchPosterior(mvn)
            mm = MockModel(p)
            weights = torch.tensor([2.0, 1.0], device=device, dtype=dtype)
            obj = ScalarizedObjective(weights)
            ei = ExpectedImprovement(model=mm, best_f=0.0, objective=obj)
            X = torch.rand(2, 1, 2, device=device, dtype=dtype)
            ei_expected = torch.tensor([0.6910, 0.5371], device=device, dtype=dtype)
            torch.allclose(ei(X), ei_expected, atol=1e-4)

        # test bad objective class
        with self.assertRaises(UnsupportedError):
            ExpectedImprovement(model=mm, best_f=0.0, objective=IdentityMCObjective())
Ejemplo n.º 4
0
    def test_expected_improvement(self):
        for dtype in (torch.float, torch.double):
            mean = torch.tensor([[-0.5]], device=self.device, dtype=dtype)
            variance = torch.ones(1, 1, device=self.device, dtype=dtype)
            mm = MockModel(MockPosterior(mean=mean, variance=variance))

            # basic test
            module = ExpectedImprovement(model=mm, best_f=0.0)
            X = torch.empty(1, 1, device=self.device, dtype=dtype)  # dummy
            ei = module(X)
            ei_expected = torch.tensor(0.19780,
                                       device=self.device,
                                       dtype=dtype)
            self.assertTrue(torch.allclose(ei, ei_expected, atol=1e-4))

            # test maximize
            module = ExpectedImprovement(model=mm, best_f=0.0, maximize=False)
            X = torch.empty(1, 1, device=self.device, dtype=dtype)  # dummy
            ei = module(X)
            ei_expected = torch.tensor(0.6978, device=self.device, dtype=dtype)
            self.assertTrue(torch.allclose(ei, ei_expected, atol=1e-4))
            with self.assertRaises(UnsupportedError):
                module.set_X_pending(None)

            # test objective (single-output)
            mean = torch.tensor([0.5], device=self.device, dtype=dtype)
            covar = torch.tensor([[0.16]], device=self.device, dtype=dtype)
            mvn = MultivariateNormal(mean, covar)
            p = GPyTorchPosterior(mvn)
            mm = MockModel(p)
            weights = torch.tensor([0.5], device=self.device, dtype=dtype)
            obj = ScalarizedObjective(weights)
            ei = ExpectedImprovement(model=mm, best_f=0.0, objective=obj)
            X = torch.rand(1, 2, device=self.device, dtype=dtype)
            ei_expected = torch.tensor(0.2601, device=self.device, dtype=dtype)
            torch.allclose(ei(X), ei_expected, atol=1e-4)

            # test objective (multi-output)
            mean = torch.tensor([[-0.25, 0.5]],
                                device=self.device,
                                dtype=dtype)
            covar = torch.tensor([[[0.5, 0.125], [0.125, 0.5]]],
                                 device=self.device,
                                 dtype=dtype)
            mvn = MultitaskMultivariateNormal(mean, covar)
            p = GPyTorchPosterior(mvn)
            mm = MockModel(p)
            weights = torch.tensor([2.0, 1.0], device=self.device, dtype=dtype)
            obj = ScalarizedObjective(weights)
            ei = ExpectedImprovement(model=mm, best_f=0.0, objective=obj)
            X = torch.rand(1, 2, device=self.device, dtype=dtype)
            ei_expected = torch.tensor(0.6910, device=self.device, dtype=dtype)
            torch.allclose(ei(X), ei_expected, atol=1e-4)
Ejemplo n.º 5
0
 def test_get_best_f_analytic(self):
     with self.assertRaises(NotImplementedError):
         get_best_f_analytic(training_data=self.nbd_td)
     best_f = get_best_f_analytic(training_data=self.bd_td)
     best_f_expected = self.bd_td.Y.squeeze().max()
     self.assertEqual(best_f, best_f_expected)
     with self.assertRaises(NotImplementedError):
         get_best_f_analytic(training_data=self.bd_td_mo)
     obj = ScalarizedObjective(weights=torch.rand(2))
     best_f = get_best_f_analytic(training_data=self.bd_td_mo,
                                  objective=obj)
     best_f_expected = obj.evaluate(self.bd_td_mo.Y).max()
     self.assertEqual(best_f, best_f_expected)
Ejemplo n.º 6
0
def get_botorch_objective(
    model: Model,
    objective_weights: Tensor,
    use_scalarized_objective: bool = True,
    outcome_constraints: Optional[Tuple[Tensor, Tensor]] = None,
    objective_thresholds: Optional[Tensor] = None,
    X_observed: Optional[Tensor] = None,
) -> AcquisitionObjective:
    """Constructs a BoTorch `AcquisitionObjective` object.

    Args:
        model: A BoTorch Model
        objective_weights: The objective is to maximize a weighted sum of
            the columns of f(x). These are the weights.
        use_scalarized_objective: A boolean parameter that defaults to True,
            specifying whether ScalarizedObjective should be used.
            NOTE: when using outcome_constraints, use_scalarized_objective
            will be ignored.
        outcome_constraints: A tuple of (A, b). For k outcome constraints
            and m outputs at f(x), A is (k x m) and b is (k x 1) such that
            A f(x) <= b. (Not used by single task models)
        objective_thresholds: A tensor containing thresholds forming a reference point
            from which to calculate pareto frontier hypervolume. Points that do not
            dominate the objective_thresholds contribute nothing to hypervolume.
        X_observed: Observed points that are feasible and appear in the
            objective or the constraints. None if there are no such points.

    Returns:
        A BoTorch `AcquisitionObjective` object. It will be one of:
        `ScalarizedObjective`, `LinearMCOObjective`, `ConstrainedMCObjective`.
    """
    if objective_thresholds is not None:
        nonzero_idcs = torch.nonzero(objective_weights).view(-1)
        objective_weights = objective_weights[nonzero_idcs]
        return WeightedMCMultiOutputObjective(weights=objective_weights,
                                              outcomes=nonzero_idcs.tolist())
    if X_observed is None:
        raise UnsupportedError(
            "X_observed is required to construct a BoTorch Objective.")
    if outcome_constraints:
        if use_scalarized_objective:
            logger.warning(
                "Currently cannot use ScalarizedObjective when there are outcome "
                "constraints. Ignoring (default) kwarg `use_scalarized_objective`"
                "= True. Creating ConstrainedMCObjective.")
        obj_tf = get_objective_weights_transform(objective_weights)

        def objective(samples: Tensor, X: Optional[Tensor] = None) -> Tensor:
            return obj_tf(samples)

        con_tfs = get_outcome_constraint_transforms(outcome_constraints)
        inf_cost = get_infeasible_cost(X=X_observed,
                                       model=model,
                                       objective=obj_tf)
        return ConstrainedMCObjective(objective=objective,
                                      constraints=con_tfs or [],
                                      infeasible_cost=inf_cost)
    elif use_scalarized_objective:
        return ScalarizedObjective(weights=objective_weights)
    return LinearMCObjective(weights=objective_weights)
Ejemplo n.º 7
0
    def _get_best_point_acqf(
        self,
        X_observed: Tensor,
        objective_weights: Tensor,
        mc_samples: int = 512,
        fixed_features: Optional[Dict[int, float]] = None,
        target_fidelities: Optional[Dict[int, float]] = None,
        outcome_constraints: Optional[Tuple[Tensor, Tensor]] = None,
        seed_inner: Optional[int] = None,
        qmc: bool = True,
        **kwargs: Any,
    ) -> Tuple[AcquisitionFunction, Optional[List[int]]]:

        model = self.model

        # subset model only to the outcomes we need for the optimization
        if kwargs.get("subset_model", True):
            model, objective_weights, outcome_constraints = subset_model(
                model=model,  # pyre-ignore: [6]
                objective_weights=objective_weights,
                outcome_constraints=outcome_constraints,
            )

        fixed_features = fixed_features or {}
        target_fidelities = target_fidelities or {}
        objective = ScalarizedObjective(weights=objective_weights)
        acq_function = PosteriorMean(
            model=model, objective=objective  # pyre-ignore: [6]
        )

        if self.fidelity_features:
            # we need to optimize at the target fidelities
            if any(f in self.fidelity_features for f in fixed_features):
                raise RuntimeError("Fixed features cannot also be fidelity features")
            elif not set(self.fidelity_features) == set(target_fidelities):
                raise RuntimeError(
                    "Must provide a target fidelity for every fidelity feature"
                )
            # make sure to not modify fixed_features in-place
            fixed_features = {**fixed_features, **target_fidelities}
        elif target_fidelities:
            raise RuntimeError(
                "Must specify fidelity_features in fit() when using target fidelities"
            )

        if fixed_features:
            acq_function = FixedFeatureAcquisitionFunction(
                acq_function=acq_function,
                d=X_observed.size(-1),
                columns=list(fixed_features.keys()),
                values=list(fixed_features.values()),
            )
            non_fixed_idcs = [
                i for i in range(self.Xs[0].size(-1)) if i not in fixed_features
            ]
        else:
            non_fixed_idcs = None

        return acq_function, non_fixed_idcs
Ejemplo n.º 8
0
 def test_deprecate_acqf_objective(self):
     mean = torch.zeros(1, 2)
     variance = torch.ones(1, 2)
     mm = MockModel(MockPosterior(mean=mean, variance=variance))
     obj = ScalarizedObjective(weights=torch.ones(2))
     # check for deprecation warning
     with self.assertWarns(DeprecationWarning):
         acqf = DummyAnalyticAcquisitionFunction(model=mm, objective=obj)
     # check that posterior transform was created and assigned
     self.assertIsInstance(acqf.posterior_transform, ScalarizedPosteriorTransform)
     self.assertFalse(hasattr(acqf, "objective"))
Ejemplo n.º 9
0
 def __init__(
     self,
     model: Model,
     beta: Tensor,
     weights: Tensor,
     maximize: bool = True,
 ) -> None:
     objective = ScalarizedObjective(weights=torch.tensor([0.1, 0.5]),offset=0.0)
     super().__init__(model=model,objective=objective)
     self.maximize = maximize
     self.register_buffer("beta", torch.as_tensor(beta))
     self.register_buffer("weights", torch.as_tensor(weights))
Ejemplo n.º 10
0
 def test_deprecate_objective_arg(self):
     objective = ScalarizedObjective(weights=torch.ones(1))
     post_tf = ScalarizedPosteriorTransform(weights=torch.zeros(1))
     with self.assertRaises(RuntimeError):
         _deprecate_objective_arg(posterior_transform=post_tf,
                                  objective=objective)
     with self.assertWarns(DeprecationWarning):
         new_tf = _deprecate_objective_arg(objective=objective)
     self.assertTrue(torch.equal(new_tf.weights, objective.weights))
     self.assertIsInstance(new_tf, ScalarizedPosteriorTransform)
     new_tf = _deprecate_objective_arg(posterior_transform=post_tf)
     self.assertEqual(id(new_tf), id(post_tf))
     self.assertIsNone(_deprecate_objective_arg())
     with self.assertRaises(UnsupportedError):
         _deprecate_objective_arg(objective=DummyObjective())
Ejemplo n.º 11
0
def get_botorch_objective(
    model: Model,
    objective_weights: Tensor,
    use_scalarized_objective: bool = True,
    outcome_constraints: Optional[Tuple[Tensor, Tensor]] = None,
    X_observed: Optional[Tensor] = None,
) -> AcquisitionObjective:
    """Constructs a BoTorch `AcquisitionObjective` object.

    Args:
        model: A BoTorch Model
        objective_weights: The objective is to maximize a weighted sum of
            the columns of f(x). These are the weights.
        use_scalarized_objective: A boolean parameter that defaults to True,
            specifying whether ScalarizedObjective should be used.
            NOTE: when using outcome_constraints, use_scalarized_objective
            will be ignored.
        outcome_constraints: A tuple of (A, b). For k outcome constraints
            and m outputs at f(x), A is (k x m) and b is (k x 1) such that
            A f(x) <= b. (Not used by single task models)
        X_observed: Observed points that are feasible and appear in the
            objective or the constraints. None if there are no such points.

    Returns:
        A BoTorch `AcquisitionObjective` object. It will be one of:
        `ScalarizedObjective`, `LinearMCOObjective`, `ConstrainedMCObjective`.
    """
    if X_observed is None:
        raise UnsupportedError(
            "X_observed is required to construct a BoTorch Objective.")
    if outcome_constraints:
        if use_scalarized_objective:
            logger.warning(
                "Currently cannot use ScalarizedObjective when there are outcome "
                "constraints. Ignoring (default) kwarg `use_scalarized_objective`"
                "= True. Creating ConstrainedMCObjective.")
        obj_tf = get_objective_weights_transform(objective_weights)
        con_tfs = get_outcome_constraint_transforms(outcome_constraints)
        inf_cost = get_infeasible_cost(X=X_observed,
                                       model=model,
                                       objective=obj_tf)
        return ConstrainedMCObjective(objective=obj_tf,
                                      constraints=con_tfs or [],
                                      infeasible_cost=inf_cost)
    if use_scalarized_objective:
        return ScalarizedObjective(weights=objective_weights)
    return LinearMCObjective(weights=objective_weights)
Ejemplo n.º 12
0
    def test_optimize_objective(self, mock_optimize_acqf):
        from botorch.acquisition.input_constructors import optimize_objective

        mock_model = MockModel(
            posterior=MockPosterior(mean=None, variance=None))
        bounds = torch.rand(2, len(self.bounds))

        A = torch.rand(1, bounds.shape[-1])
        b = torch.zeros([1, 1])
        idx = A[0].nonzero(as_tuple=False).squeeze()
        inequality_constraints = ((idx, -A[0, idx], -b[0, 0]), )

        with self.subTest("scalarObjective_linearConstraints"):
            _ = optimize_objective(
                model=mock_model,
                bounds=bounds,
                q=1,
                objective=ScalarizedObjective(
                    weights=torch.rand(bounds.shape[-1])),
                linear_constraints=(A, b),
                fixed_features=None,
            )

            kwargs = mock_optimize_acqf.call_args[1]
            self.assertIsInstance(kwargs["acq_function"], PosteriorMean)
            self.assertTrue(torch.equal(kwargs["bounds"], bounds))
            self.assertEqual(len(kwargs["inequality_constraints"]), 1)
            for a, b in zip(kwargs["inequality_constraints"][0],
                            inequality_constraints[0]):
                self.assertTrue(torch.equal(a, b))

        with self.subTest("mcObjective_fixedFeatures"):
            _ = optimize_objective(
                model=mock_model,
                bounds=bounds,
                q=1,
                objective=LinearMCObjective(
                    weights=torch.rand(bounds.shape[-1])),
                fixed_features={0: 0.5},
            )

            kwargs = mock_optimize_acqf.call_args[1]
            self.assertIsInstance(kwargs["acq_function"],
                                  FixedFeatureAcquisitionFunction)
            self.assertIsInstance(kwargs["acq_function"].acq_func,
                                  qSimpleRegret)
            self.assertTrue(torch.equal(kwargs["bounds"], bounds[:, 1:]))
Ejemplo n.º 13
0
 def test_get_best_f_analytic(self):
     with self.assertRaises(NotImplementedError):
         get_best_f_analytic(training_data=self.nbd_td)
     best_f = get_best_f_analytic(training_data=self.bd_td)
     best_f_expected = self.bd_td.Y.squeeze().max()
     self.assertEqual(best_f, best_f_expected)
     with self.assertRaises(NotImplementedError):
         get_best_f_analytic(training_data=self.bd_td_mo)
     weights = torch.rand(2)
     obj = ScalarizedObjective(weights=weights)
     best_f_obj = get_best_f_analytic(training_data=self.bd_td_mo,
                                      objective=obj)
     post_tf = ScalarizedPosteriorTransform(weights=weights)
     best_f_tf = get_best_f_analytic(training_data=self.bd_td_mo,
                                     posterior_transform=post_tf)
     best_f_expected = post_tf.evaluate(self.bd_td_mo.Y).max()
     self.assertEqual(best_f_obj, best_f_expected)
     self.assertEqual(best_f_tf, best_f_expected)
    def __init__(self, model: Model, options: dict) -> None:
        # MCAcquisitionFunction.__init__(self, model=model, sampler=sampler, objective=IdentityMCObjective())
        AnalyticAcquisitionFunction.__init__(
            self,
            model=model,
            objective=ScalarizedObjective(weights=torch.Tensor([1.0])))
        AcquisitionBaseTools.__init__(self,
                                      model=model,
                                      iden="Xsearch",
                                      Nrestarts_eta=options["Nrestarts_eta"])

        self.u_vec = None
        self.Nsamples_fmin = options["Nsamples_fmin"]
        self.Nrestarts = options["Nrestarts_safe"]
        self.debug = False
        self.method = options["method_safe"]
        self.disp_info_scipy_opti = options["disp_info_scipy_opti"]
        self.dim = self.model.dim
Ejemplo n.º 15
0
def _get_objective(
    model: Model,
    objective_weights: Tensor,
    outcome_constraints: Optional[Tuple[Tensor, Tensor]] = None,
    X_observed: Optional[Tensor] = None,
) -> AcquisitionObjective:
    if outcome_constraints is None:
        objective = ScalarizedObjective(weights=objective_weights)
    else:
        X_observed = torch.as_tensor(X_observed)
        obj_tf = get_objective_weights_transform(objective_weights)
        con_tfs = get_outcome_constraint_transforms(outcome_constraints)
        inf_cost = get_infeasible_cost(X=X_observed,
                                       model=model,
                                       objective=obj_tf)
        objective = ConstrainedMCObjective(objective=obj_tf,
                                           constraints=con_tfs or [],
                                           infeasible_cost=inf_cost)
    return objective
Ejemplo n.º 16
0
    def _get_best_point_acqf(
        self,
        X_observed: Tensor,
        objective_weights: Tensor,
        fixed_features: Optional[Dict[int, float]] = None,
        target_fidelities: Optional[Dict[int, float]] = None,
    ) -> Tuple[AcquisitionFunction, Optional[List[int]]]:
        fixed_features = fixed_features or {}
        target_fidelities = target_fidelities or {}
        objective = ScalarizedObjective(weights=objective_weights)
        acq_function = PosteriorMean(
            model=self.model, objective=objective  # pyre-ignore: [6]
        )

        if self.fidelity_features:
            # we need to optimize at the target fidelities
            if any(f in self.fidelity_features for f in fixed_features):
                raise RuntimeError("Fixed features cannot also be fidelity features")
            elif not set(self.fidelity_features) == set(target_fidelities):
                raise RuntimeError(
                    "Must provide a target fidelity for every fidelity feature"
                )
            # make sure to not modify fixed_features in-place
            fixed_features = {**fixed_features, **target_fidelities}
        elif target_fidelities:
            raise RuntimeError(
                "Must specify fidelity_features in fit() when using target fidelities"
            )

        if fixed_features:
            acq_function = FixedFeatureAcquisitionFunction(
                acq_function=acq_function,
                d=X_observed.size(-1),
                columns=list(fixed_features.keys()),
                values=list(fixed_features.values()),
            )
            non_fixed_idcs = [
                i for i in range(self.Xs[0].size(-1)) if i not in fixed_features
            ]
        else:
            non_fixed_idcs = None

        return acq_function, non_fixed_idcs
Ejemplo n.º 17
0
 def __init__(
     self,
     model: Model,
     beta: Tensor,
     weights: Tensor,
     # objective: ScalarizedObjective,
     X_pending: Optional[Tensor] = None,
     # objective_weights: Tensor,
     # outcome_constraints: Optional[Tuple[Tensor, Tensor]] = None,
     X_observed: Optional[Tensor] = None,
     # X_pending: Optional[Tensor] = None,
     maximize: bool = True,
 ) -> None:
     objective = ScalarizedObjective(weights=weights, offset=0.0)
     super().__init__(model=model, objective=objective)
     self.maximize = maximize
     self.X_observed = X_observed
     # self.X_pending = X_pending
     self.register_buffer("beta", torch.as_tensor(beta))
     self.register_buffer("weights", torch.as_tensor(weights))
Ejemplo n.º 18
0
def get_botorch_objective(
    model: Model,
    objective_weights: Tensor,
    outcome_constraints: Optional[Tuple[Tensor, Tensor]] = None,
    X_observed: Optional[Tensor] = None,
) -> AcquisitionObjective:
    """Constructs a BoTorch `Objective`."""
    if X_observed is None:
        raise UnsupportedError(
            "X_observed is required to construct a BoTorch Objective.")
    if outcome_constraints is None:
        objective = ScalarizedObjective(weights=objective_weights)
    else:
        obj_tf = get_objective_weights_transform(objective_weights)
        con_tfs = get_outcome_constraint_transforms(outcome_constraints)
        inf_cost = get_infeasible_cost(X=X_observed,
                                       model=model,
                                       objective=obj_tf)
        objective = ConstrainedMCObjective(objective=obj_tf,
                                           constraints=con_tfs or [],
                                           infeasible_cost=inf_cost)
    return objective
Ejemplo n.º 19
0
 def test_initialize_q_knowledge_gradient(self):
     for dtype in (torch.float, torch.double):
         mean = torch.zeros(1, 1, device=self.device, dtype=dtype)
         mm = MockModel(MockPosterior(mean=mean))
         # test error when neither specifying neither sampler nor num_fantasies
         with self.assertRaises(ValueError):
             qKnowledgeGradient(model=mm, num_fantasies=None)
         # test error when sampler and num_fantasies arg are inconsistent
         sampler = IIDNormalSampler(num_samples=16)
         with self.assertRaises(ValueError):
             qKnowledgeGradient(model=mm, num_fantasies=32, sampler=sampler)
         # test default construction
         qKG = qKnowledgeGradient(model=mm, num_fantasies=32)
         self.assertEqual(qKG.num_fantasies, 32)
         self.assertIsInstance(qKG.sampler, SobolQMCNormalSampler)
         self.assertEqual(qKG.sampler.sample_shape, torch.Size([32]))
         self.assertIsNone(qKG.objective)
         self.assertIsNone(qKG.inner_sampler)
         self.assertIsNone(qKG.X_pending)
         self.assertIsNone(qKG.current_value)
         self.assertEqual(qKG.get_augmented_q_batch_size(q=3), 32 + 3)
         # test custom construction
         obj = GenericMCObjective(lambda Y, X: Y.mean(dim=-1))
         sampler = IIDNormalSampler(num_samples=16)
         X_pending = torch.zeros(2, 2, device=self.device, dtype=dtype)
         qKG = qKnowledgeGradient(
             model=mm,
             num_fantasies=16,
             sampler=sampler,
             objective=obj,
             X_pending=X_pending,
         )
         self.assertEqual(qKG.num_fantasies, 16)
         self.assertEqual(qKG.sampler, sampler)
         self.assertEqual(qKG.sampler.sample_shape, torch.Size([16]))
         self.assertEqual(qKG.objective, obj)
         self.assertIsInstance(qKG.inner_sampler, SobolQMCNormalSampler)
         self.assertEqual(qKG.inner_sampler.sample_shape, torch.Size([128]))
         self.assertTrue(torch.equal(qKG.X_pending, X_pending))
         self.assertIsNone(qKG.current_value)
         self.assertEqual(qKG.get_augmented_q_batch_size(q=3), 16 + 3)
         # test assignment of num_fantasies from sampler if not provided
         qKG = qKnowledgeGradient(model=mm, num_fantasies=None, sampler=sampler)
         self.assertEqual(qKG.sampler.sample_shape, torch.Size([16]))
         # test custom construction with inner sampler and current value
         inner_sampler = SobolQMCNormalSampler(num_samples=256)
         current_value = torch.zeros(1, device=self.device, dtype=dtype)
         qKG = qKnowledgeGradient(
             model=mm,
             num_fantasies=8,
             objective=obj,
             inner_sampler=inner_sampler,
             current_value=current_value,
         )
         self.assertEqual(qKG.num_fantasies, 8)
         self.assertEqual(qKG.sampler.sample_shape, torch.Size([8]))
         self.assertEqual(qKG.objective, obj)
         self.assertIsInstance(qKG.inner_sampler, SobolQMCNormalSampler)
         self.assertEqual(qKG.inner_sampler, inner_sampler)
         self.assertIsNone(qKG.X_pending)
         self.assertTrue(torch.equal(qKG.current_value, current_value))
         self.assertEqual(qKG.get_augmented_q_batch_size(q=3), 8 + 3)
         # test construction with non-MC objective (ScalarizedObjective)
         qKG_s = qKnowledgeGradient(
             model=mm,
             num_fantasies=16,
             sampler=sampler,
             objective=ScalarizedObjective(weights=torch.rand(2)),
         )
         self.assertIsNone(qKG_s.inner_sampler)
         self.assertIsInstance(qKG_s.objective, ScalarizedObjective)
         # test error if no objective and multi-output model
         mean2 = torch.zeros(1, 2, device=self.device, dtype=dtype)
         mm2 = MockModel(MockPosterior(mean=mean2))
         with self.assertRaises(UnsupportedError):
             qKnowledgeGradient(model=mm2)
Ejemplo n.º 20
0
 def __init__(self, model: Model) -> None:
     super().__init__(model=model,
                      objective=ScalarizedObjective(weights=Tensor([1.0])))
Ejemplo n.º 21
0
 def test_evaluate_q_knowledge_gradient(self):
     for dtype in (torch.float, torch.double):
         # basic test
         n_f = 4
         mean = torch.rand(n_f, 1, 1, device=self.device, dtype=dtype)
         variance = torch.rand(n_f, 1, 1, device=self.device, dtype=dtype)
         mfm = MockModel(MockPosterior(mean=mean, variance=variance))
         with mock.patch.object(MockModel, "fantasize", return_value=mfm) as patch_f:
             with mock.patch(NO, new_callable=mock.PropertyMock) as mock_num_outputs:
                 mock_num_outputs.return_value = 1
                 mm = MockModel(None)
                 qKG = qKnowledgeGradient(model=mm, num_fantasies=n_f)
                 X = torch.rand(n_f + 1, 1, device=self.device, dtype=dtype)
                 val = qKG(X)
                 patch_f.assert_called_once()
                 cargs, ckwargs = patch_f.call_args
                 self.assertEqual(ckwargs["X"].shape, torch.Size([1, 1, 1]))
         self.assertTrue(torch.allclose(val, mean.mean(), atol=1e-4))
         self.assertTrue(torch.equal(qKG.extract_candidates(X), X[..., :-n_f, :]))
         # batched evaluation
         b = 2
         mean = torch.rand(n_f, b, 1, device=self.device, dtype=dtype)
         variance = torch.rand(n_f, b, 1, device=self.device, dtype=dtype)
         mfm = MockModel(MockPosterior(mean=mean, variance=variance))
         X = torch.rand(b, n_f + 1, 1, device=self.device, dtype=dtype)
         with mock.patch.object(MockModel, "fantasize", return_value=mfm) as patch_f:
             with mock.patch(NO, new_callable=mock.PropertyMock) as mock_num_outputs:
                 mock_num_outputs.return_value = 1
                 mm = MockModel(None)
                 qKG = qKnowledgeGradient(model=mm, num_fantasies=n_f)
                 val = qKG(X)
                 patch_f.assert_called_once()
                 cargs, ckwargs = patch_f.call_args
                 self.assertEqual(ckwargs["X"].shape, torch.Size([b, 1, 1]))
         self.assertTrue(
             torch.allclose(val, mean.mean(dim=0).squeeze(-1), atol=1e-4)
         )
         self.assertTrue(torch.equal(qKG.extract_candidates(X), X[..., :-n_f, :]))
         # pending points and current value
         X_pending = torch.rand(2, 1, device=self.device, dtype=dtype)
         mean = torch.rand(n_f, 1, 1, device=self.device, dtype=dtype)
         variance = torch.rand(n_f, 1, 1, device=self.device, dtype=dtype)
         mfm = MockModel(MockPosterior(mean=mean, variance=variance))
         current_value = torch.rand(1, device=self.device, dtype=dtype)
         X = torch.rand(n_f + 1, 1, device=self.device, dtype=dtype)
         with mock.patch.object(MockModel, "fantasize", return_value=mfm) as patch_f:
             with mock.patch(NO, new_callable=mock.PropertyMock) as mock_num_outputs:
                 mock_num_outputs.return_value = 1
                 mm = MockModel(None)
                 qKG = qKnowledgeGradient(
                     model=mm,
                     num_fantasies=n_f,
                     X_pending=X_pending,
                     current_value=current_value,
                 )
                 val = qKG(X)
                 patch_f.assert_called_once()
                 cargs, ckwargs = patch_f.call_args
                 self.assertEqual(ckwargs["X"].shape, torch.Size([1, 3, 1]))
         self.assertTrue(torch.allclose(val, mean.mean() - current_value, atol=1e-4))
         self.assertTrue(torch.equal(qKG.extract_candidates(X), X[..., :-n_f, :]))
         # test objective (inner MC sampling)
         objective = GenericMCObjective(objective=lambda Y, X: Y.norm(dim=-1))
         samples = torch.randn(3, 1, 1, device=self.device, dtype=dtype)
         mfm = MockModel(MockPosterior(samples=samples))
         X = torch.rand(n_f + 1, 1, device=self.device, dtype=dtype)
         with mock.patch.object(MockModel, "fantasize", return_value=mfm) as patch_f:
             with mock.patch(NO, new_callable=mock.PropertyMock) as mock_num_outputs:
                 mock_num_outputs.return_value = 1
                 mm = MockModel(None)
                 qKG = qKnowledgeGradient(
                     model=mm, num_fantasies=n_f, objective=objective
                 )
                 val = qKG(X)
                 patch_f.assert_called_once()
                 cargs, ckwargs = patch_f.call_args
                 self.assertEqual(ckwargs["X"].shape, torch.Size([1, 1, 1]))
         self.assertTrue(torch.allclose(val, objective(samples).mean(), atol=1e-4))
         self.assertTrue(torch.equal(qKG.extract_candidates(X), X[..., :-n_f, :]))
         # test non-MC objective (ScalarizedObjective)
         weights = torch.rand(2, device=self.device, dtype=dtype)
         objective = ScalarizedObjective(weights=weights)
         mean = torch.tensor([1.0, 0.5], device=self.device, dtype=dtype).expand(
             n_f, 1, 2
         )
         cov = torch.tensor(
             [[1.0, 0.1], [0.1, 0.5]], device=self.device, dtype=dtype
         ).expand(n_f, 2, 2)
         posterior = GPyTorchPosterior(MultitaskMultivariateNormal(mean, cov))
         mfm = MockModel(posterior)
         with mock.patch.object(MockModel, "fantasize", return_value=mfm) as patch_f:
             with mock.patch(NO, new_callable=mock.PropertyMock) as mock_num_outputs:
                 mock_num_outputs.return_value = 2
                 mm = MockModel(None)
                 qKG = qKnowledgeGradient(
                     model=mm, num_fantasies=n_f, objective=objective
                 )
                 val = qKG(X)
                 patch_f.assert_called_once()
                 cargs, ckwargs = patch_f.call_args
                 self.assertEqual(ckwargs["X"].shape, torch.Size([1, 1, 1]))
                 val_expected = (mean * weights).sum(-1).mean(0)
                 self.assertTrue(torch.allclose(val, val_expected))
Ejemplo n.º 22
0

def obj_grad_noisy(x):
    return obj_grad(x) + 0.1 * torch.randn(x.size())


num_seed_points = 1
train_x = 2 * torch.rand(num_seed_points, 1) - 1
# train_x = 0.0 * torch.rand(10, 1)
train_y = torch.cat([obj_noisy(train_x), obj_grad_noisy(train_x)], dim=-1)
model = GPWithDerivatives(train_X=train_x, train_Y=train_y)
# model.likelihood.noise_covar.register_constraint("raw_noise", GreaterThan(1e1))

for it in range(25):
    # Acquisition function...
    objective = ScalarizedObjective(torch.tensor([1.0, 0.0]))
    candidate_x, acq_value = optimize_acqf(
        UpperConfidenceBound(model, beta=0.1, objective=objective),
        # ExpectedImprovement(model, best_f=torch.max(train_y))
        bounds=torch.Tensor([[-1], [1]]),
        q=1,
        num_restarts=5,
        raw_samples=20,
    )
    candidate_y = torch.cat(
        [obj_noisy(candidate_x),
         obj_grad_noisy(candidate_x)], dim=-1)
    train_x = torch.cat([train_x, candidate_x])
    train_y = torch.cat([train_y, candidate_y])

    # This is currently an error "Cannot yet add fantasy observations to multitask GPs, but this is coming soon!"
Ejemplo n.º 23
0
    def test_max_posterior_sampling(self):
        batch_shapes = (torch.Size(), torch.Size([3]), torch.Size([3, 2]))
        dtypes = (torch.float, torch.double)
        for batch_shape, dtype, N, num_samples, d in itertools.product(
            batch_shapes, dtypes, (5, 6), (1, 2), (1, 2)
        ):
            tkwargs = {"device": self.device, "dtype": dtype}
            # X is `batch_shape x N x d` = batch_shape x N x 1.
            X = torch.randn(*batch_shape, N, d, **tkwargs)
            # the event shape is `num_samples x batch_shape x N x m`
            psamples = torch.zeros(num_samples, *batch_shape, N, 1, **tkwargs)
            psamples[..., 0, :] = 1.0

            # IdentityMCObjective, with replacement
            with mock.patch.object(MockPosterior, "rsample", return_value=psamples):
                mp = MockPosterior(None)
                with mock.patch.object(MockModel, "posterior", return_value=mp):
                    mm = MockModel(None)
                    MPS = MaxPosteriorSampling(mm)
                    s = MPS(X, num_samples=num_samples)
                    self.assertTrue(torch.equal(s, X[..., [0] * num_samples, :]))

            # ScalarizedMCObjective, with replacement
            with mock.patch.object(MockPosterior, "rsample", return_value=psamples):
                mp = MockPosterior(None)
                with mock.patch.object(MockModel, "posterior", return_value=mp):
                    mm = MockModel(None)
                    with mock.patch.object(
                        ScalarizedObjective, "forward", return_value=mp
                    ):
                        obj = ScalarizedObjective(torch.rand(2, **tkwargs))
                        MPS = MaxPosteriorSampling(mm, objective=obj)
                        s = MPS(X, num_samples=num_samples)
                        self.assertTrue(torch.equal(s, X[..., [0] * num_samples, :]))

            # without replacement
            psamples[..., 1, 0] = 1e-6
            with mock.patch.object(MockPosterior, "rsample", return_value=psamples):
                mp = MockPosterior(None)
                with mock.patch.object(MockModel, "posterior", return_value=mp):
                    mm = MockModel(None)
                    MPS = MaxPosteriorSampling(mm, replacement=False)
                    if len(batch_shape) > 1:
                        with self.assertRaises(NotImplementedError):
                            MPS(X, num_samples=num_samples)
                    else:
                        s = MPS(X, num_samples=num_samples)
                        # order is not guaranteed, need to sort
                        self.assertTrue(
                            torch.equal(
                                torch.sort(s, dim=-2).values,
                                torch.sort(X[..., :num_samples, :], dim=-2).values,
                            )
                        )

            # ScalarizedMCObjective, without replacement
            with mock.patch.object(MockPosterior, "rsample", return_value=psamples):
                mp = MockPosterior(None)
                with mock.patch.object(MockModel, "posterior", return_value=mp):
                    mm = MockModel(None)
                    with mock.patch.object(
                        ScalarizedObjective, "forward", return_value=mp
                    ):
                        obj = ScalarizedObjective(torch.rand(2, **tkwargs))
                        MPS = MaxPosteriorSampling(mm, objective=obj, replacement=False)
                        if len(batch_shape) > 1:
                            with self.assertRaises(NotImplementedError):
                                MPS(X, num_samples=num_samples)
                        else:
                            s = MPS(X, num_samples=num_samples)
                            # order is not guaranteed, need to sort
                            self.assertTrue(
                                torch.equal(
                                    torch.sort(s, dim=-2).values,
                                    torch.sort(X[..., :num_samples, :], dim=-2).values,
                                )
                            )
Ejemplo n.º 24
0
    def test_q_neg_int_post_variance(self):
        no = "botorch.utils.testing.MockModel.num_outputs"
        for dtype in (torch.float, torch.double):
            # basic test
            mean = torch.zeros(4, 1, device=self.device, dtype=dtype)
            variance = torch.rand(4, 1, device=self.device, dtype=dtype)
            mc_points = torch.rand(10, 1, device=self.device, dtype=dtype)
            mfm = MockModel(MockPosterior(mean=mean, variance=variance))
            with mock.patch.object(MockModel, "fantasize", return_value=mfm):
                with mock.patch(
                        no,
                        new_callable=mock.PropertyMock) as mock_num_outputs:
                    mock_num_outputs.return_value = 1
                    # TODO: Make this work with arbitrary models
                    mm = MockModel(None)
                    qNIPV = qNegIntegratedPosteriorVariance(
                        model=mm, mc_points=mc_points)
                    X = torch.empty(1, 1, device=self.device,
                                    dtype=dtype)  # dummy
                    val = qNIPV(X)
                    self.assertTrue(
                        torch.allclose(val, -(variance.mean()), atol=1e-4))
            # batched model
            mean = torch.zeros(2, 4, 1, device=self.device, dtype=dtype)
            variance = torch.rand(2, 4, 1, device=self.device, dtype=dtype)
            mc_points = torch.rand(2, 10, 1, device=self.device, dtype=dtype)
            mfm = MockModel(MockPosterior(mean=mean, variance=variance))
            with mock.patch.object(MockModel, "fantasize", return_value=mfm):
                with mock.patch(
                        no,
                        new_callable=mock.PropertyMock) as mock_num_outputs:
                    mock_num_outputs.return_value = 1
                    # TODO: Make this work with arbitrary models
                    mm = MockModel(None)
                    qNIPV = qNegIntegratedPosteriorVariance(
                        model=mm, mc_points=mc_points)
                    # TODO: Allow broadcasting for batch evaluation
                    X = torch.empty(2, 1, 1, device=self.device,
                                    dtype=dtype)  # dummy
                    val = qNIPV(X)
                    val_exp = -variance.mean(dim=-2).squeeze(-1)
                    self.assertTrue(torch.allclose(val, val_exp, atol=1e-4))
            # multi-output model
            mean = torch.zeros(4, 2, device=self.device, dtype=dtype)
            variance = torch.rand(4, 2, device=self.device, dtype=dtype)
            cov = torch.diag_embed(variance.view(-1))
            f_posterior = GPyTorchPosterior(
                MultitaskMultivariateNormal(mean, cov))
            mc_points = torch.rand(10, 1, device=self.device, dtype=dtype)
            mfm = MockModel(f_posterior)
            with mock.patch.object(MockModel, "fantasize", return_value=mfm):
                with mock.patch(
                        no,
                        new_callable=mock.PropertyMock) as mock_num_outputs:
                    mock_num_outputs.return_value = 2
                    mm = MockModel(None)

                    # check error if objective is not ScalarizedObjective
                    with self.assertRaises(UnsupportedError):
                        qNegIntegratedPosteriorVariance(
                            model=mm,
                            mc_points=mc_points,
                            objective=IdentityMCObjective(),
                        )

                    weights = torch.tensor([0.5, 0.5],
                                           device=self.device,
                                           dtype=dtype)
                    qNIPV = qNegIntegratedPosteriorVariance(
                        model=mm,
                        mc_points=mc_points,
                        objective=ScalarizedObjective(weights=weights),
                    )
                    X = torch.empty(1, 1, device=self.device,
                                    dtype=dtype)  # dummy
                    val = qNIPV(X)
                    self.assertTrue(
                        torch.allclose(val, -0.5 * variance.mean(), atol=1e-4))
            # batched multi-output model
            mean = torch.zeros(4, 3, 1, 2, device=self.device, dtype=dtype)
            variance = torch.rand(4, 3, 1, 2, device=self.device, dtype=dtype)
            cov = torch.diag_embed(variance.view(4, 3, -1))
            f_posterior = GPyTorchPosterior(
                MultitaskMultivariateNormal(mean, cov))
            mc_points = torch.rand(4, 1, device=self.device, dtype=dtype)
            mfm = MockModel(f_posterior)
            with mock.patch.object(MockModel, "fantasize", return_value=mfm):
                with mock.patch(
                        no,
                        new_callable=mock.PropertyMock) as mock_num_outputs:
                    mock_num_outputs.return_value = 2
                    mm = MockModel(None)
                    weights = torch.tensor([0.5, 0.5],
                                           device=self.device,
                                           dtype=dtype)
                    qNIPV = qNegIntegratedPosteriorVariance(
                        model=mm,
                        mc_points=mc_points,
                        objective=ScalarizedObjective(weights=weights),
                    )
                    X = torch.empty(3, 1, 1, device=self.device,
                                    dtype=dtype)  # dummy
                    val = qNIPV(X)
                    val_exp = -0.5 * variance.mean(dim=0).view(3,
                                                               -1).mean(dim=-1)
                    self.assertTrue(torch.allclose(val, val_exp, atol=1e-4))
Ejemplo n.º 25
0
    def test_q_expected_improvement(self):
        for dtype in (torch.float, torch.double):
            # the event shape is `b x q x t` = 1 x 1 x 1
            samples = torch.zeros(1, 1, 1, device=self.device, dtype=dtype)
            mm = MockModel(MockPosterior(samples=samples))
            # X is `q x d` = 1 x 1. X is a dummy and unused b/c of mocking
            X = torch.zeros(1, 1, device=self.device, dtype=dtype)

            # basic test
            sampler = IIDNormalSampler(num_samples=2)
            acqf = qExpectedImprovement(model=mm, best_f=0, sampler=sampler)
            res = acqf(X)
            self.assertEqual(res.item(), 0.0)

            # test shifting best_f value
            acqf = qExpectedImprovement(model=mm, best_f=-1, sampler=sampler)
            res = acqf(X)
            self.assertEqual(res.item(), 1.0)

            # test size verification of best_f
            with self.assertRaises(ValueError):
                qExpectedImprovement(
                    model=mm, best_f=torch.zeros(2, device=self.device, dtype=dtype)
                )

            # basic test, no resample
            sampler = IIDNormalSampler(num_samples=2, seed=12345)
            acqf = qExpectedImprovement(model=mm, best_f=0, sampler=sampler)
            res = acqf(X)
            self.assertEqual(res.item(), 0.0)
            self.assertEqual(acqf.sampler.base_samples.shape, torch.Size([2, 1, 1, 1]))
            bs = acqf.sampler.base_samples.clone()
            res = acqf(X)
            self.assertTrue(torch.equal(acqf.sampler.base_samples, bs))

            # basic test, qmc, no resample
            sampler = SobolQMCNormalSampler(num_samples=2)
            acqf = qExpectedImprovement(model=mm, best_f=0, sampler=sampler)
            res = acqf(X)
            self.assertEqual(res.item(), 0.0)
            self.assertEqual(acqf.sampler.base_samples.shape, torch.Size([2, 1, 1, 1]))
            bs = acqf.sampler.base_samples.clone()
            acqf(X)
            self.assertTrue(torch.equal(acqf.sampler.base_samples, bs))

            # basic test, qmc, resample
            sampler = SobolQMCNormalSampler(num_samples=2, resample=True)
            acqf = qExpectedImprovement(model=mm, best_f=0, sampler=sampler)
            res = acqf(X)
            self.assertEqual(res.item(), 0.0)
            self.assertEqual(acqf.sampler.base_samples.shape, torch.Size([2, 1, 1, 1]))
            bs = acqf.sampler.base_samples.clone()
            acqf(X)
            self.assertFalse(torch.equal(acqf.sampler.base_samples, bs))

            # basic test for X_pending and warning
            acqf.set_X_pending()
            self.assertIsNone(acqf.X_pending)
            acqf.set_X_pending(None)
            self.assertIsNone(acqf.X_pending)
            acqf.set_X_pending(X)
            self.assertEqual(acqf.X_pending, X)
            res = acqf(X)
            X2 = torch.zeros(
                1, 1, 1, device=self.device, dtype=dtype, requires_grad=True
            )
            with warnings.catch_warnings(record=True) as ws, settings.debug(True):
                acqf.set_X_pending(X2)
                self.assertEqual(acqf.X_pending, X2)
                self.assertEqual(len(ws), 1)
                self.assertTrue(issubclass(ws[-1].category, BotorchWarning))

        # test bad objective type
        obj = ScalarizedObjective(
            weights=torch.rand(2, device=self.device, dtype=dtype)
        )
        with self.assertRaises(UnsupportedError):
            qExpectedImprovement(model=mm, best_f=0, sampler=sampler, objective=obj)
Ejemplo n.º 26
0
    def test_KnowledgeGradient_helpers(self):
        model = KnowledgeGradient()
        model.fit(
            Xs=self.Xs,
            Ys=self.Ys,
            Yvars=self.Yvars,
            search_space_digest=SearchSpaceDigest(
                feature_names=self.feature_names,
                bounds=self.bounds,
            ),
            metric_names=self.metric_names,
        )

        # test _instantiate_KG
        objective = ScalarizedObjective(weights=self.objective_weights)

        # test acquisition setting
        acq_function = _instantiate_KG(model=model.model,
                                       objective=objective,
                                       n_fantasies=10,
                                       qmc=True)
        self.assertIsInstance(acq_function.sampler, SobolQMCNormalSampler)
        self.assertIsInstance(acq_function.objective, ScalarizedObjective)
        self.assertEqual(acq_function.num_fantasies, 10)

        acq_function = _instantiate_KG(model=model.model,
                                       objective=objective,
                                       n_fantasies=10,
                                       qmc=False)
        self.assertIsInstance(acq_function.sampler, IIDNormalSampler)

        acq_function = _instantiate_KG(model=model.model,
                                       objective=objective,
                                       qmc=False)
        self.assertIsNone(acq_function.inner_sampler)

        acq_function = _instantiate_KG(model=model.model,
                                       objective=objective,
                                       qmc=True,
                                       X_pending=self.X_dummy)
        self.assertIsNone(acq_function.inner_sampler)
        self.assertTrue(torch.equal(acq_function.X_pending, self.X_dummy))

        # test _get_best_point_acqf
        acq_function, non_fixed_idcs = model._get_best_point_acqf(
            objective_weights=self.objective_weights,
            outcome_constraints=self.outcome_constraints,
            X_observed=self.X_dummy,
        )
        self.assertIsInstance(acq_function, qSimpleRegret)
        self.assertIsInstance(acq_function.sampler, SobolQMCNormalSampler)
        self.assertIsNone(non_fixed_idcs)

        acq_function, non_fixed_idcs = model._get_best_point_acqf(
            objective_weights=self.objective_weights,
            outcome_constraints=self.outcome_constraints,
            X_observed=self.X_dummy,
            qmc=False,
        )
        self.assertIsInstance(acq_function.sampler, IIDNormalSampler)
        self.assertIsNone(non_fixed_idcs)

        with self.assertRaises(RuntimeError):
            model._get_best_point_acqf(
                objective_weights=self.objective_weights,
                outcome_constraints=self.outcome_constraints,
                X_observed=self.X_dummy,
                target_fidelities={1: 1.0},
            )

        # multi-fidelity tests

        model = KnowledgeGradient()
        model.fit(
            Xs=self.Xs,
            Ys=self.Ys,
            Yvars=self.Yvars,
            search_space_digest=SearchSpaceDigest(
                feature_names=self.feature_names,
                bounds=self.bounds,
                fidelity_features=[-1],
            ),
            metric_names=self.metric_names,
        )

        acq_function = _instantiate_KG(
            model=model.model,
            objective=objective,
            target_fidelities={2: 1.0},
            current_value=0,
        )
        self.assertIsInstance(acq_function, qMultiFidelityKnowledgeGradient)

        acq_function = _instantiate_KG(
            model=model.model,
            objective=LinearMCObjective(weights=self.objective_weights),
        )
        self.assertIsInstance(acq_function.inner_sampler,
                              SobolQMCNormalSampler)

        # test error that target fidelity and fidelity weight indices must match
        with self.assertRaises(RuntimeError):
            _instantiate_KG(
                model=model.model,
                objective=objective,
                target_fidelities={1: 1.0},
                fidelity_weights={2: 1.0},
                current_value=0,
            )

        # test _get_best_point_acqf
        acq_function, non_fixed_idcs = model._get_best_point_acqf(
            objective_weights=self.objective_weights,
            outcome_constraints=self.outcome_constraints,
            X_observed=self.X_dummy,
            target_fidelities={2: 1.0},
        )
        self.assertIsInstance(acq_function, FixedFeatureAcquisitionFunction)
        self.assertIsInstance(acq_function.acq_func.sampler,
                              SobolQMCNormalSampler)
        self.assertEqual(non_fixed_idcs, [0, 1])

        acq_function, non_fixed_idcs = model._get_best_point_acqf(
            objective_weights=self.objective_weights,
            outcome_constraints=self.outcome_constraints,
            X_observed=self.X_dummy,
            target_fidelities={2: 1.0},
            qmc=False,
        )
        self.assertIsInstance(acq_function, FixedFeatureAcquisitionFunction)
        self.assertIsInstance(acq_function.acq_func.sampler, IIDNormalSampler)
        self.assertEqual(non_fixed_idcs, [0, 1])

        # test error that fixed features are provided
        with self.assertRaises(RuntimeError):
            model._get_best_point_acqf(
                objective_weights=self.objective_weights,
                outcome_constraints=self.outcome_constraints,
                X_observed=self.X_dummy,
                qmc=False,
            )

        # test error if fixed features are also fidelity features
        with self.assertRaises(RuntimeError):
            model._get_best_point_acqf(
                objective_weights=self.objective_weights,
                outcome_constraints=self.outcome_constraints,
                X_observed=self.X_dummy,
                fixed_features={2: 2.0},
                target_fidelities={2: 1.0},
                qmc=False,
            )
Ejemplo n.º 27
0
    def test_qMS_init(self):
        d = 2
        q = 1
        num_data = 3
        q_batch_sizes = [1, 1, 1]
        num_fantasies = [2, 2, 1]
        t_batch_size = [2]
        for dtype in (torch.float, torch.double):
            bounds = torch.tensor([[0], [1]], device=self.device, dtype=dtype)
            bounds = bounds.repeat(1, d)
            train_X = torch.rand(num_data, d, device=self.device, dtype=dtype)
            train_Y = torch.rand(num_data, 1, device=self.device, dtype=dtype)
            model = SingleTaskGP(train_X, train_Y)

            # exactly one of samplers or num_fantasies
            with self.assertRaises(UnsupportedError):
                qMultiStepLookahead(
                    model=model,
                    batch_sizes=q_batch_sizes,
                    valfunc_cls=[qExpectedImprovement] * 4,
                    valfunc_argfacs=[make_best_f] * 4,
                    inner_mc_samples=[2] * 4,
                )

            # cannot use qMS as its own valfunc_cls
            with self.assertRaises(UnsupportedError):
                qMultiStepLookahead(
                    model=model,
                    batch_sizes=q_batch_sizes,
                    valfunc_cls=[qMultiStepLookahead] * 4,
                    valfunc_argfacs=[make_best_f] * 4,
                    num_fantasies=num_fantasies,
                    inner_mc_samples=[2] * 4,
                )

            # construct using samplers
            samplers = [
                SobolQMCNormalSampler(num_samples=nf,
                                      resample=False,
                                      collapse_batch_dims=True)
                for nf in num_fantasies
            ]
            qMS = qMultiStepLookahead(
                model=model,
                batch_sizes=q_batch_sizes,
                valfunc_cls=[qExpectedImprovement] * 4,
                valfunc_argfacs=[make_best_f] * 4,
                inner_mc_samples=[2] * 4,
                samplers=samplers,
            )
            self.assertEqual(qMS.num_fantasies, num_fantasies)

            # use default valfunc_cls, valfun_argfacs, inner_mc_samples
            qMS = qMultiStepLookahead(
                model=model,
                batch_sizes=q_batch_sizes,
                samplers=samplers,
            )
            self.assertEqual(len(qMS._valfunc_cls), 4)
            self.assertEqual(len(qMS.inner_samplers), 4)
            self.assertEqual(len(qMS._valfunc_argfacs), 4)

            # _construct_inner_samplers error catching tests below
            # AnalyticAcquisitionFunction with MCAcquisitionObjective
            with self.assertRaises(UnsupportedError):
                qMultiStepLookahead(
                    model=model,
                    objective=IdentityMCObjective(),
                    batch_sizes=q_batch_sizes,
                    valfunc_cls=[ExpectedImprovement] * 4,
                    valfunc_argfacs=[make_best_f] * 4,
                    num_fantasies=num_fantasies,
                )
            # AnalyticAcquisitionFunction and q > 1
            with self.assertRaises(UnsupportedError):
                qMultiStepLookahead(
                    model=model,
                    batch_sizes=[2, 2, 2],
                    valfunc_cls=[ExpectedImprovement] * 4,
                    valfunc_argfacs=[make_best_f] * 4,
                    num_fantasies=num_fantasies,
                    inner_mc_samples=[2] * 4,
                )
            # AnalyticAcquisitionFunction and inner_mc_samples
            with self.assertWarns(Warning):
                qMultiStepLookahead(
                    model=model,
                    batch_sizes=q_batch_sizes,
                    valfunc_cls=[ExpectedImprovement] * 4,
                    valfunc_argfacs=[make_best_f] * 4,
                    num_fantasies=num_fantasies,
                    inner_mc_samples=[2] * 4,
                )
            # MCAcquisitionFunction and non MCAcquisitionObjective
            with self.assertRaises(UnsupportedError):
                qMultiStepLookahead(
                    model=model,
                    objective=ScalarizedObjective(weights=torch.tensor([1.0])),
                    batch_sizes=[2, 2, 2],
                    valfunc_cls=[qExpectedImprovement] * 4,
                    valfunc_argfacs=[make_best_f] * 4,
                    num_fantasies=num_fantasies,
                    inner_mc_samples=[2] * 4,
                )

            # test warmstarting
            qMS = qMultiStepLookahead(
                model=model,
                batch_sizes=q_batch_sizes,
                samplers=samplers,
            )
            q_prime = qMS.get_augmented_q_batch_size(q)
            eval_X = torch.rand(t_batch_size + [q_prime, d])
            warmstarted_X = warmstart_multistep(
                acq_function=qMS,
                bounds=bounds,
                num_restarts=5,
                raw_samples=10,
                full_optimizer=eval_X,
            )
            self.assertEqual(warmstarted_X.shape, torch.Size([5, q_prime, d]))
Ejemplo n.º 28
0
torch_to_jax = lambda x: x.numpy()

num_seed_points = 7
train_x = jax_to_torch([
    flatten(init_random_params(rp.poop(), (-1, 28 * 28))[1]) @ basis for _ in range(num_seed_points)
])
train_y = jax_to_torch([loss_and_grad(torch_to_jax(train_x[i, :])) for i in range(num_seed_points)])

model = GPWithDerivatives(train_X=train_x, train_Y=train_y)
# model.likelihood.noise_covar.register_constraint("raw_noise", GreaterThan(1e1))

for it in range(25):
  t0 = time.time()

  # Negate the first element of the objective, since botorch maximizes.
  objective = ScalarizedObjective(torch.tensor([-1.0] + [0.0] * dim_basis))

  # q: number of candidates.
  q = 10

  # candidate_x has shape (q, dim_basis)
  t1 = time.time()
  candidate_x, acq_value = optimize_acqf(
      # UpperConfidenceBound(model, beta=0.1, objective=objective),
      qUpperConfidenceBound(model, beta=0.1, objective=objective),
      bounds=torch.Tensor([[-1] * dim_basis, [1] * dim_basis]),
      q=q,
      # Not sure why these are necessary:
      num_restarts=1,
      raw_samples=1,
  )
Ejemplo n.º 29
0
    def test_KnowledgeGradient(self):

        model = KnowledgeGradient()
        model.fit(
            Xs=self.Xs,
            Ys=self.Ys,
            Yvars=self.Yvars,
            search_space_digest=SearchSpaceDigest(
                feature_names=self.feature_names,
                bounds=self.bounds,
            ),
            metric_names=self.metric_names,
        )

        n = 2

        X_dummy = torch.rand(1, n, 4, dtype=self.dtype, device=self.device)
        acq_dummy = torch.tensor(0.0, dtype=self.dtype, device=self.device)

        with mock.patch(self.optimize_acqf) as mock_optimize_acqf:
            mock_optimize_acqf.side_effect = [(X_dummy, acq_dummy)]
            Xgen, wgen, _, __ = model.gen(
                n=n,
                bounds=self.bounds,
                objective_weights=self.objective_weights,
                outcome_constraints=None,
                linear_constraints=None,
                model_gen_options={
                    "acquisition_function_kwargs": self.acq_options,
                    "optimizer_kwargs": self.optimizer_options,
                },
            )
            self.assertTrue(torch.equal(Xgen, X_dummy.cpu()))
            self.assertTrue(torch.equal(wgen, torch.ones(n, dtype=self.dtype)))

            # called once, the best point call is not caught by mock
            mock_optimize_acqf.assert_called_once()

        ini_dummy = torch.rand(10, 32, 3, dtype=self.dtype, device=self.device)
        optimizer_options2 = {
            "num_restarts": 1,
            "raw_samples": 1,
            "maxiter": 5,
            "batch_limit": 1,
            "partial_restarts": 2,
        }
        with mock.patch(
                "ax.models.torch.botorch_kg.gen_one_shot_kg_initial_conditions",
                return_value=ini_dummy,
        ) as mock_warmstart_initialization:
            Xgen, wgen, _, __ = model.gen(
                n=n,
                bounds=self.bounds,
                objective_weights=self.objective_weights,
                outcome_constraints=None,
                linear_constraints=None,
                model_gen_options={
                    "acquisition_function_kwargs": self.acq_options,
                    "optimizer_kwargs": optimizer_options2,
                },
            )
            mock_warmstart_initialization.assert_called_once()

        obj = ScalarizedObjective(weights=self.objective_weights)
        dummy_acq = PosteriorMean(model=model.model, objective=obj)
        with mock.patch("ax.models.torch.utils.PosteriorMean",
                        return_value=dummy_acq) as mock_posterior_mean:
            Xgen, wgen, _, __ = model.gen(
                n=n,
                bounds=self.bounds,
                objective_weights=self.objective_weights,
                outcome_constraints=None,
                linear_constraints=None,
                model_gen_options={
                    "acquisition_function_kwargs": self.acq_options,
                    "optimizer_kwargs": optimizer_options2,
                },
            )
            self.assertEqual(mock_posterior_mean.call_count, 2)

        # Check best point selection within bounds (some numerical tolerance)
        xbest = model.best_point(bounds=self.bounds,
                                 objective_weights=self.objective_weights)
        lb = torch.tensor([b[0] for b in self.bounds]) - 1e-5
        ub = torch.tensor([b[1] for b in self.bounds]) + 1e-5
        self.assertTrue(torch.all(xbest <= ub))
        self.assertTrue(torch.all(xbest >= lb))

        # test error message
        linear_constraints = (
            torch.tensor([[0.0, 0.0, 0.0], [0.0, 1.0, 0.0]]),
            torch.tensor([[0.5], [1.0]]),
        )
        with self.assertRaises(UnsupportedError):
            Xgen, wgen = model.gen(
                n=n,
                bounds=self.bounds,
                objective_weights=self.objective_weights,
                outcome_constraints=None,
                linear_constraints=linear_constraints,
            )

        # test input warping
        self.assertFalse(model.use_input_warping)
        model = KnowledgeGradient(use_input_warping=True)
        model.fit(
            Xs=self.Xs,
            Ys=self.Ys,
            Yvars=self.Yvars,
            search_space_digest=SearchSpaceDigest(
                feature_names=self.feature_names,
                bounds=self.bounds,
            ),
            metric_names=self.metric_names,
        )
        self.assertTrue(model.use_input_warping)
        self.assertTrue(hasattr(model.model, "input_transform"))
        self.assertIsInstance(model.model.input_transform, Warp)

        # test loocv pseudo likelihood
        self.assertFalse(model.use_loocv_pseudo_likelihood)
        model = KnowledgeGradient(use_loocv_pseudo_likelihood=True)
        model.fit(
            Xs=self.Xs,
            Ys=self.Ys,
            Yvars=self.Yvars,
            search_space_digest=SearchSpaceDigest(
                feature_names=self.feature_names,
                bounds=self.bounds,
            ),
            metric_names=self.metric_names,
        )
        self.assertTrue(model.use_loocv_pseudo_likelihood)
Ejemplo n.º 30
0
    def test_KnowledgeGradient(self):

        model = KnowledgeGradient()
        model.fit(
            Xs=self.Xs,
            Ys=self.Ys,
            Yvars=self.Yvars,
            bounds=self.bounds,
            feature_names=self.feature_names,
            metric_names=self.metric_names,
            task_features=[],
            fidelity_features=[],
        )

        n = 2

        best_point_dummy = torch.rand(1,
                                      3,
                                      dtype=self.dtype,
                                      device=self.device)
        X_dummy = torch.rand(1, n, 4, dtype=self.dtype, device=self.device)
        acq_dummy = torch.tensor(0.0, dtype=self.dtype, device=self.device)

        with mock.patch(self.optimize_acqf) as mock_optimize_acqf:
            mock_optimize_acqf.side_effect = [
                (best_point_dummy, None),
                (X_dummy, acq_dummy),
            ]
            Xgen, wgen, _ = model.gen(
                n=n,
                bounds=self.bounds,
                objective_weights=self.objective_weights,
                outcome_constraints=None,
                linear_constraints=None,
                model_gen_options={
                    "acquisition_function_kwargs": self.acq_options,
                    "optimizer_kwargs": self.optimizer_options,
                },
            )
            self.assertTrue(torch.equal(Xgen, X_dummy.cpu()))
            self.assertTrue(torch.equal(wgen, torch.ones(n, dtype=self.dtype)))
            mock_optimize_acqf.assert_called(
            )  # called twice, once for best_point

        ini_dummy = torch.rand(10, 32, 3, dtype=self.dtype, device=self.device)
        optimizer_options2 = {
            "num_restarts": 1,
            "raw_samples": 1,
            "maxiter": 5,
            "batch_limit": 1,
            "partial_restarts": 2,
        }
        with mock.patch(
                "ax.models.torch.botorch_kg.gen_one_shot_kg_initial_conditions",
                return_value=ini_dummy,
        ) as mock_warmstart_initialization:
            Xgen, wgen, _ = model.gen(
                n=n,
                bounds=self.bounds,
                objective_weights=self.objective_weights,
                outcome_constraints=None,
                linear_constraints=None,
                model_gen_options={
                    "acquisition_function_kwargs": self.acq_options,
                    "optimizer_kwargs": optimizer_options2,
                },
            )
            mock_warmstart_initialization.assert_called_once()

        obj = ScalarizedObjective(weights=self.objective_weights)
        dummy_acq = PosteriorMean(model=model.model, objective=obj)
        with mock.patch("ax.models.torch.botorch_kg.PosteriorMean",
                        return_value=dummy_acq) as mock_posterior_mean:
            Xgen, wgen, _ = model.gen(
                n=n,
                bounds=self.bounds,
                objective_weights=self.objective_weights,
                outcome_constraints=None,
                linear_constraints=None,
                model_gen_options={
                    "acquisition_function_kwargs": self.acq_options,
                    "optimizer_kwargs": optimizer_options2,
                },
            )
            self.assertEqual(mock_posterior_mean.call_count, 2)

        # Check best point selection
        X_dummy = torch.rand(3)
        acq_dummy = torch.tensor(0.0)
        with mock.patch(self.optimize_acqf,
                        return_value=(X_dummy,
                                      acq_dummy)) as mock_optimize_acqf:
            xbest = model.best_point(bounds=self.bounds,
                                     objective_weights=self.objective_weights)
            self.assertTrue(torch.equal(xbest, X_dummy))
            mock_optimize_acqf.assert_called_once()

        # test error message
        linear_constraints = (
            torch.tensor([[0.0, 0.0, 0.0], [0.0, 1.0, 0.0]]),
            torch.tensor([[0.5], [1.0]]),
        )
        with self.assertRaises(UnsupportedError):
            Xgen, wgen = model.gen(
                n=n,
                bounds=self.bounds,
                objective_weights=self.objective_weights,
                outcome_constraints=None,
                linear_constraints=linear_constraints,
            )