def _update_feas_param(self, num=1000): # feas_param values to be considered feas_params = np.linspace(self.feas_param, 0.0, 11) # use known_constraints only, so that we can see how much of the remaining domain is considered feasible # by the classifier random_sampler = RandomSampler(self.config, constraints=self.known_constraints) # draw random samples samples = random_sampler.draw(num=num) for i, feas_param in enumerate(feas_params): feasibility = [ self.bayesian_network.classification_surrogate( sample, threshold=feas_param) for sample in samples ] fraction_feasible = sum(feasibility) / len(feasibility) self.log( f'feas_param: {feas_param}, fraction_feasible: {fraction_feasible}', 'DEBUG') # if at least 10% feasible, feas_param is acceptable if fraction_feasible > 0.1: self.feas_param = feas_param if i != 0: self.log( f'Setting "feas_param" to {feas_param} to have >10% of the optimization domain ' f'classified as feasible', 'WARNING') break # if feas_param == 0 and fraction_feasible == 0, something is wrong if feas_param < 1e-5 and fraction_feasible < 1e-5: raise ValueError( '** feas_param == 0 and fraction_feasible == 0 **')
def __init__(self, config): self.config = config Logger.__init__(self, 'Acquisition', self.config.get('verbosity')) self.random_sampler = RandomSampler(self.config.general, self.config.parameters) self.total_num_vars = len(self.config.feature_names) self.local_optimizers = None self.num_cpus = multiprocessing.cpu_count()
def __init__(self, config): self.config = config Logger.__init__(self, 'Acquisition', self.config.get('verbosity')) self.random_sampler = RandomSampler(self.config.general, self.config.parameters) self.total_num_vars = len(self.config.feature_names) self.local_optimizers = None # figure out how many CPUs to use if self.config.get('num_cpus') == 'all': self.num_cpus = multiprocessing.cpu_count() else: self.num_cpus = int(self.config.get('num_cpus'))
def _propose_randomly_thread(self, best_params, num_samples, acquisition_constraints, dominant_samples=None, return_list=None): """ acquisition_constraints : list list of constraints functions. dominant_samples : dominant samples for batch constraints. """ random_sampler = RandomSampler(self.config, constraints=acquisition_constraints) # ------------------- # get uniform samples # ------------------- if dominant_samples is None: uniform_samples = random_sampler.draw(num=num_samples) perturb_samples = random_sampler.perturb(best_params, num=num_samples) samples = np.concatenate([uniform_samples, perturb_samples]) else: dominant_features = self.config.feature_process_constrained for batch_sample in dominant_samples: uniform_samples = random_sampler.draw(num=num_samples // len(dominant_samples)) perturb_samples = random_sampler.perturb(best_params, num=num_samples) samples = np.concatenate([uniform_samples, perturb_samples]) samples[:, dominant_features] = batch_sample[dominant_features] # append to shared memory list if present if return_list is not None: return_list.append(samples) return samples
class Acquisition(Logger): def __init__(self, config): self.config = config Logger.__init__(self, 'Acquisition', self.config.get('verbosity')) self.random_sampler = RandomSampler(self.config.general, self.config.parameters) self.total_num_vars = len(self.config.feature_names) self.local_optimizers = None self.num_cpus = multiprocessing.cpu_count() def _propose_randomly(self, best_params, num_samples, dominant_samples = None): # get uniform samples if dominant_samples is None: uniform_samples = self.random_sampler.draw(num = self.total_num_vars * num_samples) perturb_samples = self.random_sampler.perturb(best_params, num = self.total_num_vars * num_samples) samples = np.concatenate([uniform_samples, perturb_samples]) else: dominant_features = self.config.feature_process_constrained for batch_sample in dominant_samples: uniform_samples = self.random_sampler.draw(num = self.total_num_vars * num_samples // len(dominant_samples)) perturb_samples = self.random_sampler.perturb(best_params, num = self.total_num_vars * num_samples) samples = np.concatenate([uniform_samples, perturb_samples]) samples[:, dominant_features] = batch_sample[dominant_features] return samples def _proposal_optimization_thread(self, proposals, kernel_contribution, batch_index, return_index, return_dict = None, dominant_samples = None): self.log('starting process for %d' % batch_index, 'INFO') def kernel(x): num, inv_den = kernel_contribution(x) return (num + self.sampling_param_values[batch_index]) * inv_den if dominant_samples is not None: ignore = self.config.feature_process_constrained else: ignore = np.array([False for _ in range(len(self.config.feature_process_constrained))]) local_optimizer = self.local_optimizers[batch_index] local_optimizer.set_func(kernel, ignores = ignore) optimized = [] for sample_index, sample in enumerate(proposals): opt = local_optimizer.optimize(kernel, sample, max_iter = 10) optimized.append(opt) optimized = np.array(optimized) if return_dict.__class__.__name__ == 'DictProxy': return_dict[return_index] = optimized else: return optimized def _optimize_proposals(self, random_proposals, kernel_contribution, dominant_samples = None): if self.config.get('parallel'): result_dict = Manager().dict() # get the number of splits num_splits = self.num_cpus // len(self.sampling_param_values) + 1 split_size = len(random_proposals) // num_splits processes = [] for batch_index in range(len(self.sampling_param_values)): for split_index in range(num_splits): split_start = split_size * split_index split_end = split_size * (split_index + 1) return_index = num_splits * batch_index + split_index process = Process(target = self._proposal_optimization_thread, args = (random_proposals[split_start : split_end], kernel_contribution, batch_index, return_index, result_dict, dominant_samples)) processes.append(process) process.start() for process_index, process in enumerate(processes): process.join() else: num_splits = 1 result_dict = {} for batch_index in range(len(self.sampling_param_values)): return_index = batch_index result_dict[batch_index] = self._proposal_optimization_thread(random_proposals, kernel_contribution, batch_index, return_index, dominant_samples = dominant_samples) # collect optimized samples samples = [] for batch_index in range(len(self.sampling_param_values)): batch_samples = [] for split_index in range(num_splits): return_index = num_splits * batch_index + split_index batch_samples.append(result_dict[return_index]) samples.append(np.concatenate(batch_samples)) samples = np.array(samples) return np.array(samples) def propose(self, best_params, kernel_contribution, sampling_param_values, num_samples = 200, parallel = 'True', dominant_samples = None, dominant_strategy = None, ): self.local_optimizers = [ParameterOptimizer(self.config) for _ in range(len(sampling_param_values))] assert len(self.local_optimizers) == len(sampling_param_values) self.sampling_param_values = sampling_param_values random_proposals = self._propose_randomly( best_params, num_samples, dominant_samples = dominant_samples, ) import time start = time.time() optimized_proposals = self._optimize_proposals( random_proposals, kernel_contribution, dominant_samples = dominant_samples, ) end = time.time() #print('[TIME]: ', end - start, ' (optimizing proposals)') self.log('[TIME]: ' + str(end - start) + ' (optimizing proposals)', 'INFO') extended_proposals = np.array([random_proposals for _ in range(len(sampling_param_values))]) combined_proposals = np.concatenate((extended_proposals, optimized_proposals), axis = 1) return combined_proposals