Beispiel #1
0
    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)
Beispiel #2
0
    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
Beispiel #3
0
    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)
Beispiel #4
0
    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")
Beispiel #5
0
    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()
Beispiel #6
0
    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!")
Beispiel #8
0
    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
Beispiel #9
0
    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")
Beispiel #10
0
    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()
Beispiel #11
0
    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.")
Beispiel #12
0
    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
Beispiel #13
0
    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()
Beispiel #14
0
    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)