def test_qEI(self): for double in (True, False): self._setUp(double=double) qEI = qExpectedImprovement(self.model_st, best_f=0.0) candidates, _ = optimize_acqf( 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, _ = optimize_acqf( 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)) candidates_batch_limit, _ = optimize_acqf( acq_function=qEI, bounds=self.bounds, q=3, num_restarts=10, raw_samples=20, options={"maxiter": 5, "batch_limit": 5}, ) self.assertTrue(torch.all(-EPS <= candidates_batch_limit)) self.assertTrue(torch.all(candidates_batch_limit <= 1 + EPS))
def find_eta_c(self, rho_t): """ Find the minimum of the posterior mean, i.e., min_x mu(x|D) s.t. Pr(g(x) <= 0) > rho_t, where D is the data set D={Y,X}, mu(x|D) is the posterior mean of the GP queried at location x, and rho_t depends on the current budget of failures. """ self.my_print("Finding min_x mu(x|D) s.t. Pr(g(x) <= 0) > 0.99") self.gp_mean_obj_cons.rho_t = rho_t options = { "batch_limit": 1, "maxiter": 200, "ftol": 1e-6, "method": self.method_opti } x_eta_c, _ = optimize_acqf(acq_function=self.gp_mean_obj_cons, bounds=self.bounds, q=1, num_restarts=self.Nrestarts_eta_c, raw_samples=500, return_best_only=True, options=options) self.my_print("Done!") # Revaluate the mean (because the one returned might be affected by the constant that is added to ensure non-negativity) eta_c = self.model_list[0](x_eta_c).mean.view(1) return x_eta_c, eta_c
def optimize_acqf_and_get_observation(acq_func, args): """ Optimizes the acquisition function, and returns a new candidate and a noisy observation. botorch defaults: num_restarts=10, raw_samples=256, batch_limit=5, maxiter=200 """ batch_initial_conditions = gen_one_shot_kg_initial_conditions( acq_function=acq_func, bounds=bo_bounds, q=1, num_restarts=args.acqf_opt_num_restarts, raw_samples=args.acqf_opt_raw_samples, options={"batch_limit": args.acqf_opt_batch_limit, "maxiter": args.acqf_opt_maxiter}, ) # optimize acquisition function candidates, _ = optimize_acqf( acq_function=acq_func, bounds=bo_bounds, q=1, num_restarts=args.acqf_opt_num_restarts, raw_samples=args.acqf_opt_raw_samples, # used for intialization heuristic options={"batch_limit": args.acqf_opt_batch_limit, "maxiter": args.acqf_opt_maxiter}, batch_initial_conditions=batch_initial_conditions ) # proposed evaluation new_theta = candidates.detach() # observe new noisy function evaluation new_G, new_G_sem = composite_simulation(new_theta.squeeze()) return new_theta, new_G, new_G_sem
def argmax_posterior_mean(cands: to.Tensor, cands_values: to.Tensor, ddp_space: BoxSpace, num_restarts: int, num_samples: int) -> to.Tensor: """ Compute the GP input with the maximal posterior mean. :param cands: candidates a.k.a. x :param cands_values: observed values a.k.a. y :param ddp_space: space of the domain distribution parameters, indicates the lower and upper bound :param num_restarts: number of restarts for the optimization of the acquisition function :param num_samples: number of samples for the optimization of the acquisition function :return: un-normalized candidate with maximum posterior value a.k.a. x """ if not isinstance(cands, to.Tensor): raise pyrado.TypeErr(given=cands, expected_type=to.Tensor) if not isinstance(cands_values, to.Tensor): raise pyrado.TypeErr(given=cands_values, expected_type=to.Tensor) if not isinstance(ddp_space, BoxSpace): raise pyrado.TypeErr(given=ddp_space, expected_type=BoxSpace) # Normalize the input data and standardize the output data uc_projector = UnitCubeProjector( to.from_numpy(ddp_space.bound_lo).to(dtype=to.get_default_dtype()), to.from_numpy(ddp_space.bound_up).to(dtype=to.get_default_dtype()), ) cands_norm = uc_projector.project_to(cands) cands_values_stdized = standardize(cands_values) if cands_norm.shape[0] > cands_values.shape[0]: print_cbt( f"There are {cands.shape[0]} candidates but only {cands_values.shape[0]} evaluations. Ignoring " f"the candidates without evaluation for computing the argmax.", "y", ) cands_norm = cands_norm[:cands_values.shape[0], :] # Create and fit the GP model gp = SingleTaskGP(cands_norm, cands_values_stdized) gp.likelihood.noise_covar.register_constraint("raw_noise", GreaterThan(1e-5)) mll = ExactMarginalLogLikelihood(gp.likelihood, gp) fit_gpytorch_model(mll) # Find position with maximal posterior mean cand_norm, _ = optimize_acqf( acq_function=PosteriorMean(gp), bounds=to.stack( [to.zeros(ddp_space.flat_dim), to.ones(ddp_space.flat_dim)]).to(dtype=to.float32), q=1, num_restarts=num_restarts, raw_samples=num_samples, ) cand_norm = cand_norm.to(dtype=to.get_default_dtype()) cand = uc_projector.project_back(cand_norm.detach()) print_cbt(f"Converged to argmax of the posterior mean: {cand.numpy()}", "g", bright=True) return cand
def run(): train_x, train_obj, train_con, best_observed_value_nei = generate_initial_data(n=10) # define models for objective and constraint model_obj = FixedNoiseGP(train_x, train_obj, train_yvar.expand_as(train_obj)).to(train_x) model_con = FixedNoiseGP(train_x, train_con, train_yvar.expand_as(train_con)).to(train_x) # combine into a multi-output GP model model = ModelListGP(model_obj, model_con) mll = SumMarginalLogLikelihood(model.likelihood, model) fit_gpytorch_model(mll) acqui_gpmean_cons = GPmeanConstrained(model=model,objective=constrained_obj) # Forward: # X = torch.rand(size=(1,6)) # acqui_gpmean_cons.forward(X) method_opti = "SLSQP" # constraints # method_opti = "COBYLA" # constraints # method_opti = "L-BFGS-B" # Below, num_restarts must be equal to q, otherwise, it fails... options = {"batch_limit": 1,"maxiter": 200,"ftol":1e-6,"method":method_opti} x_eta_c, eta_c = optimize_acqf(acq_function=acqui_gpmean_cons,bounds=bounds,q=1,num_restarts=1, raw_samples=500,return_best_only=True,options=options) pdb.set_trace()
def optimize_acqf_and_get_observation(acq_func, obj_func, time_list, global_start_time): """Optimizes the acquisition function, and returns a new candidate and observation.""" # optimize candidates, _ = optimize_acqf( acq_function=acq_func, bounds=standard_bounds, q=1, num_restarts=20, raw_samples=1024, # used for initialization heuristic options={ "batch_limit": 5, "maxiter": 200, "nonnegative": True }, sequential=True, ) # 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
def test(dim=1): assert dim == 1 X0 = torch.Tensor([[0.93452506], [0.18872502], [0.89790337], [0.95841797], [0.82335255], [0.45000000], [0.50000000]]) Y0 = torch.Tensor([-0.4532849,-0.66614552,-0.92803395,0.08880341,-0.27683621,1.000000,1.500000]) # Y0 = Y0[:,None] Neval = Y0.shape[0] train_x = X0 train_y = Y0[:,None] Nrestarts = 10 model = SingleTaskGP(train_x, train_y) EI = ExpectedImprovement(model, best_f=0.2) print("[get_next_point()] Computing next candidate by maximizing the acquisition function ...") options={"batch_limit": 50,"maxiter": 200,"ftol":1e-9,"method":"L-BFGS-B","iprint":2,"maxls":30,"disp":True} x_next,alpha_next = optimize_acqf(acq_function=EI,bounds=torch.Tensor([[0.0]*dim,[1.0]*dim],device=device),q=1,num_restarts=Nrestarts, raw_samples=500,return_best_only=True,options=options) print("x_next:",x_next) print("alpha_next:",alpha_next)
def find_eta(self): """ Find the minimum of the posterior mean, i.e., min_x mu(x|D), where D is the data set D={Y,X}, and mu(x|D) is the posterior mean of the GP queried at location x. For this, we do local optimization with random restarts. """ logger.info("Finding min_x mu(x|D)...") options = { "batch_limit": 50, "maxiter": 200, "ftol": 1e-6, "method": self.method_opti } x_eta, _ = optimize_acqf(acq_function=self.gp_mean, bounds=self.bounds, q=1, num_restarts=self.Nrestarts_eta, raw_samples=500, return_best_only=True, options=options) logger.info("Done!") # Revaluate the mean (because the one returned might be affected by the constant that is added to ensure non-negativity) eta = self.model(x_eta).mean.view(1) return x_eta, eta
def get_risky_evaluation(self): # Gather fmin samples, using the Frechet distribution: fmin_samples = get_fmin_samples_from_gp( model=self.model_list[0], Nsamples=self.Nsamples_fmin, eta=self.eta_c) # This assumes self.eta has been updated self.update_u_vec(fmin_samples) self.which_mode = "risky" self.my_print( "[get_risky_evaluation()] Computing next candidate by maximizing the acquisition function ..." ) options = { "batch_limit": 50, "maxiter": 300, "ftol": 1e-9, "method": self.method_risky, "iprint": 2, "maxls": 20, "disp": self.disp_info_scipy_opti } x_next, alpha_next = optimize_acqf(acq_function=self, bounds=self.bounds, q=1, num_restarts=self.Nrestarts_risky, raw_samples=500, return_best_only=True, options=options) self.my_print("Done!") return x_next, alpha_next
def current_best(self, past_only: bool = False, **kwargs) -> Tuple[Tensor, Tensor]: """ Get the current best solution and value :param past_only: If True, optimization is over previously evaluated points only. :param kwargs: ignored :return: Current best solution and value """ inner = PosteriorMean(self.model) if past_only: with torch.no_grad(): values = inner(self.X.reshape(-1, 1, self.dim_x)) best = torch.argmax(values) current_best_sol = self.X[best] current_best_value = -values[best] else: current_best_sol, current_best_value = optimize_acqf( acq_function=inner, bounds=self.bounds, q=1, num_restarts=self.num_restarts, raw_samples=self.num_restarts * self.raw_multiplier, ) # negated again to report the correct value if self.verbose: print( "Current best solution, value: ", current_best_sol, -current_best_value ) return current_best_sol, -current_best_value
def get_candidate(model, acq, full_train_Y, q, bounds, dim): if acq == 'EI': if q == 1: EI = ExpectedImprovement(model, full_train_Y.max().item()) else: EI = qExpectedImprovement(model, full_train_Y.max().item()) bounds_t = torch.FloatTensor([[bounds[0]] * dim, [bounds[1]] * dim]) candidate, acq_value = optimize_acqf( EI, bounds=bounds_t, q=q, num_restarts=15, raw_samples=5000, ) elif acq == 'TS': sobol = SobolEngine(dim, scramble=True) n_candidates = min(5000, max(20000, 2000 * dim)) pert = sobol.draw(n_candidates) X_cand = (bounds[1] - bounds[0]) * pert + bounds[0] thompson_sampling = MaxPosteriorSampling(model=model, replacement=False) candidate = thompson_sampling(X_cand, num_samples=q) else: raise NotImplementedError('Only TS and EI are implemented') return candidate, EI if acq == 'EI' else None
def get_bayes_pop(self, n_suggestions): """ Parameters ---------- n_suggestions: Number of new suggestions/trial solutions to generate using BO Returns The new set of trial solutions obtained by optimizing the acquisition function ------- """ try: candidates, _ = optimize_acqf( acq_function=self.acquisition, bounds=self.min_max_bounds, q=n_suggestions, num_restarts=10, raw_samples=512, # used for initialization heuristic sequential=True) bayes_pop = unnormalize(candidates, self.torch_bounds).numpy() except Exception as e: print('Error in get_bayes_pop(): {}'.format(e)) population = self.search_space.unwarp( bayes_pop) # Translate the solution back to the original space return population
def bo_loop(gp_model: SingleTaskGP, acq_func_id: str, acq_func_kwargs: Dict[str, Any], acq_func_opt_kwargs: Dict[str, Any], bounds: Tensor, tkwargs: Dict[str, Any], q: int, num_restarts: int, raw_initial_samples, seed: int, num_MC_sample_acq: int) -> Iterable[Any]: # seed everything np.random.seed(seed) torch.manual_seed(seed) # put on proper device # we want to maximize fmax = torch.quantile(gp_model.train_targets, .9).item() print(f"Using good point cutoff {fmax:.2f}") device = gp_model.train_inputs[0].device bounds = bounds.to(**tkwargs) gp_model.eval() acq_func_kwargs['best_f'] = fmax acq_func = query_acq_func(acq_func_id=acq_func_id, acq_func_kwargs=acq_func_kwargs, gp_model=gp_model, q=q, num_MC_samples_acq=num_MC_sample_acq ) # if q is 1 use analytic acquisitions acq_func.to(**tkwargs) options = { 'batch_limit': 100 } if acq_func_opt_kwargs == {} else acq_func_opt_kwargs print("Start acquisition function optimization...") if q == 1: # use optimize_acq (with LBFGS) candidate, acq_value = optimize_acqf(acq_function=acq_func, bounds=bounds, q=q, num_restarts=num_restarts, raw_samples=raw_initial_samples, return_best_only=True, options=options) else: candidate, acq_value = optimize_acqf_torch( acq_function=acq_func, bounds=bounds, q=q, num_restarts=num_restarts, raw_samples=raw_initial_samples, return_best_only=True, options=options, ) print(f"Acquired {candidate} with acquisition value {acq_value}") return candidate.to(device=device)
def optimize_loop(model, loss, X_train, y_train, bounds, n_samples=10): best_value = y_train.max() acq_func = qExpectedImprovement(model, best_f=best_value) X_new, acq_value = optimize_acqf(acq_func, bounds=bounds, q=20, num_restarts=10, raw_samples=76) #X_new = X_new.view((n_samples,-1)) print(X_new) return X_new
def optimize_acqf_and_get_observation(self, acq, seed): """Optimizes the acquisition function, and returns a new candidate.""" init = initializers.gen_batch_initial_conditions( acq, self.bounds, options={"seed": seed}, **self.optim_kwargs) # optimize candidate, acq_value = optimize_acqf(acq, bounds=self.bounds, batch_initial_conditions=init, **self.optim_kwargs) # observe new value new_x = candidate.detach() #self.scale_to_bounds(candidate.detach()) return new_x
def optimize_acqui_use_restarts_as_batch(self, options): logger.info("[get_next_point()] Optimizing acquisition function ...") x_next, alpha_next = optimize_acqf(acq_function=self, bounds=self.bounds, q=1, num_restarts=self.Nrestarts, raw_samples=500, return_best_only=True, options=options) return x_next, alpha_next
def _update_current_best(self) -> None: """ Updates the current best solution and corresponding value """ pm = PosteriorMean(self.model) self.current_best_sol, self.current_best_val = optimize_acqf( pm, Tensor([[0], [1]]).repeat(1, self.dim), q=1, num_restarts=self.num_restarts, raw_samples=self.raw_samples, )
def test_EI(self): for double in (True, False): self._setUp(double=double) EI = ExpectedImprovement(self.model_st, best_f=0.0) candidates, _ = optimize_acqf( acq_function=EI, bounds=self.bounds, q=1, num_restarts=10, raw_samples=20, options={"maxiter": 5}, ) self.assertTrue(-EPS <= candidates <= 1 + EPS) EI = ExpectedImprovement(self.model_fn, best_f=0.0) candidates, _ = optimize_acqf( acq_function=EI, bounds=self.bounds, q=1, num_restarts=10, raw_samples=20, options={"maxiter": 5}, ) self.assertTrue(-EPS <= candidates <= 1 + EPS)
def select_next_points_botorch(observed_X: List[List[float]], observed_y: List[float]) -> np.ndarray: """Generate the next sample to evaluate with XTB Uses BOTorch to pick the next sample using Expected Improvement Args: observed_X: Observed coordinates observed_y: Observed energies Returns: Next coordinates to try """ # Clip the energies if needed observed_y = np.clip(observed_y, -np.inf, 2 + np.log10(np.clip(observed_y, 1, np.inf))) # Convert inputs to torch arrays train_X = torch.tensor(observed_X, dtype=torch.float) train_y = torch.tensor(observed_y, dtype=torch.float) train_y = train_y[:, None] train_y = standardize(-1 * train_y) # Make the GP gp = SingleTaskGP(train_X, train_y, covar_module=gpykernels.ScaleKernel( gpykernels.ProductStructureKernel( num_dims=train_X.shape[1], base_kernel=gpykernels.PeriodicKernel( period_length_prior=NormalPrior(360, 0.1))))) mll = ExactMarginalLogLikelihood(gp.likelihood, gp) fit_gpytorch_model(mll) # Solve the optimization problem # Following boss, we use Eq. 5 of https://arxiv.org/pdf/1012.2599.pdf with delta=0.1 n_sampled, n_dim = train_X.shape kappa = np.sqrt( 2 * np.log10(np.power(n_sampled, n_dim / 2 + 2) * np.pi**2 / (3.0 * 0.1))) # Results in more exploration over time ei = UpperConfidenceBound(gp, kappa) bounds = torch.zeros(2, train_X.shape[1]) bounds[1, :] = 360 candidate, acq_value = optimize_acqf(ei, bounds=bounds, q=1, num_restarts=64, raw_samples=64) return candidate.detach().numpy()[0, :]
def _sample(self, candidates: Optional[np.array] = None) -> np.array: if len(self.X_observed) < self.num_initial_random_draws: return self.initial_sampler.sample(candidates=candidates) else: z_observed = torch.Tensor(self.transform_outputs(self.y_observed.numpy())) with torch.no_grad(): # both (n, 1) #mu_pred, sigma_pred = self.thompson_sampling.prior(self.X_observed) mu_pred, sigma_pred = self.initial_sampler.prior.predict(self.X_observed) mu_pred = torch.Tensor(mu_pred) sigma_pred = torch.Tensor(sigma_pred) # (n, 1) r_observed = residual_transform(z_observed, mu_pred, sigma_pred) # build and fit GP on residuals gp = SingleTaskGP( train_X=self.X_observed, train_Y=r_observed, likelihood=GaussianLikelihood(noise_constraint=GreaterThan(1e-3)), ) mll = ExactMarginalLogLikelihood(gp.likelihood, gp) fit_gpytorch_model(mll) acq = ShiftedExpectedImprovement( model=gp, best_f=z_observed.min(dim=0).values, mean_std_predictor=self.initial_sampler.prior.predict, maximize=False, ) if candidates is None: candidate, acq_value = optimize_acqf( acq, bounds=self.bounds_tensor, q=1, num_restarts=5, raw_samples=100, ) # import matplotlib.pyplot as plt # x = torch.linspace(-1, 1).unsqueeze(dim=-1) # x = torch.cat((x, x * 0), dim=1) # plt.plot(x[:, 0].flatten().tolist(), acq(x.unsqueeze(dim=1)).tolist()) # plt.show() return candidate[0] else: # (N,) ei = acq(torch.Tensor(candidates).unsqueeze(dim=-2)) return torch.Tensor(candidates[ei.argmax()])
def gen(self, num_points=1, **kwargs): self.model.eval() train_x = self.model.train_inputs[0] acq = self._get_acquisition_fn() new_candidate, batch_acq_values = optimize_acqf( acq_function=acq, bounds=torch.tensor(np.c_[self.lb, self.ub]).T.to(train_x), q=num_points, num_restarts=self.restarts, raw_samples=self.samps, ) return new_candidate.numpy()
def optimize_acqf_and_get_observation(acq_func, dataset): """Optimizes the acquisition function, and returns a new candidate and a noisy observation.""" # optimize candidates, _ = optimize_acqf( acq_function=acq_func, bounds=bounds, q=BATCH_SIZE, num_restarts=10, raw_samples=512, # used for intialization heuristic options={"batch_limit": 5, "maxiter": 200}, ) # observe new values new_x = candidates.detach() exact_obj = call_external(new_x, BATCH_SIZE, 5, dataset).unsqueeze(-1) # add output dimension new_obj = exact_obj + NOISE_SE * torch.randn_like(exact_obj) return new_x, new_obj
def optimize_acqf_and_get_observation(acq_func, mean_y=None, std_y=None): """optimize acquisition function and evaluate new candidates """ # optimize candidates, _ = optimize_acqf( acq_function=acq_func, bounds=bounds, q=BATCH_SIZE, num_restarts=10, raw_samples=512, # used for intialization heuristic ) # observe new values new_x = candidates.detach() new_y = evaluate_y(new_x, mean_y=mean_y, std_y=std_y) return new_x, new_y
def propose_candidates(args, prev_res): ## train a surrogate model gp = SingleTaskGP(prev_res['hparams'], prev_res['acc']) mll = ExactMarginalLogLikelihood(gp.likelihood, gp) fit_gpytorch_model(mll) ## construct an acquisition function and optimize it UCB = UpperConfidenceBound(gp, beta=0.1) candidates, acq_value = optimize_acqf(UCB, bounds=bounds, q=args.n_cand, num_restarts=5, raw_samples=20) return candidates
def optimize_loop(model, loss, X_train, y_train, X_test, y_test, bounds): best_value = y_train.min() acq_func = ExpectedImprovement(model, best_f=best_value, maximize=False) X_new, acq_value = optimize_acqf(acq_func, bounds=bounds, q=1, \ num_restarts=100, raw_samples=100) X_new = X_new.view((1, 1)) y_new = (eval_true_func(X_new) - y_mean) / y_std # concatenate new points to training set X_train_new = torch.cat((X_train, X_new)) y_train_new = torch.cat((y_train, y_new)) plot_acq_func(acq_func, X_test=X_test, X_train=X_train_new, X_new=X_new) # condition model on new observation gpr_model, gpr_mll = get_gpr_model(X_new, y_new, model=model) # plot model performance plot_testing(gpr_model, X_test=X_test, X_train=X_train_new, \ y_train=y_train_new, y_test=y_test, X_new=X_new, y_new=y_new) return gpr_model, gpr_mll, X_train_new, y_train_new
def _maximize_kg(self) -> None: """ maximizes the KG acquisition function and stores the resulting value and the candidate """ acq_func = qKnowledgeGradient( model=self.model, current_value=self.current_best_val ) # acq_func = qExpectedImprovement(model=self.model, best_f=self.current_best_val) # acq_func = ExpectedImprovement(model=self.model, best_f=self.current_best_val) self.next_candidate, self.kg_value = optimize_acqf( acq_func, Tensor([[0], [1]]).repeat(1, self.dim), q=1, num_restarts=self.num_restarts, raw_samples=self.raw_samples, )
def optimize_acqf_and_get_observation(acq_func): """Optimizes the acquisition function, and returns a new candidate and a noisy observation""" candidates, _ = optimize_acqf( acq_function=acq_func, bounds=torch.stack([ torch.zeros(d, dtype=dt), torch.ones(d, dtype=dt), ]), q=1, num_restarts=10, raw_samples=200, ) x = unnormalize(candidates.detach(), bounds=bounds) print('Hyper-parameter: ' + str(x)) obj = self.train(x.view(-1)).unsqueeze(-1) print(print('Error: ' + str(obj))) return x, obj
def optimize_acqf_and_get_observation(acq_func): """Optimizes the acquisition function, and returns a new candidate and a noisy observation.""" # optimize candidates, _ = optimize_acqf( acq_function=acq_func, bounds=bounds, q=BATCH_SIZE, num_restarts=10, raw_samples=500, # used for intialization heuristic options={ "batch_limit": 5, "max_iter": 200, }) # observe new values new_x = candidates.detach() exact_obj = neg_hartmann6(new_x).unsqueeze(-1) # add output dimension exact_con = outcome_constraint(new_x).unsqueeze(-1) # add output dimension new_obj = exact_obj + NOISE_SE * torch.randn_like(exact_obj) new_con = exact_con + NOISE_SE * torch.randn_like(exact_con) return new_x, new_obj, new_con
def argmax_posterior_mean(cands: to.Tensor, cands_values: to.Tensor, uc_normalizer: UnitCubeProjector, num_restarts: int, num_samples: int) -> to.Tensor: """ Compute the GP input with the maximal posterior mean. :param cands: candidates a.k.a. x :param cands_values: observed values a.k.a. y :param uc_normalizer: unit cube normalizer used during the experiments (can be recovered form the bounds) :param num_restarts: number of restarts for the optimization of the acquisition function :param num_samples: number of samples for the optimization of the acquisition function :return: un-normalized candidate with maximum posterior value a.k.a. x """ # Normalize the input data and standardize the output data cands_norm = uc_normalizer.project_to(cands) cands_values_stdized = standardize(cands_values) # Create and fit the GP model gp = SingleTaskGP(cands_norm, cands_values_stdized) gp.likelihood.noise_covar.register_constraint('raw_noise', GreaterThan(1e-5)) mll = ExactMarginalLogLikelihood(gp.likelihood, gp) fit_gpytorch_model(mll) # Find position with maximal posterior mean cand_norm, acq_value = optimize_acqf( acq_function=PosteriorMean(gp), bounds=to.stack([ to.zeros_like(uc_normalizer.bound_lo), to.ones_like(uc_normalizer.bound_up) ]), q=1, num_restarts=num_restarts, raw_samples=num_samples) cand = uc_normalizer.project_back(cand_norm.detach()) print_cbt(f'Converged to argmax of the posterior mean\n{cand.numpy()}', 'g', bright=True) return cand
def optimize_acqf_and_get_observation(acq_func): """ Optimizes the acquisition function, and returns a new candidate and a noisy observation. :param acq_func: Acquisition function to use. :return: new_x: new candidate new_train_obj: noisy observation of g(x) """ # optimize candidates, _ = optimize_acqf( acq_function=acq_func, bounds=bounds, q=BATCH_SIZE, num_restarts=10, raw_samples=512, # used for initialization heuristic options={"batch_limit": 5, "maxiter": 200}, ) # observe new values new_x = candidates.detach() exact_obj, _, _ = exact_sin_objective(new_x, plot_sample=None, fplot=False) new_train_obj = train_sin_objective(new_x, fplot=False) return new_x, new_train_obj