def test_qEI(self, cuda=False): for double in (True, False): self._setUp(double=double, cuda=cuda) qEI = qExpectedImprovement(self.model_st, best_f=0.0) candidates = joint_optimize( acq_function=qEI, bounds=self.bounds, q=3, num_restarts=10, raw_samples=20, options={"maxiter": 5}, ) self.assertTrue(torch.all(-EPS <= candidates)) self.assertTrue(torch.all(candidates <= 1 + EPS)) qEI = qExpectedImprovement(self.model_fn, best_f=0.0) candidates = joint_optimize( acq_function=qEI, bounds=self.bounds, q=3, num_restarts=10, raw_samples=20, options={"maxiter": 5}, ) self.assertTrue(torch.all(-EPS <= candidates)) self.assertTrue(torch.all(candidates <= 1 + EPS))
def optimize_acqf_and_get_observation(acq_func, x0, y0): # Optimizes the acquisition function, returns new candidate new_x # and its objective function value new_obj # optimize if args.optimize_acq == 'scipy': candidates = joint_optimize( acq_function=acq_func, bounds=bounds, q=args.q, num_restarts=args.num_restarts, raw_samples=200, ) else: Xinit = gen_batch_initial_conditions(acq_func, bounds, q=args.q, num_restarts=args.num_restarts, raw_samples=500) batch_candidates, batch_acq_values = gen_candidates_torch( initial_conditions=Xinit, acquisition_function=acq_func, lower_bounds=bounds[0], upper_bounds=bounds[1], verbose=False) candidates = get_best_candidates(batch_candidates, batch_acq_values) # observe new values new_x = candidates.detach() if not args.inf_norm: new_x = latent_proj(new_x, args.eps) new_obj = obj_func(new_x, x0, y0) return new_x, new_obj
def optimize_EI(gp, best_f, n_dim): """ Reference: https://botorch.org/api/optim.html bounds: 2d-ndarray (2, D) The values of lower and upper bound of each parameter. q: int The number of candidates to sample num_restarts: int The number of starting points for multistart optimization. raw_samples: int The number of initial points. Returns for joint_optimize is (num_restarts, q, D) """ mll = ExactMarginalLogLikelihood(gp.likelihood, gp) fit_gpytorch_model(mll) ei = ExpectedImprovement(gp, best_f=best_f, maximize=False) bounds = torch.from_numpy(np.array([[0.] * n_dim, [1.] * n_dim])) x = joint_optimize(ei, bounds=bounds, q=1, num_restarts=3, raw_samples=15) return np.array(x[0])
def bo_step(X, y, noise, objective, bounds, GP=None, acquisition=None, q=1, state_dict=None, plot=False): """ One iteration of Bayesian optimization: 1. Fit GP model using (X, y) 2. Create acquisition function 3. Optimize acquisition function to obtain candidate point 4. Evaluate objective at candidate point 5. Add new point to the data set Parameters ---------- X : torch.tensor, shape=(n_samples, dim) Input values y : torch.tensor, shape=(n_samples,) Objective values objective : callable, argument=torch.tensor Objective black-box function, accepting as an argument torch.tensor bounds : torch.tensor, shape=(2, dim) Box-constraints GP : callable GP model class constructor. It is a function that takes as input 2 tensors - X, y - and returns an instance of botorch.models.Model. acquisition : callable Acquisition function construction. It is a function that receives one argument - GP model - and returns an instance of botorch.acquisition.AcquisitionFunction q : int Number of candidate points to find state_dict : dict GP model state dict plot : bool Flag indicating whether to plot the result Returns ------- X : torch.tensor Tensor of input values with new point y : torch.tensor Tensor of output values with new point gp : botorch.models.Model Constructed GP model """ attempts = 0 while attempts < 10: try: options = {'lr': 1e-1 / (1 + 10**attempts), 'maxiter': 100} # Create GP model mll, gp = initialize_model(X, y, noise=noise, bounds=bounds, GP=GP, state_dict=state_dict) if USE_SCIPY: fit_gpytorch_model(mll) else: fit_gpytorch_model(mll, optimizer=fit_gpytorch_torch, options=options) # Create acquisition function acquisition_ = acquisition(gp, y) # Optimize acquisition function candidate, acq_value_list = joint_optimize( acquisition_, bounds=bounds, q=q, num_restarts=20, raw_samples=20000, ) break except RuntimeError: # state_dict = None attempts += 1 if attempts > 1: state_dict = None print("Attempt #{}".format(attempts), traceback.print_exc()) X = torch.cat([X, candidate]) y = torch.cat([y, objective(candidate).detach().view(1, 1)], dim=0) if plot: utils.plot_acquisition(acquisition, X, y, candidate) return X, y, gp