def optimize_surrogate_if_needed(self): run_opt = False if self.optimise_surrogate_model_flag == 'data': if len(self.surrogate.Y) >= self.opt_next_at_n_data: self.opt_next_at_n_data += self.optimize_every_n_data run_opt = True elif self.optimise_surrogate_model_flag == 'iter': if len(self.curr_bo_step) >= self.opt_next_at_iter: self.opt_next_at_iter += self.optimize_every_n_iter run_opt = True elif self.optimise_surrogate_model_flag == 'always': run_opt = True if run_opt: if self.verbose >= 1: print("Optimising surrogate model...") self.surrogate.optimize() if self.verbose > 1: print( f"Surrogate model optimisation complete. " f"New param_array = {self.surrogate.param_array}") self.param_array_hist.append(self.surrogate.param_array)
def get_next(self): """Finds the next point to sample at Returns ------- x_best : np.ndarray Location to sample at acq_at_x_best : float Value of the acquisition function at the sampling locations """ assert self.batch_size == 1, "Use batch BO class for batch size > 1" acq = self._create_acq_function() best_eval = self._optimise_acq_func(acq) x_best, acq_at_x_best = best_eval if self.verbose > 1: print("Optimised acq_dict function") print("x, acq_dict(x) = {}".format(best_eval)) mu, _ = self.surrogate.predict(x_best) return x_best, acq_at_x_best
def _update_surrogate_with_new_data(self, new_sample_x, new_sample_y): if self.verbose > 1: print("Updating the surrogate model's data arrays") model_x, model_y = self.surrogate.X, self.surrogate.Y_raw new_x = np.vstack((model_x, new_sample_x)) new_y = np.vstack((model_y, new_sample_y)) self.surrogate.set_XY(X=new_x, Y=new_y)
def run(self): """ Run the BayesOpt loop """ t0 = time.time() if self.verbose: print("Started BayesOpt.run()") self._initialise_bo_df() for self.curr_bo_step in range(0, self.n_bo_steps): # try: if True: # if True: t1 = time.time() if self.verbose: print("**--** Starting BayesOpt iteration {}/{} **--**" .format(self.curr_bo_step + 1, self.n_bo_steps)) self.optimize_surrogate_if_needed() self.x_min, self.y_min, self.var_at_y_min = self._get_y_min() x_best, acq_at_x_best = self.get_next() t2 = time.time() time_taken = t2 - t1 if self.create_plots: self.plot_step(x_best=x_best) # get new y new_sample_x, new_sample_y = self._sample_at_x(x_best) self._update_surrogate_with_new_data(new_sample_x, new_sample_y) self.save_history(acq_at_x_best) # update variables for plotting self.sampling_locs[self.curr_bo_step] = x_best self._update_bo_df(x_best, acq_at_x_best, new_sample_x, new_sample_y, time_taken) if self.curr_bo_step == self.n_bo_steps - 1: # last step if self.verbose > 1: print("Used up budget.") print("Minimum at", self.surrogate.X[np.argmin(self.surrogate.Y)]) if self.verbose: print(f"Completed BO exp in {round(time.time() - t0, 2)}s")
def save_plots_to_disk(self, fig): folder = (self.save_plots if isinstance(self.save_plots, str) else './plots/') if not os.path.exists(folder): os.makedirs(folder) prefix = ('' if self.plots_prefix in (None, False) else self.plots_prefix) fname = os.path.join(folder, f"{prefix}{self.curr_bo_step}.png") fig.savefig(fname) if self.verbose: print("Saved plot ", fname) plt.close()
def _sample_at_x(self, x_best) -> Tuple[np.ndarray, np.ndarray]: """Evaluate the sampler object at these points. This function is useful if we want to impose specific noise on the measurements Parameters ---------- x_best Locations to sample at Returns ------- x : np.ndarray Sampled locations x (this is useful in case of input noise) y : np.ndarray Values of y at the sampled locations """ if self.verbose > 1: print("Sampling at selected location") new_sample = self.sampler(x_best) return x_best, new_sample
def exp_async_synch(args=None, sampler=None, true_min_val=None, x_init=None, y_init=None, x_lim=None, foldername=None, hp_bounds=None, restart_bounds=None, hyper_priors=None, n_iter=None, starting_jobs=None, async_interface=None, force_run=None, debug=None): """ Using keyword args for clearer calling of the func. All args that are necessary are asserted to not be None """ assert args is not None assert sampler is not None assert true_min_val is not None assert x_init is not None assert y_init is not None assert x_lim is not None assert foldername is not None assert hp_bounds is not None assert restart_bounds is not None assert hyper_priors is not None assert n_iter is not None assert async_interface is not None assert force_run is not None assert debug is not None exp_type = get_async_synch_from_args(args) # ********* Convert args ******** # seed, proc_name, batch_size, ard_flag, n_workers, kern_choice, \ kern_func, acq_dict, opt_frequency = apply_general_settings(args) # ********* Optimisations ******** # y_min_opt_params, acq_opt_params, min_acq_opt_params, gp_opt_params, \ optimise_surrogate_model = get_default_optimisation_params(hp_bounds, restart_bounds) kern_gp = kern_func(x_lim.shape[0], variance=np.var(y_init), lengthscale=0.2, ARD=ard_flag) surrogate = GP(x_init, y_init, kern_gp, lik_variance=1e-6, lik_variance_fixed=True, opt_params=gp_opt_params, hyper_priors=hyper_priors) # surrogate.optimize() # ********* Paths ******** # if exp_type == 'async': postfix = 'results/asyncbo' elif exp_type == 'synch': postfix = 'results/synchbo' else: raise NotImplementedError if args.machine == 0: # local folder = os.path.join(f'../{postfix}/', foldername) elif args.machine == 1: # arc raise NotImplementedError else: folder = os.path.join(f'../{postfix}', foldername) if exp_type == 'async': # synth time vs real exp if hasattr(args, 'timer'): fname = f'asyncst_{args.proc}_{acq_dict["type"]}_' \ f'{kern_choice}_{sampler.__name__}_{n_workers}_' \ f'{batch_size}_{seed}_{n_iter}_' \ f't{args.timer}.pkl' else: fname = f'asyncbo_{args.proc}_{acq_dict["type"]}_' \ f'{kern_choice}_{sampler.__name__}_{n_workers}_' \ f'{batch_size}_{seed}_{n_iter}.pkl' elif exp_type == 'synch': # synth time vs real exp if hasattr(args, 'timer'): fname = f'synchst_{args.proc}_{acq_dict["type"]}_' \ f'{kern_choice}_{sampler.__name__}_{n_workers}_' \ f'{batch_size}_{seed}_{n_iter}_' \ f't{args.timer}.pkl' else: fname = f'synchbo_{args.proc}_{acq_dict["type"]}_' \ f'{kern_choice}_{sampler.__name__}_{n_workers}_' \ f'{batch_size}_{seed}_{n_iter}.pkl' else: raise NotImplementedError save_fname = os.path.join(folder, fname) if os.path.exists(save_fname) and not (debug or force_run): print('*** WARNING:', save_fname, 'exists already on disk! ' 'Skipping...') sys.exit() # Avoids multiple instances of this code trying to create the folder at # the same time and then crashing time.sleep(np.random.uniform(0, 2)) if not os.path.exists(folder): os.makedirs(folder) # ********* BO ******** # df_all_exps = None # Run BayesOpt print(f"Starting exp {proc_name} with ({sampler.__name__}, {seed})") kwargs = dict() kwargs['acq_dict'] = acq_dict kwargs['y_min_opt_params'] = y_min_opt_params kwargs['acq_opt_params'] = acq_opt_params kwargs['min_acq_opt_params'] = min_acq_opt_params kwargs['offset_acq'] = True kwargs['n_bo_steps'] = n_iter kwargs['optimise_surrogate_model'] = optimise_surrogate_model kwargs['track_cond_k'] = False kwargs['verbose'] = 1 kwargs['batch_size'] = batch_size kwargs['starting_jobs'] = starting_jobs kwargs['optimize_every_n_data'] = opt_frequency if 'trueM' in proc_name: kwargs['true_M'] = true_min_val if acq_dict['type'] == 'UCB': # lp_transform = 'softplus' lp_transform = 'none' else: lp_transform = 'none' if debug: kwargs['track_cond_k'] = False kwargs['create_plots'] = True kwargs['save_plots'] = True kwargs['plots_prefix'] = f"{proc_name}_{sampler.__name__}_" kwargs['verbose'] = 2 if exp_type == 'async': bo = create_async_bo_instance(proc_name, sampler, surrogate, x_lim, lp_transform, async_interface, kwargs) elif exp_type == 'synch': bo = create_synch_bo_instance(proc_name, sampler, surrogate, x_lim, lp_transform, async_interface, kwargs) else: raise NotImplementedError bo.run() hash = get_commit_hash() # Combine the BO report with info about the experiment exp_desc = { 'githash': hash, 'seed': seed, 'async_interface': async_interface.__class__.__name__, 'proc_name': proc_name, 'bo_strategy': f"{proc_name}_{acq_dict['type']}", 'batch_size': batch_size, 'n_workers': n_workers, 'kern_choice': kern_choice, 'model_opt_params': surrogate.opt_params, 'func': sampler.__name__, 'x_lim': x_lim, 'optimise_surrogate_model': optimise_surrogate_model, 'acq_opt_params': acq_opt_params, 'acq_dict': acq_dict, 'acq_type': acq_dict['type'], 'y_min_opt_params': y_min_opt_params, 'ard': ard_flag } exp_desc = pd.DataFrame([exp_desc]) df_bo_exp = exp_desc.join(bo.df, how='right').ffill() if df_all_exps is None: df_all_exps = df_bo_exp else: df_all_exps = df_all_exps.append(df_bo_exp) if debug: bo.plot_y_min() plt.title(proc_name) plt.show() df_all_exps = df_all_exps.reset_index() print(f"Saving the exp summary to {save_fname}...") # df_all_exps.to_pickle(fname) time_limited_df_to_pickle(df_all_exps, save_fname, 20) print("Done!")
def get_next(self): """Finds the next point(s) to sample at Returns ------- x_best : np.ndarray Location to sample at acq_at_x_best : float Value of the acquisition function at the sampling locations """ acq_orig = self._create_acq_function() # fix for jumping straight to get_next() instead of via run() if self.y_min is None: self.x_min, self.y_min, self.var_at_y_min = self._get_y_min() M = self._get_min_value_for_acq() if self.offset_acq: _, min_val = self._optimise_acq_func( acq_orig, max_or_min='min', acq_opt_params=self.min_acq_opt_params) acq_orig = AcquisitionWithOffset(acq_orig, min_val) L = estimate_lipschitz_constant(self.surrogate, self.bounds) self.L = L # ASYNC x_busy = self.interface.get_array_of_running_jobs() if x_busy is not None: acq = self._create_lp_acq_function(x_busy, L, M, acq_orig=acq_orig) else: acq = acq_orig # First point is the result of a greedy search on the unpenalized # acquisition function x_best, acq_at_x_best = self._optimise_acq_func(acq) if self.debug: self.plot_acq(acq.evaluate, x_busy=x_busy) x_batch = x_best acq_at_each_x_batch = acq_at_x_best if self.batch_size > 1: if self.verbose: print(f"Lipschitz constant estimate = {L}") while len(x_batch) < self.batch_size: # ASYNC if x_busy is not None: x_pen = np.vstack((x_busy, x_batch)) else: x_pen = x_batch acq = self._create_lp_acq_function(x_pen, L, M, acq_orig=acq_orig) if self.debug: self.plot_acq(acq.evaluate, x_batch=x_batch, x_busy=x_busy) x_best, acq_at_x_best = self._optimise_acq_func(acq) x_batch = np.vstack((x_batch, x_best)) acq_at_each_x_batch = np.hstack( (acq_at_each_x_batch, acq_at_x_best)) return x_batch, acq_at_each_x_batch
def run(self): """ Run the Async BayesOpt loop """ # TODO: test this t_starting_run = time.time() if self.verbose: print("Started BayesOpt.run()") self._initialise_bo_df() if self.starting_jobs is not None: for job in self.starting_jobs: self.interface.add_job_to_queue(job) for self.curr_bo_step in range(0, self.n_bo_steps): new_sample_x, new_sample_y = None, None # try: if True: t_beginning_of_bo_step = time.time() if self.verbose: print("**--** Starting BayesOpt iteration {}/{} **--**". format(self.curr_bo_step + 1, self.n_bo_steps)) # Move time ahead until we have the correct number of free # workers self.interface.run_until_n_free(self.batch_size) n_free_workers = self.interface.status['n_free_workers'] completed_jobs = self.interface.get_completed_jobs() if len(completed_jobs) > 0: new_sample_x, new_sample_y = \ self._add_completed_jobs_to_surrogate(completed_jobs) assert n_free_workers >= self.batch_size t_before_opt_surrogate = time.time() # if self.verbose: # print(f"Surrogate n_data = {len(self.surrogate.X)}") # if self.optimise_surrogate_model_flag: # if self.verbose > 1: # print("Optimising surrogate model...") # self.surrogate.optimize() # self.param_array_hist.append(self.surrogate.param_array) # if self.verbose > 1: # print( # f"Surrogate model optimisation complete. " # f"New param_array = {self.surrogate.param_array}") self.optimize_surrogate_if_needed() t_after_opt_surrogate = time.time() t_before_find_y_min = time.time() self.x_min, self.y_min, self.var_at_y_min = self._get_y_min() t_after_find_y_min = t_before_get_next = time.time() if self.verbose: print("Selecting next point(s)...") x_batch, acq_at_x_batch = self.get_next() t_after_get_next = t_end_of_bo_step = time.time() time_taken_opt_surrogate = \ (t_after_opt_surrogate - t_before_opt_surrogate) time_taken_find_y_min = \ (t_after_find_y_min - t_before_find_y_min) time_taken_get_next = \ (t_after_get_next - t_before_get_next) time_taken_bo_step = \ (t_end_of_bo_step - t_beginning_of_bo_step) time_taken_dict = { 'time_taken_opt_surrogate': time_taken_opt_surrogate, 'time_taken_find_y_min': time_taken_find_y_min, 'time_taken_get_next': time_taken_get_next, 'time_taken_bo_step': time_taken_bo_step, } if self.create_plots: self.plot_step(x_batch=x_batch) # queue the jobs jobs = [] for ii in range(len(x_batch)): job = {'x': x_batch[ii], 'f': self.sampler} jobs.append(job) self.interface.add_job_to_queue(jobs) self.save_history(None) if self.curr_bo_step == self.n_bo_steps - 1: # last step if self.verbose > 1: print("Used up budget.") print("Minimum at", self.surrogate.X[np.argmin(self.surrogate.Y)]) self._update_bo_df(x_batch, acq_at_x_batch, new_sample_x, new_sample_y, time_taken_dict) # Attempting to force SLURM to update the output file sys.stdout.flush() # except np.linalg.linalg.LinAlgError: # print("WARNING: BayesOpt crashed at iteration {}!".format( # self.curr_bo_step)) # break if self.verbose: print(f"Completed BO exp in;" f" {round(time.time() - t_starting_run, 2)}s")
def plot_acq(self, acq_func=None, x_batch=None, x_best=None, x_busy=None): import pylab as plt assert self.surrogate.X.shape[1] == 1, "Debugging acq only in 1D!" if x_batch is not None: x_batch = np.vstack(x_batch) if x_busy is not None: x_busy = np.vstack(x_busy) x_dense = np.linspace(self.bounds[0, 0], self.bounds[0, 1], 1000) if acq_func is not None: fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(12, 9)) acq_dense = acq_func(x_dense[:, None]) if x_best is None: x_best = np.atleast_2d(x_dense[np.argmax(acq_dense)]) else: fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(7, 9)) axes = axes, acq_dense = None f_mean, f_var = self.surrogate.predict(x_dense[:, None]) f_var[f_var < 1e-10] = 1e-10 f_mean = f_mean.flatten() f_var = f_var.flatten() f_std = np.sqrt(f_var) # Mean and variance of surrogate axes[0].plot(x_dense, f_mean, 'k', label='Surrogate') axes[0].fill_between(x_dense, f_mean + 2 * f_std, f_mean - 2 * f_std, color='b', alpha=0.2) axes[0].set_title(f'{acq_func} Surrogate model') # Data in the surrogate if len(self.surrogate.X) > 0: axes[0].plot(self.surrogate.X, self.surrogate.Y_raw, 'b*', markersize=16, label='Data') # New point(s) axes[0].plot(x_best, self.surrogate.predict(np.atleast_2d(x_best))[0], 'r*', markersize=16, label='New') if x_batch is not None: axes[0].plot(x_batch, self.surrogate.predict(x_batch)[0], 'g*', label="Batch", markersize=16) if acq_func is not None: axes[1].plot(x_batch, acq_func(x_batch), 'g*', label="Batch", markersize=16) if x_busy is not None and len(x_busy) > 0: axes[0].plot(x_busy, self.surrogate.predict(x_busy)[0], 'k*', label="Busy", markersize=16) if acq_func is not None: axes[1].plot(x_busy, acq_func(x_busy), 'k*', label="Busy", markersize=16) if acq_func is not None: # Acquisition function axes[1].plot(x_dense, acq_dense, 'k') # New point(s) if x_best is not None: axes[1].plot(x_best, acq_func(x_best), 'r*', markersize=16, label='New') folder = (self.save_plots if isinstance(self.save_plots, str) else './plots/') if not os.path.exists(folder): os.makedirs(folder) if x_batch is None: x_batch = [] fname = os.path.join(folder, f"{self.curr_bo_step}_{len(x_batch)}.pdf") fig.savefig(fname) if self.verbose: print("Saved plot ", fname) plt.close() fig.show()
def __init__(self, sampler: Callable, surrogate: GP, bounds: np.ndarray, batch_size: int = 1, acq_dict: Optional[Dict] = None, y_min_opt_params: Optional[dict] = None, acq_opt_params: Optional[dict] = None, n_bo_steps: Optional[int] = 30, optimise_surrogate_model: Optional[bool] = True, optimize_every_n_data: Optional[int] = None, track_cond_k: Optional[bool] = True, min_acq: Optional[float] = None, create_plots: Optional[bool] = False, save_plots: Optional[bool] = False, plots_prefix: Optional[str] = False, verbose: Optional[Union[bool, int]] = False, debug: Optional[bool] = False, **kwargs): self.verbose = verbose self.debug = debug self.df = None self.curr_bo_step = None self.batch_size = batch_size if self.verbose: print("Initialising BayesOpt instance...") if acq_dict is None: self.acq_dict = {'type': 'EI'} else: self.acq_dict = acq_dict self.min_acq = min_acq if y_min_opt_params is None: self.y_min_opt_params = {'method': 'direct', 'n_direct_evals': 100} else: self.y_min_opt_params = y_min_opt_params if acq_opt_params is None: self.acq_opt_params = {'method': 'direct', 'n_direct_evals': 100} else: self.acq_opt_params = acq_opt_params self.n_bo_steps = n_bo_steps self.param_array_hist = [] self.surrogate = surrogate self.sampler = sampler self.bounds = bounds if optimize_every_n_data is not None: self.optimise_surrogate_model_flag = 'data' self.optimize_every_n_data = optimize_every_n_data self.opt_next_at_n_data = \ len(self.surrogate.Y) + self.optimize_every_n_data elif optimise_surrogate_model: self.optimise_surrogate_model_flag = 'always' self.counter_since_last_surrogate_opt = 0 self.x_min = None self.y_min = None self.var_at_y_min = None self.acq_hist = np.zeros(self.n_bo_steps) self.sampling_locs = np.zeros((self.n_bo_steps, self.bounds.shape[0])) # For debugging numerical issues self.track_cond_k = track_cond_k if self.track_cond_k: self.cond_k_hist = np.zeros(self.n_bo_steps) else: self.cond_k_hist = None # Keep a record of the best sample so far self.y_min_hist = np.zeros(self.n_bo_steps) self.var_at_y_min_hist = np.zeros(self.n_bo_steps) self.x_min_hist = np.zeros((self.n_bo_steps, self.bounds.shape[0])) self.create_plots = create_plots self.save_plots = save_plots self.plots_prefix = plots_prefix if self.verbose: print("Initialisation of BayesOpt instance done.")
def plot_step(self, x_best=None, save_plots=None, external_call=False, **kwargs): """ Plots a summary of the BayesOpt step and saves the image to a specified folder """ if save_plots is None: save_plots = self.save_plots text = "Task" figsize = (12, 9) acq = self._create_acq_function() p = x_best if len(self.bounds) == 1: # 1D n_x = 100 x_dense = np.linspace(self.bounds[0, 0], self.bounds[0, 1], n_x) # get mean and std over the domain f_mean, f_var = self.surrogate.predict(x_dense[:, None]) f_mean = f_mean.flatten() f_var = f_var.flatten() f_std = np.sqrt(f_var) acq_dense = acq.evaluate(x_dense[:, None]) if self.verbose: print("Preparing plots") fig, axes = plt.subplots(nrows=2, ncols=1, figsize=figsize, sharex='all') # Mean and variance of surrogate axes[0].plot(x_dense, f_mean, 'k', label='Surrogate') axes[0].fill_between(x_dense, f_mean + 2 * f_std, f_mean - 2 * f_std, color='b', alpha=0.2) axes[0].set_title(f'Step {self.curr_bo_step} Surrogate model') # Data in the surrogate if len(self.surrogate.X) > 0: axes[0].plot(self.surrogate.X, self.surrogate.Y_raw, 'b*', markersize=16, label='Data') # New point(s) if x_best is not None: axes[0].plot(x_best, self.surrogate.predict(x_best)[0], 'r*', markersize=16, label='New') # Acquisition function axes[1].plot(x_dense, acq_dense, 'k') # New point(s) if x_best is not None: axes[1].plot(x_best, acq.evaluate(x_best), 'r*', markersize=16, label='New') axes[1].set_title('Acquisition function') if not external_call: axes[0].legend(numpoints=1) axes[1].legend(numpoints=1) elif len(self.bounds) == 2: # 2D n_x1, n_x2 = 20, 20 x1 = np.linspace(self.bounds[0, 0], self.bounds[0, 1], n_x1) x2 = np.linspace(self.bounds[1, 0], self.bounds[1, 1], n_x2)[::-1] x1x2 = np.dstack(np.meshgrid(x1, x2)).reshape(-1, 2) y_grid = self.sampler(x1x2)['f_of_x'] # get mean and std over the domain f_mean, f_var = self.surrogate.predict(x1x2) f_mean = f_mean[:, 0] f_var = f_var[:, 0] f_std = np.sqrt(f_var) acq_dense = acq.evaluate(x1x2) if self.verbose: print("Preparing plots") fig, axes = plt.subplots(nrows=2, ncols=2, figsize=figsize) fig.suptitle("Step " + str(self.curr_bo_step), fontsize=16) levels = np.linspace(np.min(y_grid), np.max(y_grid), 10) # Mean of the GP im1 = axes[0, 0].contourf(x1, x2, f_mean.reshape(n_x1, n_x2), levels=levels) axes[0, 0].plot(self.surrogate.X[:, 0], self.surrogate.X[:, 1], 'r*', markersize=15) if self.curr_bo_step > 0: axes[0, 0].plot(p[0][0, 0], p[0][0, 1], 'c*', markersize=20) axes[0, 0].plot(self.x_min[0], self.x_min[1], 'y*', markersize=18) axes[0, 0].set_title('Mean of the GP') # Chosen task im2 = axes[0, 1].contourf(x1, x2, y_grid.reshape(n_x1, n_x2), levels=levels) axes[0, 1].plot(self.surrogate.X[:, 0], self.surrogate.X[:, 1], 'r*', markersize=15) if self.curr_bo_step > 0: axes[0, 1].plot(p[0][0, 0], p[0][0, 1], 'c*', markersize=20) axes[0, 1].plot(self.x_min[0], self.x_min[1], 'y*', markersize=18) axes[0, 1].set_title(text) # Stdev of GP im3 = axes[1, 0].contourf(x1, x2, f_std.reshape(n_x1, n_x2)) fig.colorbar(im3, ax=axes[1, 0]) axes[1, 0].plot(self.surrogate.X[:, 0], self.surrogate.X[:, 1], 'r*', markersize=15) if self.curr_bo_step > 0: axes[1, 0].plot(p[0][0, 0], p[0][0, 1], 'c*', markersize=20) axes[1, 0].set_title('Stdev of the GP') # Acquisition function im4 = axes[1, 1].contourf(x1, x2, acq_dense.reshape(n_x1, n_x2)) fig.colorbar(im4, ax=axes[1, 1]) axes[1, 1].plot(self.surrogate.X[:, 0], self.surrogate.X[:, 1], 'r*', markersize=15) if self.curr_bo_step > 0: axes[1, 1].plot(p[0][0, 0], p[0][0, 1], 'c*', markersize=20) axes[1, 1].set_title('Acquisition Function') cax = fig.add_axes([0.91, 0.55, 0.015, 0.35]) cb = fig.colorbar(im2, cax=cax) else: raise NotImplementedError if not external_call: if save_plots: self.save_plots_to_disk(fig) else: plt.show() return fig, axes
def _get_y_min(self): """ Get y_min for EI computation Returns smallest y_min of the model. Can change this to evaluate lowest y over domain later. """ if self.verbose: print("Finding y_min") def optimiser_func(x): return self.surrogate.predict(np.atleast_2d(x))[0].flatten() if self.y_min_opt_params['method'] == 'standard': idx = np.argmin(self.surrogate.Y_raw) x_min = self.surrogate.X[idx] y_min = self.surrogate.Y_raw[idx] elif self.y_min_opt_params['method'] == 'direct': def optimiser_func(x): return self.surrogate.predict(np.array([x]))[0] n_direct_evals = self.y_min_opt_params['n_direct_evals'] res = scipydirect.minimize(optimiser_func, self.bounds, maxf=n_direct_evals) x_min = res.x y_min = res.fun elif self.y_min_opt_params['method'] == 'multigrad': num_restarts = self.y_min_opt_params['num_restarts'] res = minimize_with_restarts(optimiser_func, self.bounds, num_restarts=num_restarts, verbose=False) x_min = res.x y_min = res.fun elif self.y_min_opt_params['method'] == 'samplegrad': op = self.y_min_opt_params if 'minimize_options' in op.keys(): minimize_options = op['minimize_options'] else: minimize_options = None if 'num_samples' in op.keys(): num_samples = op['num_samples'] else: num_samples = 1000 if 'num_local' in op.keys(): num_local = op['num_local'] else: num_local = 5 if 'evaluate_sequentially' in op.keys(): evaluate_sequentially = \ op['evaluate_sequentially'] else: evaluate_sequentially = False res = sample_then_minimize( optimiser_func, self.bounds, num_samples=num_samples, num_local=num_local, minimize_options=minimize_options, evaluate_sequentially=evaluate_sequentially, extra_locs=self.surrogate.X, verbose=False) x_min = res.x y_min = res.fun else: raise NotImplementedError _, var_at_y_min = self.surrogate.predict(np.atleast_2d(x_min)) if self.verbose: print(f"Current y_min = {y_min}") return x_min, y_min.item(), var_at_y_min.item()
def _optimise_acq_func(self, acq, max_or_min='max', acq_opt_params=None): """ Run the chosen optimisation procedure """ if self.verbose: print(f"Optimising acquisition function ({max_or_min})") if acq_opt_params is None: acq_opt_params = self.acq_opt_params if max_or_min == 'max': def optimiser_func(x): return -acq.evaluate(np.atleast_2d(x)) elif max_or_min == 'min': def optimiser_func(x): return acq.evaluate(np.atleast_2d(x)) else: raise NotImplementedError if acq_opt_params['method'] == 'direct': n_direct_evals = acq_opt_params['n_direct_evals'] res = scipydirect.minimize(optimiser_func, self.bounds, maxf=n_direct_evals) elif acq_opt_params['method'] == 'multigrad': num_restarts = acq_opt_params['num_restarts'] if 'minimize_options' in acq_opt_params.keys(): minimize_options = acq_opt_params['minimize_options'] else: minimize_options = None res = minimize_with_restarts(optimiser_func, self.bounds, num_restarts=num_restarts, hard_bounds=self.bounds, minimize_options=minimize_options, verbose=False) elif acq_opt_params['method'] == 'samplegrad': if 'minimize_options' in acq_opt_params.keys(): minimize_options = acq_opt_params['minimize_options'] else: minimize_options = None if 'num_samples' in acq_opt_params.keys(): num_samples = acq_opt_params['num_samples'] else: num_samples = 1000 if 'num_local' in acq_opt_params.keys(): num_local = acq_opt_params['num_local'] else: num_local = 5 if 'num_chunks' in acq_opt_params.keys(): num_chunks = acq_opt_params['num_chunks'] else: num_chunks = 5 if 'evaluate_sequentially' in acq_opt_params.keys(): evaluate_sequentially = \ acq_opt_params['evaluate_sequentially'] else: evaluate_sequentially = True res = sample_then_minimize( optimiser_func, self.bounds, num_samples=num_samples, num_local=num_local, num_chunks=num_chunks, minimize_options=minimize_options, evaluate_sequentially=evaluate_sequentially, verbose=False) else: raise NotImplementedError best_x = np.atleast_2d(res.x) # Return the correct value for the acquisition function depending on # whether we minimized or maximized if max_or_min == 'max': best_eval = best_x, -res.fun elif max_or_min == 'min': best_eval = best_x, res.fun else: raise NotImplementedError return best_eval
get_commit_hash, create_default_parser, \ get_interface, get_iters, \ generate_starting_data, create_intial_busy_jobs, \ get_default_hp_priors_and_bounds from ml_utils import timed_print as print # ********* Parser ******** # parser = create_default_parser(synth_time=True) parser.add_argument('-f', '--func', help='Function index.', default=10, type=int) args = parser.parse_args() print(f"Got arguments: \n{args}") # ********* Exp settings ******** # debug = False force_run = False foldername = get_commit_hash(with_date=True) # ********* Overrides ******** # # args.func = 0 # args.proc = 'synch-LP' # args.workers = 4 # args.batch = 4 # ********* Task and data ******** # f, x_lim, true_min_loc, true_min_val = get_math_exp_task(args.func)