def maximise_acquisition(self, acq_fn, anc_data, *args, **kwargs): # Merged from multiple places in Dragonfly's code to select the right optimiser # Avoids patching "cp_ga_optimiser_from_proc_args" globally domain, max_evals = anc_data.domain, anc_data.max_evals obj_in_func_caller = CPFunctionCaller(lambda x: acq_fn([x]), domain, domain_orderings=None) worker_manager = SyntheticWorkerManager(1, time_distro='const') if "prev_evaluations" in kwargs: options = { "prev_evaluations": Namespace(qinfos=kwargs["prev_evaluations"]) } else: options = {} if self.acq_opt_method == "aging": _, ga_max_pt, _ = \ build_aging_cp_ga_optimiser(obj_in_func_caller, domain, worker_manager, max_evals, mode='asy', options=None) else: assert self.acq_opt_method == "local" _, ga_max_pt, _ = \ build_local_cp_ga_optimiser(obj_in_func_caller, domain, self.mutate_all, worker_manager, max_evals, mode='asy', options=options) return ga_max_pt
def build_local_cp_ga_optimiser(func_caller, cp_domain, nn_mutate_op, worker_manager, max_capital, mode='asy', orderings=None, options=None, reporter="silent"): """ A GA optimiser on Cartesian product space from the function caller. """ log = logging.getLogger("LocalGA Optimiser") if not isinstance(func_caller, ExperimentCaller): func_caller = CPFunctionCaller(func_caller, cp_domain, domain_orderings=orderings) options = load_options(blackbox_opt_args, partial_options=options) options.mode = mode options.capital_type = 'return_value' start_time = timer() log.info( f"Starting GA optimisation with capital {max_capital} ({options.capital_type})." ) result = LocalCPGAOptimiser(func_caller, nn_mutate_op, worker_manager, options=options, reporter=reporter).optimise(max_capital) end_time = timer() log.info(f"GA optimisation finished, took {(end_time - start_time):.2f}s.") return result
def build_aging_cp_ga_optimiser(func_caller, cp_domain, worker_manager, max_capital, mode='asy', orderings=None, single_mutation_ops=None, single_crossover_ops=None, options=None, reporter="silent"): """ A GA optimiser on Cartesian product space from the function caller. """ log = logging.getLogger("AgingGA Optimiser") if not isinstance(func_caller, ExperimentCaller): func_caller = CPFunctionCaller(func_caller, cp_domain, domain_orderings=orderings) options = load_options(ga_opt_args, partial_options=options) options.mode = mode options.capital_type = 'return_value' options.population_size = 100 options.sample_size = 25 start_time = timer() log.info( f"Starting GA optimisation with capital {max_capital} ({options.capital_type})." ) result = CPGAOptimiser(func_caller, worker_manager, single_mutation_ops=single_mutation_ops, single_crossover_ops=single_crossover_ops, options=options, reporter=reporter).optimise(max_capital) end_time = timer() log.info(f"GA optimisation finished, took {(end_time - start_time):.2f}s.") return result
accuracy = 100 * correct / total return accuracy def parallel_exec(draw): train_instance = Trainable_cifar10() train_instance.reset(*draw) return train_instance.train_and_eval() if __name__ == "__main__": DEBUG = True config = load_config_file('cifar10-dom.json') domain, domain_orderings = config.domain, config.domain_orderings func_caller = CPFunctionCaller(None, domain, domain_orderings=domain_orderings) opt = gp_bandit.CPGPBandit(func_caller, ask_tell_mode=True) opt.initialise() parallel_jobs = 10 train_instance = Trainable_cifar10() while True: results = {} if parallel_jobs > 0: draws = [opt.ask() for _ in range(parallel_jobs)] with Pool(parallel_jobs) as p: accuracies = p.map(parallel_exec, draws) # accuracies = [parallel_exec(d) for d in draws] [opt.tell([(d,a)]) for d,a in zip(draws, accuracies)] results.update({tuple(d):a for d,a in zip(draws, accuracies)})
def maximise_function(func, domain, max_capital, config=None, options=None): """ Maximises a function 'func' over the domain 'domain'. Inputs: func: The function to be maximised. domain: The domain over which the function should be maximised, should be an instance of the Domain class in exd/domains.py. If domain is a list of the form [[l1, u1], [l2, u2], ...] where li < ui, then we will create a Euclidean domain with lower bounds li and upper bounds ui along each dimension. max_capital: The maximum capital (budget) available for optimisation. config: Contains configuration parameters that are typically returned by exd.cp_domain_utils.load_config_file. config can be None only if domain is a EuclideanDomain object. options: Additional hyper-parameters for optimisation. * Alternatively, domain could be None if config is either a path_name to a configuration file or has configuration parameters. Returns: opt_val: The maximum value found during the optimisatio procdure. opt_pt: The corresponding optimum point. history: A record of the optimisation procedure which include the point evaluated and the values at each time step. """ # Preprocess domain and config arguments raw_func = func domain, preproc_func_list, config, _ = _preprocess_arguments( domain, [func], config) func = preproc_func_list[0] # Load arguments depending on domain type if domain.get_type() == 'euclidean': func_caller = EuclideanFunctionCaller(func, domain, vectorised=False) else: func_caller = CPFunctionCaller( func, domain, raw_func=raw_func, domain_orderings=config.domain_orderings) # Create worker manager and function caller worker_manager = SyntheticWorkerManager(num_workers=1) # Optimise function here ----------------------------------------------------------- opt_val, opt_pt, history = gpb_from_func_caller(func_caller, worker_manager, max_capital, is_mf=False, options=options) # Post processing if domain.get_type() == 'euclidean' and config is None: opt_pt = func_caller.get_raw_domain_coords(opt_pt) history.curr_opt_points = [ func_caller.get_raw_domain_coords(pt) for pt in history.curr_opt_points ] history.query_points = [ func_caller.get_raw_domain_coords(pt) for pt in history.query_points ] else: opt_pt = get_raw_from_processed_via_config(opt_pt, config) history.curr_opt_points_raw = [ get_raw_from_processed_via_config(pt, config) for pt in history.curr_opt_points ] history.query_points_raw = [ get_raw_from_processed_via_config(pt, config) for pt in history.query_points ] return opt_val, opt_pt, history
def maximise_multifidelity_function(func, fidel_space, domain, fidel_to_opt, fidel_cost_func, max_capital, config=None, options=None): """ Maximises a multi-fidelity function 'func' over the domain 'domain' and fidelity space 'fidel_space'. Inputs: func: The function to be maximised. Takes two arguments func(z, x) where z is a member of the fidelity space and x is a member of the domain. fidel_space: The fidelity space from which the approximations are obtained. Should be an instance of the Domain class in exd/domains.py. If of the form [[l1, u1], [l2, u2], ...] where li < ui, then we will create a Euclidean domain with lower bounds li and upper bounds ui along each dimension. domain: The domain over which the function should be maximised, should be an instance of the Domain class in exd/domains.py. If domain is a list of the form [[l1, u1], [l2, u2], ...] where li < ui, then we will create a Euclidean domain with lower bounds li and upper bounds ui along each dimension. fidel_to_opt: The point at the fidelity space at which we wish to maximise func. max_capital: The maximum capital (budget) available for optimisation. config: Contains configuration parameters that are typically returned by exd.cp_domain_utils.load_config_file. config can be None only if domain is a EuclideanDomain object. options: Additional hyper-parameters for optimisation. * Alternatively, domain and fidelity space could be None if config is either a path_name to a configuration file or has configuration parameters. Returns: opt_val: The maximum value found during the optimisation procdure. opt_pt: The corresponding optimum point. history: A record of the optimisation procedure which include the point evaluated and the values at each time step. """ # Preprocess domain and config arguments raw_func = func fidel_space, domain, preproc_func_list, fidel_cost_func, fidel_to_opt, config, _ = \ _preprocess_multifidelity_arguments(fidel_space, domain, [func], fidel_cost_func, fidel_to_opt, config) func = preproc_func_list[0] # Load arguments and function caller if fidel_space.get_type() == 'euclidean' and domain.get_type( ) == 'euclidean': func_caller = EuclideanFunctionCaller(func, domain, vectorised=False, raw_fidel_space=fidel_space, fidel_cost_func=fidel_cost_func, raw_fidel_to_opt=fidel_to_opt) else: func_caller = CPFunctionCaller( func, domain, '', raw_func=raw_func, domain_orderings=config.domain_orderings, fidel_space=fidel_space, fidel_cost_func=fidel_cost_func, fidel_to_opt=fidel_to_opt, fidel_space_orderings=config.fidel_space_orderings) # Create worker manager worker_manager = SyntheticWorkerManager(num_workers=1) # Optimise function here ----------------------------------------------------------- opt_val, opt_pt, history = gpb_from_func_caller(func_caller, worker_manager, max_capital, is_mf=True, options=options) # Post processing if domain.get_type() == 'euclidean' and config is None: opt_pt = func_caller.get_raw_domain_coords(opt_pt) history.curr_opt_points = [ func_caller.get_raw_domain_coords(pt) for pt in history.curr_opt_points ] history.query_points = [ func_caller.get_raw_domain_coords(pt) for pt in history.query_points ] else: def _get_raw_from_processed_for_mf(fidel, pt): """ Returns raw point from processed point by accounting for the fact that a point could be None in the multi-fidelity setting. """ if fidel is None or pt is None: return None, None else: return get_raw_from_processed_via_config((fidel, pt), config) # Now re-write curr_opt_points opt_pt = _get_raw_from_processed_for_mf(fidel_to_opt, opt_pt)[1] history.curr_opt_points_raw = [ _get_raw_from_processed_for_mf(fidel_to_opt, pt)[1] for pt in history.curr_opt_points ] query_fidel_points_raw = [ _get_raw_from_processed_for_mf(fidel, pt) for fidel, pt in zip(history.query_fidels, history.query_points) ] history.query_fidels = [zx[0] for zx in query_fidel_points_raw] history.query_points = [zx[1] for zx in query_fidel_points_raw] return opt_val, opt_pt, history
def main(): """ Main function. """ # Load configuration file objective, config_file, mf_cost = _CHOOSER_DICT[PROBLEM] config = load_config_file(config_file) # Specify optimisation method ----------------------------------------------------- opt_method = 'bo' # opt_method = 'ga' # opt_method = 'rand' # Optimise max_capital = 60 domain, domain_orderings = config.domain, config.domain_orderings if PROBLEM in ['3d', '5d']: # Create function caller. # Note there is no function passed in to the Function Caller object. func_caller = CPFunctionCaller(None, domain, domain_orderings=domain_orderings) if opt_method == 'bo': opt = gp_bandit.CPGPBandit(func_caller, ask_tell_mode=True) elif opt_method == 'ga': opt = cp_ga_optimiser.CPGAOptimiser(func_caller, ask_tell_mode=True) elif opt_method == 'rand': opt = random_optimiser.CPRandomOptimiser(func_caller, ask_tell_mode=True) opt.initialise() # Optimize using the ask-tell interface # User continually asks for the next point to evaluate, then tells the optimizer the # new result to perform Bayesian optimisation. best_x, best_y = None, float('-inf') for _ in range(max_capital): x = opt.ask() y = objective(x) opt.tell([(x, y)]) print('x: %s, y: %s' % (x, y)) if y > best_y: best_x, best_y = x, y print("Optimal Value: %s, Optimal Point: %s" % (best_y, best_x)) # Compare results with the maximise_function API print("-------------") print("Compare with maximise_function API:") opt_val, opt_pt, history = maximise_function(objective, config.domain, max_capital, opt_method=opt_method, config=config) elif PROBLEM == '3d_euc': # Create function caller. # Note there is no function passed in to the Function Caller object. domain = domain.list_of_domains[0] func_caller = EuclideanFunctionCaller(None, domain) if opt_method == 'bo': opt = gp_bandit.EuclideanGPBandit(func_caller, ask_tell_mode=True) elif opt_method == 'ga': raise ValueError("Invalid opt_method %s" % (opt_method)) opt.initialise() # Optimize using the ask-tell interface # User continually asks for the next point to evaluate, then tells the optimizer the # new result to perform Bayesian optimisation. best_x, best_y = None, float('-inf') for _ in range(max_capital): # Optionally, you can add an integer argument `n_points` to ask to have it return # `n_points` number of points. These points will be returned as a list. # No argument for `n_points` returns a single point from ask. x = opt.ask() y = objective(x) opt.tell([(x, y)]) print('x: %s, y: %s' % (x, y)) if y > best_y: best_x, best_y = x, y print("Optimal Value: %s, Optimal Point: %s" % (best_y, best_x)) # Compare results with the maximise_function API print("-------------") print("Compare with maximise_function API:") opt_val, opt_pt, history = maximise_function(objective, config.domain, max_capital, opt_method=opt_method, config=config) else: # Create function caller. # Note there is no function passed in to the Function Caller object. (ask_tell_fidel_space, ask_tell_domain, _, ask_tell_mf_cost, ask_tell_fidel_to_opt, ask_tell_config, _) = \ preprocess_multifidelity_arguments(config.fidel_space, domain, [objective], mf_cost, config.fidel_to_opt, config) func_caller = CPFunctionCaller( None, ask_tell_domain, domain_orderings=domain_orderings, fidel_space=ask_tell_fidel_space, fidel_cost_func=ask_tell_mf_cost, fidel_to_opt=ask_tell_fidel_to_opt, fidel_space_orderings=config.fidel_space_orderings, config=ask_tell_config) if opt_method == 'bo': opt = gp_bandit.CPGPBandit(func_caller, is_mf=True, ask_tell_mode=True) else: raise ValueError("Invalid opt_method %s" % (opt_method)) opt.initialise() # Optimize using the ask-tell interface # User continually asks for the next point to evaluate, then tells the optimizer the # new result to perform Bayesian optimisation. best_z, best_x, best_y = None, None, float('-inf') for _ in range(max_capital): point = opt.ask() z, x = point[0], point[1] y = objective(z, x) opt.tell([(z, x, y)]) print('z: %s, x: %s, y: %s' % (z, x, y)) if y > best_y: best_z, best_x, best_y = z, x, y print("Optimal Value: %s, Optimal Point: %s" % (best_y, best_x)) # Compare results with the maximise_multifidelity_function API print("-------------") print("Compare with maximise_multifidelity_function API:") opt_val, opt_pt, history = maximise_multifidelity_function( objective, config.fidel_space, config.domain, config.fidel_to_opt, mf_cost, max_capital, opt_method=opt_method, config=config) print('opt_pt: %s' % (str(opt_pt))) print('opt_val: %s' % (str(opt_val)))