Exemple #1
0
 def test_optimize_acqf_list_empty_list(self):
     with self.assertRaises(ValueError):
         optimize_acqf_list(
             acq_function_list=[],
             bounds=torch.stack([torch.zeros(3), 4 * torch.ones(3)]),
             num_restarts=2,
             raw_samples=10,
         )
Exemple #2
0
def optimize_qparego_and_get_observation(model, train_obj, sampler):
    """Samples a set of random weights for each candidate in the batch, performs sequential greedy optimization
    of the qParEGO acquisition function, and returns a new candidate and observation."""
    acq_func_list = []
    for _ in range(BATCH_SIZE):
        weights = sample_simplex(problem.num_objectives, **tkwargs).squeeze()
        objective = GenericMCObjective(
            get_chebyshev_scalarization(weights=weights, Y=train_obj))
        acq_func = qExpectedImprovement(  # pyre-ignore: [28]
            model=model,
            objective=objective,
            best_f=objective(train_obj).max(),
            sampler=sampler,
        )
        acq_func_list.append(acq_func)
    # optimize
    candidates, _ = optimize_acqf_list(
        acq_function_list=acq_func_list,
        bounds=standard_bounds,
        num_restarts=NUM_RESTARTS,
        raw_samples=RAW_SAMPLES,  # used for intialization heuristic
        options={
            "batch_limit": 5,
            "maxiter": 200
        },
    )
    # observe new values
    new_x = unnormalize(candidates.detach(), bounds=problem.bounds)
    new_obj = problem(new_x)
    return new_x, new_obj
Exemple #3
0
def scipy_optimizer_list(
    acq_function_list: List[AcquisitionFunction],
    bounds: Tensor,
    inequality_constraints: Optional[List[Tuple[Tensor, Tensor,
                                                float]]] = None,
    fixed_features: Optional[Dict[int, float]] = None,
    rounding_func: Optional[Callable[[Tensor], Tensor]] = None,
    **kwargs: Any,
) -> Tuple[Tensor, Tensor]:
    r"""Sequential optimizer using scipy's minimize module on a numpy-adaptor.

    The ith acquisition in the sequence uses the ith given acquisition_function.

    Args:
        acq_function_list: A list of botorch AcquisitionFunctions,
            optimized sequentially.
        bounds: A `2 x d`-dim tensor, where `bounds[0]` (`bounds[1]`) are the
            lower (upper) bounds of the feasible hyperrectangle.
        n: The number of candidates to generate.
        inequality constraints: A list of tuples (indices, coefficients, rhs),
            with each tuple encoding an inequality constraint of the form
            `\sum_i (X[indices[i]] * coefficients[i]) >= rhs`
        fixed_features: A map {feature_index: value} for features that should
            be fixed to a particular value during generation.
        rounding_func: A function that rounds an optimization result
            appropriately (i.e., according to `round-trip` transformations).

    Returns:
        2-element tuple containing

        - A `n x d`-dim tensor of generated candidates.
        - A `n`-dim tensor of conditional acquisition
          values, where `i`-th element is the expected acquisition value
          conditional on having observed candidates `0,1,...,i-1`.
    """
    num_restarts: int = kwargs.get("num_restarts", 20)
    raw_samples: int = kwargs.get("num_raw_samples", 50 * num_restarts)

    # use SLSQP by default for small problems since it yields faster wall times
    if "method" not in kwargs:
        kwargs["method"] = "SLSQP"
    X, expected_acquisition_value = optimize_acqf_list(
        acq_function_list=acq_function_list,
        bounds=bounds,
        num_restarts=num_restarts,
        raw_samples=raw_samples,
        options=kwargs,
        inequality_constraints=inequality_constraints,
        fixed_features=fixed_features,
        post_processing_func=rounding_func,
    )
    return X, expected_acquisition_value
def optimize_qparego_and_get_observation(model, train_obj, train_con, sampler, obj_func, time_list, global_start_time):
    """Samples a set of random weights for each candidate in the batch, performs sequential greedy optimization
    of the qParEGO acquisition function, and returns a new candidate and observation."""
    acq_func_list = []
    for _ in range(1):
        # sample random weights
        weights = sample_simplex(problem.num_objs, **tkwargs).squeeze()
        # construct augmented Chebyshev scalarization
        scalarization = get_chebyshev_scalarization(weights=weights, Y=train_obj)
        # initialize ConstrainedMCObjective
        constrained_objective = get_constrained_mc_objective(train_obj=train_obj, train_con=train_con, scalarization=scalarization)
        train_y = torch.cat([train_obj, train_con], dim=-1)
        acq_func = qExpectedImprovement(  # pyre-ignore: [28]
            model=model,
            objective=constrained_objective,
            best_f=constrained_objective(train_y).max(),
            sampler=sampler,
        )
        acq_func_list.append(acq_func)
    # optimize
    candidates, _ = optimize_acqf_list(
        acq_function_list=acq_func_list,
        bounds=standard_bounds,
        num_restarts=20,
        raw_samples=1024,  # used for intialization heuristic
        options={"batch_limit": 5, "maxiter": 200},
    )
    # observe new values
    new_x = candidates.detach()
    new_obj = []
    new_con = []
    for x in new_x:
        res = obj_func(x)
        y = res['objs']
        c = res['constraints']
        new_obj.append(y)
        new_con.append(c)
        global_time = time.time() - global_start_time
        time_list.append(global_time)
    new_obj = torch.tensor(new_obj, **tkwargs).reshape(new_x.shape[0], -1)
    new_con = torch.tensor(new_con, **tkwargs).reshape(new_x.shape[0], -1)
    print(f'evaluate {new_x.shape[0]} configs on real objective')
    return new_x, new_obj, new_con
Exemple #5
0
 def test_optimize_acqf_list(self, mock_optimize_acqf):
     num_restarts = 2
     raw_samples = 10
     options = {}
     tkwargs = {"device": self.device}
     bounds = torch.stack([torch.zeros(3), 4 * torch.ones(3)])
     inequality_constraints = [[
         torch.tensor([3]),
         torch.tensor([4]),
         torch.tensor(5)
     ]]
     # reinitialize so that dtype
     mock_acq_function_1 = MockAcquisitionFunction()
     mock_acq_function_2 = MockAcquisitionFunction()
     mock_acq_function_list = [mock_acq_function_1, mock_acq_function_2]
     for num_acqf, dtype in itertools.product([1, 2],
                                              (torch.float, torch.double)):
         for m in mock_acq_function_list:
             # clear previous X_pending
             m.set_X_pending(None)
         tkwargs["dtype"] = dtype
         inequality_constraints[0] = [
             t.to(**tkwargs) for t in inequality_constraints[0]
         ]
         mock_optimize_acqf.reset_mock()
         bounds = bounds.to(**tkwargs)
         candidate_rvs = []
         acq_val_rvs = []
         gcs_return_vals = [(torch.rand(1, 3, **tkwargs),
                             torch.rand(1, **tkwargs))
                            for _ in range(num_acqf)]
         for rv in gcs_return_vals:
             candidate_rvs.append(rv[0])
             acq_val_rvs.append(rv[1])
         side_effect = list(zip(candidate_rvs, acq_val_rvs))
         mock_optimize_acqf.side_effect = side_effect
         orig_candidates = candidate_rvs[0].clone()
         # Wrap the set_X_pending method for checking that call arguments
         with mock.patch.object(
                 MockAcquisitionFunction,
                 "set_X_pending",
                 wraps=mock_acq_function_1.set_X_pending,
         ) as mock_set_X_pending_1, mock.patch.object(
                 MockAcquisitionFunction,
                 "set_X_pending",
                 wraps=mock_acq_function_2.set_X_pending,
         ) as mock_set_X_pending_2:
             candidates, acq_values = optimize_acqf_list(
                 acq_function_list=mock_acq_function_list[:num_acqf],
                 bounds=bounds,
                 num_restarts=num_restarts,
                 raw_samples=raw_samples,
                 options=options,
                 inequality_constraints=inequality_constraints,
                 post_processing_func=rounding_func,
             )
             # check that X_pending is set correctly in sequential optimization
             if num_acqf > 1:
                 x_pending_call_args_list = mock_set_X_pending_2.call_args_list
                 idxr = torch.ones(num_acqf,
                                   dtype=torch.bool,
                                   device=self.device)
                 for i in range(len(x_pending_call_args_list) - 1):
                     idxr[i] = 0
                     self.assertTrue(
                         torch.equal(x_pending_call_args_list[i][0][0],
                                     orig_candidates[idxr]))
                     idxr[i] = 1
                     orig_candidates[i] = candidate_rvs[i + 1]
             else:
                 mock_set_X_pending_1.assert_not_called()
         # check final candidates
         expected_candidates = (torch.cat(candidate_rvs[-num_acqf:], dim=0)
                                if num_acqf > 1 else candidate_rvs[0])
         self.assertTrue(torch.equal(candidates, expected_candidates))
         # check call arguments for optimize_acqf
         call_args_list = mock_optimize_acqf.call_args_list
         expected_call_args = {
             "acq_function": None,
             "bounds": bounds,
             "q": 1,
             "num_restarts": num_restarts,
             "raw_samples": raw_samples,
             "options": options,
             "inequality_constraints": inequality_constraints,
             "equality_constraints": None,
             "fixed_features": None,
             "post_processing_func": rounding_func,
             "batch_initial_conditions": None,
             "return_best_only": True,
             "sequential": False,
         }
         for i in range(len(call_args_list)):
             expected_call_args["acq_function"] = mock_acq_function_list[i]
             for k, v in call_args_list[i][1].items():
                 if torch.is_tensor(v):
                     self.assertTrue(torch.equal(expected_call_args[k], v))
                 elif k == "acq_function":
                     self.assertIsInstance(mock_acq_function_list[i],
                                           MockAcquisitionFunction)
                 else:
                     self.assertEqual(expected_call_args[k], v)