From 97d5b23358bd8bf19ba818588a3e5d279809fc4a Mon Sep 17 00:00:00 2001 From: Michael Hush Date: Thu, 1 Dec 2016 10:50:26 +1100 Subject: [PATCH 1/2] Added visualization introduced bug Visualizations now work for NN and GP learners. Mysterious bug has appeared in GP. The scikit-learn stops providing uncertainty predictions after being fit for a certain number of times. Commiting so I can change branch and investigate. --- mloop/controllers.py | 45 +++++++---- mloop/learners.py | 193 ++++++++++++++++++++++++++++++++++++------------ mloop/utilities.py | 16 ++++ mloop/visualizations.py | 144 +++++++++++++++++++++++++++++++++++- 4 files changed, 335 insertions(+), 63 deletions(-) diff --git a/mloop/controllers.py b/mloop/controllers.py index ca2035a..4352a40 100644 --- a/mloop/controllers.py +++ b/mloop/controllers.py @@ -11,8 +11,8 @@ import logging import os -controller_dict = {'random':1,'nelder_mead':2,'gaussian_process':3,'differential_evolution':4} -number_of_controllers = 4 +controller_dict = {'random':1,'nelder_mead':2,'gaussian_process':3,'differential_evolution':4,'neural_net':5} +number_of_controllers = 5 default_controller_archive_filename = 'controller_archive' default_controller_archive_file_type = 'txt' @@ -338,6 +338,7 @@ def optimize(self): log.info('Controller finished. Closing down M-LOOP. Please wait a moment...') except ControllerInterrupt: self.log.warning('Controller ended by interruption.') + ''' except (KeyboardInterrupt,SystemExit): log.warning('!!! Do not give the interrupt signal again !!! \n M-LOOP stopped with keyboard interupt or system exit. Please wait at least 1 minute for the threads to safely shut down. \n ') log.warning('Closing down controller.') @@ -347,6 +348,7 @@ def optimize(self): self.log.warning('Safely shut down. Below are results found before exception.') self.print_results() raise + ''' self._shut_down() self.print_results() self.log.info('M-LOOP Done.') @@ -539,6 +541,7 @@ class MachineLearnerController(Controller): def __init__(self, interface, training_type='differential_evolution', + machine_learner_type='machine_learner', num_training_runs=None, no_delay=True, num_params=None, @@ -551,6 +554,8 @@ def __init__(self, interface, super(MachineLearnerController,self).__init__(interface, **kwargs) + self.machine_learner_type = machine_learner_type + self.last_training_cost = None self.last_training_bad = None self.last_training_run_flag = False @@ -678,13 +683,14 @@ def _optimization_routine(self): self._put_params_and_out_dict(next_params) self.save_archive() self._get_cost_and_in_dict() + while (self.num_in_costs < self.num_training_runs) and self.check_end_conditions(): self.log.info('Run:' + str(self.num_in_costs +1)) next_params = self._next_params() self._put_params_and_out_dict(next_params) self.save_archive() self._get_cost_and_in_dict() - + if self.check_end_conditions(): #Start last training run self.log.info('Run:' + str(self.num_in_costs +1)) @@ -701,19 +707,26 @@ def _optimization_routine(self): ml_count = 0 while self.check_end_conditions(): + print('1-1.') self.log.info('Run:' + str(self.num_in_costs +1)) if ml_consec==self.generation_num or (self.no_delay and self.ml_learner_params_queue.empty()): + print('1-2.') next_params = self._next_params() + print('1-3.') self._put_params_and_out_dict(next_params) ml_consec = 0 else: + print('1-4.') next_params = self.ml_learner_params_queue.get() - super(MachineLearnerController,self)._put_params_and_out_dict(next_params, param_type='gaussian_process') + print('1-5.') + super(MachineLearnerController,self)._put_params_and_out_dict(next_params, param_type=self.machine_learner_type) ml_consec += 1 ml_count += 1 - - if ml_count%self.generation_num == 2: + if ml_count==self.generation_num: + print('1-6.') self.new_params_event.set() + ml_count = 0 + self.save_archive() self._get_cost_and_in_dict() @@ -789,6 +802,7 @@ def __init__(self, interface, **kwargs): super(GaussianProcessController,self).__init__(interface, + machine_learner_type='gaussian_process', num_params=num_params, min_boundary=min_boundary, max_boundary=max_boundary, @@ -829,15 +843,16 @@ def __init__(self, interface, learner_archive_file_type = mll.default_learner_archive_file_type, **kwargs): - super(GaussianProcessController,self).__init__(interface, - num_params=num_params, - min_boundary=min_boundary, - max_boundary=max_boundary, - trust_region=trust_region, - learner_archive_filename=learner_archive_filename, - learner_archive_file_type=learner_archive_file_type, - **kwargs) - + super(NeuralNetController,self).__init__(interface, + machine_learner_type='neural_net', + num_params=num_params, + min_boundary=min_boundary, + max_boundary=max_boundary, + trust_region=trust_region, + learner_archive_filename=learner_archive_filename, + learner_archive_file_type=learner_archive_file_type, + **kwargs) + self.ml_learner = mll.NeuralNetLearner(start_datetime=self.start_datetime, num_params=num_params, min_boundary=min_boundary, diff --git a/mloop/learners.py b/mloop/learners.py index ed15093..9aefa99 100644 --- a/mloop/learners.py +++ b/mloop/learners.py @@ -91,6 +91,7 @@ def __init__(self, self.min_boundary = np.full((self.num_params,), -1.0) else: self.min_boundary = np.array(min_boundary, dtype=np.float) + if self.min_boundary.shape != (self.num_params,): self.log.error('min_boundary array the wrong shape:' + repr(self.min_boundary.shape)) raise ValueError @@ -130,6 +131,9 @@ def __init__(self, self.log.debug('Learner init completed.') + + + def check_num_params(self,param): ''' Check the number of parameters is right. @@ -918,12 +922,12 @@ def __init__(self, #Basic optimization settings num_params = int(self.training_dict['num_params']) - min_boundary = np.squeeze(np.array(self.training_dict['min_boundary'], dtype=float)) - max_boundary = np.squeeze(np.array(self.training_dict['max_boundary'], dtype=float)) + min_boundary = mlu.safe_cast_to_list(self.training_dict['min_boundary']) + max_boundary = mlu.safe_cast_to_list(self.training_dict['max_boundary']) #Configuration of the learner self.cost_has_noise = bool(self.training_dict['cost_has_noise']) - self.length_scale = np.squeeze(np.array(self.training_dict['length_scale'])) + self.length_scale = mlu.safe_squeeze(self.training_dict['length_scale']) self.length_scale_history = list(self.training_dict['length_scale_history']) self.noise_level = float(self.training_dict['noise_level']) self.noise_level_history = mlu.safe_cast_to_list(self.training_dict['noise_level_history']) @@ -935,20 +939,20 @@ def __init__(self, #Data from previous experiment self.all_params = np.array(self.training_dict['all_params'], dtype=float) - self.all_costs = np.squeeze(np.array(self.training_dict['all_costs'], dtype=float)) - self.all_uncers = np.squeeze(np.array(self.training_dict['all_uncers'], dtype=float)) + self.all_costs = mlu.safe_squeeze(self.training_dict['all_costs']) + self.all_uncers = mlu.safe_squeeze(self.training_dict['all_uncers']) self.bad_run_indexs = mlu.safe_cast_to_list(self.training_dict['bad_run_indexs']) #Derived properties self.best_cost = float(self.training_dict['best_cost']) - self.best_params = np.squeeze(np.array(self.training_dict['best_params'], dtype=float)) + self.best_params = mlu.safe_squeeze(self.training_dict['best_params']) self.best_index = int(self.training_dict['best_index']) self.worst_cost = float(self.training_dict['worst_cost']) self.worst_index = int(self.training_dict['worst_index']) self.cost_range = float(self.training_dict['cost_range']) try: - self.predicted_best_parameters = np.squeeze(np.array(self.training_dict['predicted_best_parameters'])) + self.predicted_best_parameters = mlu.safe_squeeze(self.training_dict['predicted_best_parameters']) self.predicted_best_cost = float(self.training_dict['predicted_best_cost']) self.predicted_best_uncertainty = float(self.training_dict['predicted_best_uncertainty']) self.has_global_minima = True @@ -969,7 +973,6 @@ def __init__(self, self.has_local_minima = True except KeyError: self.has_local_minima = False - super(GaussianProcessLearner,self).__init__(num_params=num_params, min_boundary=min_boundary, @@ -1024,9 +1027,6 @@ def __init__(self, self.bias_func_cost_factor = [1.0,1.0,1.0,1.0] self.bias_func_uncer_factor =[0.0,1.0,2.0,3.0] self.generation_num = self.bias_func_cycle - if self.generation_num < 3: - self.log.error('Number in generation must be larger than 2.') - raise ValueError #Constants, limits and tolerances self.search_precision = 1.0e-6 @@ -1188,7 +1188,7 @@ def get_params_and_costs(self): self.cost_range = self.worst_cost - self.best_cost if not self.bad_defaults_set: update_bads_flag = True - + new_params.append(param) new_costs.append(cost) new_uncers.append(uncer) @@ -1263,13 +1263,13 @@ def update_archive(self): 'update_hyperparameters':self.update_hyperparameters, 'length_scale':self.length_scale, 'noise_level':self.noise_level}) - - + def fit_gaussian_process(self): ''' Fit the Gaussian process to the current data ''' + print('3-1') self.log.debug('Fitting Gaussian process.') if self.all_params.size==0 or self.all_costs.size==0 or self.all_uncers.size==0: self.log.error('Asked to fit GP but no data is in all_costs, all_params or all_uncers.') @@ -1279,6 +1279,7 @@ def fit_gaussian_process(self): self.gaussian_process.alpha_ = self.scaled_uncers self.gaussian_process.fit(self.all_params,self.scaled_costs) + print('3-2') if self.update_hyperparameters: self.fit_count += 1 @@ -1296,6 +1297,9 @@ def fit_gaussian_process(self): else: self.length_scale = last_hyperparameters['length_scale'] self.length_scale_history.append(self.length_scale) + print('3-3') + print(repr(self.length_scale)) + print(repr(self.noise_level)) def update_bias_function(self): @@ -1313,7 +1317,10 @@ def predict_biased_cost(self,params): Returns: pred_bias_cost (float): Biased cost predicted at the given parameters ''' + #print('2-8-1-1.') + #(pred_cost, pred_uncer) = (self.gaussian_process.predict(params[np.newaxis,:]), 0.1) (pred_cost, pred_uncer) = self.gaussian_process.predict(params[np.newaxis,:], return_std=True) + #print('2-8-1-2.') return self.cost_bias*pred_cost - self.uncer_bias*pred_uncer def find_next_parameters(self): @@ -1324,15 +1331,20 @@ def find_next_parameters(self): next_params (array): Returns next parameters from biased cost search. ''' self.params_count += 1 + print('2-6.') self.update_bias_function() self.update_search_params() next_params = None next_cost = float('inf') + print('2-7.') for start_params in self.search_params: + print('2-8-1.') result = so.minimize(self.predict_biased_cost, start_params, bounds = self.search_region, tol=self.search_precision) + print('2-8-2.') if result.fun < next_cost: next_params = result.x next_cost = result.fun + print('2-9.') return next_params def run(self): @@ -1347,13 +1359,18 @@ def run(self): while not self.end_event.is_set(): #self.log.debug('Learner waiting for new params event') self.save_archive() + print('2-1.') self.wait_for_new_params_event() #self.log.debug('Gaussian process learner reading costs') + print('2-2.') self.get_params_and_costs() + print('2-4.') self.fit_gaussian_process() for _ in range(self.generation_num): + print('2-5.') self.log.debug('Gaussian process learner generating parameter:'+ str(self.params_count+1)) next_params = self.find_next_parameters() + print('2-10.') self.params_out_queue.put(next_params) if self.end_event.is_set(): raise LearnerInterrupt() @@ -1520,41 +1537,106 @@ def __init__(self, predict_local_minima_at_end = False, **kwargs): - + if nn_training_filename is not None: + + nn_training_filename = str(nn_training_filename) + nn_training_file_type = str(nn_training_file_type) + if not mlu.check_file_type_supported(nn_training_file_type): + self.log.error('GP training file type not supported' + repr(nn_training_file_type)) + + self.training_dict = mlu.get_dict_from_file(nn_training_filename, nn_training_file_type) + + #Basic optimization settings + num_params = int(self.training_dict['num_params']) + min_boundary = mlu.safe_cast_to_list(self.training_dict['min_boundary']) + max_boundary = mlu.safe_cast_to_list(self.training_dict['max_boundary']) + + #Counters + self.costs_count = int(self.training_dict['costs_count']) + self.fit_count = int(self.training_dict['fit_count']) + self.params_count = int(self.training_dict['params_count']) - super(NeuralNetLearner,self).__init__(**kwargs) - - #Storage variables, archived - self.all_params = np.array([], dtype=float) - self.all_costs = np.array([], dtype=float) - self.all_uncers = np.array([], dtype=float) - self.bad_run_indexs = [] - self.best_cost = float('inf') - self.best_params = float('nan') - self.best_index = 0 - self.worst_cost = float('-inf') - self.worst_index = 0 - self.cost_range = float('inf') - self.length_scale_history = [] - self.noise_level_history = [] - - self.costs_count = 0 - self.fit_count = 0 - self.params_count = 0 - - self.has_local_minima = False - self.has_global_minima = False + #Data from previous experiment + self.all_params = np.array(self.training_dict['all_params'], dtype=float) + self.all_costs = mlu.safe_squeeze(self.training_dict['all_costs']) + self.all_uncers = mlu.safe_squeeze(self.training_dict['all_uncers']) + + self.bad_run_indexs = mlu.safe_cast_to_list(self.training_dict['bad_run_indexs']) + #Derived properties + self.best_cost = float(self.training_dict['best_cost']) + self.best_params = mlu.safe_squeeze(self.training_dict['best_params']) + self.best_index = int(self.training_dict['best_index']) + self.worst_cost = float(self.training_dict['worst_cost']) + self.worst_index = int(self.training_dict['worst_index']) + self.cost_range = float(self.training_dict['cost_range']) + + #Configuration of the fake neural net learner + self.length_scale = mlu.safe_squeeze(self.training_dict['length_scale']) + self.noise_level = float(self.training_dict['noise_level']) + + + try: + self.predicted_best_parameters = mlu.safe_squeeze(self.training_dict['predicted_best_parameters']) + self.predicted_best_cost = float(self.training_dict['predicted_best_cost']) + self.predicted_best_uncertainty = float(self.training_dict['predicted_best_uncertainty']) + self.has_global_minima = True + except KeyError: + self.has_global_minima = False + try: + self.local_minima_parameters = list(self.training_dict['local_minima_parameters']) + + if isinstance(self.training_dict['local_minima_costs'], np.ndarray): + self.local_minima_costs = list(np.squeeze(self.training_dict['local_minima_costs'])) + else: + self.local_minima_costs = list(self.training_dict['local_minima_costs']) + if isinstance(self.training_dict['local_minima_uncers'], np.ndarray): + self.local_minima_uncers = list(np.squeeze(self.training_dict['local_minima_uncers'])) + else: + self.local_minima_uncers = list(self.training_dict['local_minima_uncers']) + + self.has_local_minima = True + except KeyError: + self.has_local_minima = False + + super(NeuralNetLearner,self).__init__(num_params=num_params, + min_boundary=min_boundary, + max_boundary=max_boundary, + **kwargs) + else: + + super(NeuralNetLearner,self).__init__(**kwargs) + + #Storage variables, archived + self.all_params = np.array([], dtype=float) + self.all_costs = np.array([], dtype=float) + self.all_uncers = np.array([], dtype=float) + self.bad_run_indexs = [] + self.best_cost = float('inf') + self.best_params = float('nan') + self.best_index = 0 + self.worst_cost = float('-inf') + self.worst_index = 0 + self.cost_range = float('inf') + self.length_scale_history = [] + self.noise_level_history = [] + + self.costs_count = 0 + self.fit_count = 0 + self.params_count = 0 + + self.has_local_minima = False + self.has_global_minima = False + #Multiprocessor controls self.new_params_event = mp.Event() #Storage variables and counters self.search_params = [] self.scaled_costs = None - self.cost_bias = None - self.uncer_bias = None #Constants, limits and tolerances + self.generation_num = 1 self.search_precision = 1.0e-6 self.parameter_searches = max(10,self.num_params) self.hyperparameter_searches = max(10,self.num_params) @@ -1572,6 +1654,13 @@ def __init__(self, self.default_bad_uncertainty = float(default_bad_uncertainty) else: self.default_bad_uncertainty = None + if (self.default_bad_cost is None) and (self.default_bad_uncertainty is None): + self.bad_defaults_set = False + elif (self.default_bad_cost is not None) and (self.default_bad_uncertainty is not None): + self.bad_defaults_set = True + else: + self.log.error('Both the default cost and uncertainty must be set for a bad run or they must both be set to None.') + raise ValueError self._set_trust_region(trust_region) @@ -1590,7 +1679,7 @@ def __init__(self, self.cost_has_noise = True self.noise_level = 1 - self.create_nerual_net() + self.create_neural_net() @@ -1638,6 +1727,7 @@ def fit_neural_net(self): Fit the Neural Net with the appropriate topology to the data ''' + self.log.debug('Fitting Gaussian process.') if self.all_params.size==0 or self.all_costs.size==0 or self.all_uncers.size==0: self.log.error('Asked to fit GP but no data is in all_costs, all_params or all_uncers.') @@ -1674,7 +1764,17 @@ def predict_cost(self,params): float : Predicted cost at paramters ''' return self.gaussian_process.predict(params[np.newaxis,:]) - + + + def predict_costs_from_param_array(self,params): + ''' + Produces a prediction of costs from an array of params. + + Returns: + float : Predicted cost at paramters + ''' + return self.gaussian_process.predict(params) + #--- FAKE NN CONSTRUCTOR END ---# @@ -1817,7 +1917,9 @@ def update_archive(self): 'fit_count':self.fit_count, 'costs_count':self.costs_count, 'params_count':self.params_count, - 'update_hyperparameters':self.update_hyperparameters}) + 'update_hyperparameters':self.update_hyperparameters, + 'length_scale':self.length_scale, + 'noise_level':self.noise_level}) def find_next_parameters(self): ''' @@ -1827,12 +1929,11 @@ def find_next_parameters(self): next_params (array): Returns next parameters from biased cost search. ''' self.params_count += 1 - self.update_bias_function() self.update_search_params() next_params = None next_cost = float('inf') for start_params in self.search_params: - result = so.minimize(self.predict_biased_cost, start_params, bounds = self.search_region, tol=self.search_precision) + result = so.minimize(self.predict_cost, start_params, bounds = self.search_region, tol=self.search_precision) if result.fun < next_cost: next_params = result.x next_cost = result.fun @@ -1853,7 +1954,7 @@ def run(self): self.wait_for_new_params_event() #self.log.debug('Gaussian process learner reading costs') self.get_params_and_costs() - self.fit_gaussian_process() + self.fit_neural_net() for _ in range(self.generation_num): self.log.debug('Gaussian process learner generating parameter:'+ str(self.params_count+1)) next_params = self.find_next_parameters() @@ -1864,7 +1965,7 @@ def run(self): pass if self.predict_global_minima_at_end or self.predict_local_minima_at_end: self.get_params_and_costs() - self.fit_gaussian_process() + self.fit_neural_net() end_dict = {} if self.predict_global_minima_at_end: self.find_global_minima() diff --git a/mloop/utilities.py b/mloop/utilities.py index cd35aee..7efdd08 100644 --- a/mloop/utilities.py +++ b/mloop/utilities.py @@ -197,7 +197,23 @@ def safe_cast_to_list(in_array): out_list = list(in_array) return out_list + +def safe_squeeze(in_array, set_dtype = float): + ''' + Attempts to squeeze an array, but has a different behavior for arrays with only a single value. + + Args: + in_array (array): The array to be squeezed + + Returns: + array: Array. + ''' + + out_array = np.squeeze(np.array(in_array, dtype=set_dtype)) + if out_array.shape == (): + out_array = np.array([out_array[()]]) + return out_array class NullQueueListener(): ''' diff --git a/mloop/visualizations.py b/mloop/visualizations.py index 6505c38..be8c5f3 100644 --- a/mloop/visualizations.py +++ b/mloop/visualizations.py @@ -43,6 +43,12 @@ def show_all_default_visualizations(controller, show_plots=True): log.debug('Creating differential evolution visualizations.') create_differential_evolution_learner_visualizations(controller.learner.total_archive_filename, file_type=controller.learner.learner_archive_file_type) + + if isinstance(controller, mlc.NeuralNetController): + log.debug('Creating neural net visualizations.') + create_neural_net_learner_visualizations(controller.ml_learner.total_archive_filename, + file_type=controller.learner.learner_archive_file_type) + if isinstance(controller, mlc.GaussianProcessController): log.debug('Creating gaussian process visualizations.') @@ -51,6 +57,7 @@ def show_all_default_visualizations(controller, show_plots=True): file_type=controller.ml_learner.learner_archive_file_type, plot_all_minima_vs_cost=plot_all_minima_vs_cost_flag) + log.info('Showing visualizations, close all to end MLOOP.') if show_plots: plt.show() @@ -375,8 +382,8 @@ class GaussianProcessVisualizer(mll.GaussianProcessLearner): def __init__(self, filename, file_type = 'pkl', **kwargs): - super(GaussianProcessVisualizer, self).__init__(ml_training_filename = filename, - ml_training_file_type = file_type, + super(GaussianProcessVisualizer, self).__init__(gp_training_filename = filename, + gp_training_file_type = file_type, update_hyperparameters = False, **kwargs) @@ -545,4 +552,137 @@ def plot_hyperparameters_vs_run(self): plt.xlabel(run_label) plt.ylabel(noise_label) plt.title('GP Learner: Noise level vs fit number.') + +def create_neural_net_learner_visualizations(filename, + file_type='pkl', + plot_cross_sections=True): + ''' + Creates plots from a neural nets learner file. + + Args: + filename (Optional [string]): Filename for the neural net archive. Must provide datetime or filename. Default None. + + Keyword Args: + file_type (Optional [string]): File type 'pkl' pickle, 'mat' matlab or 'txt' text. + plot_cross_sections (Optional [bool]): If True plot predict landscape cross sections, else do not. Default True. + plot_all_minima_vs_cost (Optional [bool]): If True plot all minima parameters versus cost number, False does not. If None it will only make the plots if all minima were previously calculated. Default None. + ''' + visualization = NeuralNetVisualizer(filename, file_type=file_type) + if plot_cross_sections: + visualization.plot_cross_sections() + + +class NeuralNetVisualizer(mll.NeuralNetLearner): + ''' + NeuralNetVisualizer extends of NeuralNetLearner, designed not to be used as a learner, but to instead post process a NeuralNetLearner archive file and produce useful data for visualization of the state of the learner. + + Args: + filename (String): Filename of the GaussianProcessLearner archive. + + Keyword Args: + file_type (String): Can be 'mat' for matlab, 'pkl' for pickle or 'txt' for text. Default 'pkl'. + + ''' + + def __init__(self, filename, file_type = 'pkl', **kwargs): + + super(NeuralNetVisualizer, self).__init__(nn_training_filename = filename, + nn_training_file_type = file_type, + update_hyperparameters = False, + **kwargs) + + self.log = logging.getLogger(__name__) + + #Trust region + self.has_trust_region = bool(np.array(self.training_dict['has_trust_region'])) + self.trust_region = np.squeeze(np.array(self.training_dict['trust_region'], dtype=float)) + + self.create_neural_net() + self.fit_neural_net() + + if np.all(np.isfinite(self.min_boundary)) and np.all(np.isfinite(self.min_boundary)): + self.finite_flag = True + self.param_scaler = lambda p: (p-self.min_boundary)/self.diff_boundary + else: + self.finite_flag = False + + self.param_colors = _color_list_from_num_of_params(self.num_params) + if self.has_trust_region: + self.scaled_trust_min = self.param_scaler(np.maximum(self.best_params - self.trust_region, self.min_boundary)) + self.scaled_trust_max = self.param_scaler(np.minimum(self.best_params + self.trust_region, self.max_boundary)) + + def run(self): + ''' + Overides the GaussianProcessLearner multiprocessor run routine. Does nothing but makes a warning. + ''' + self.log.warning('You should not have executed start() from the GaussianProcessVisualizer. It is not intended to be used as a independent process. Ending.') + + + def return_cross_sections(self, points=100, cross_section_center=None): + ''' + Finds the predicted global minima, then returns a list of vectors of parameters values, costs and uncertainties, corresponding to the 1D cross sections along each parameter axis through the predicted global minima. + + Keyword Args: + points (int): the number of points to sample along each cross section. Default value is 100. + cross_section_center (array): parameter array where the centre of the cross section should be taken. If None, the parameters for the best returned cost are used. + + Returns: + a tuple (cross_arrays, cost_arrays, uncer_arrays) + cross_parameter_arrays (list): a list of arrays for each cross section, with the values of the varied parameter going from the minimum to maximum value. + cost_arrays (list): a list of arrays for the costs evaluated along each cross section about the minimum. + uncertainty_arrays (list): a list of uncertainties + + ''' + points = int(points) + if points <= 0: + self.log.error('Points provided must be larger than zero:' + repr(points)) + raise ValueError + + if cross_section_center is None: + cross_section_center = self.best_params + else: + cross_section_center = np.array(cross_section_center) + if not self.check_in_boundary(cross_section_center): + self.log.error('cross_section_center not in boundaries:' + repr(cross_section_center)) + raise ValueError + + cross_parameter_arrays = [ np.linspace(min_p, max_p, points) for (min_p,max_p) in zip(self.min_boundary,self.max_boundary)] + cost_arrays = [] + for ind in range(self.num_params): + sample_parameters = np.array([cross_section_center for _ in range(points)]) + sample_parameters[:, ind] = cross_parameter_arrays[ind] + costs = self.predict_costs_from_param_array(sample_parameters) + cost_arrays.append(costs) + cross_parameter_arrays = np.array(cross_parameter_arrays)/self.cost_scaler.scale_ + cost_arrays = self.cost_scaler.inverse_transform(np.array(cost_arrays)) + return (cross_parameter_arrays,cost_arrays) + + def plot_cross_sections(self): + ''' + Produce a figure of the cross section about best cost and parameters + ''' + global figure_counter, legend_loc + figure_counter += 1 + plt.figure(figure_counter) + points = 100 + (_,cost_arrays) = self.return_cross_sections(points=points) + rel_params = np.linspace(0,1,points) + for ind in range(self.num_params): + plt.plot(rel_params,cost_arrays[ind,:],'-',color=self.param_colors[ind]) + if self.has_trust_region: + axes = plt.gca() + ymin, ymax = axes.get_ylim() + ytrust = ymin + 0.1*(ymax - ymin) + for ind in range(self.num_params): + plt.plot([self.scaled_trust_min[ind],self.scaled_trust_max[ind]],[ytrust,ytrust],'s', color=self.param_colors[ind]) + plt.xlabel(scale_param_label) + plt.xlim((0,1)) + plt.ylabel(cost_label) + plt.title('NN Learner: Predicted landscape' + ('with trust regions.' if self.has_trust_region else '.')) + artists = [] + for ind in range(self.num_params): + artists.append(plt.Line2D((0,1),(0,0), color=self.param_colors[ind], linestyle='-')) + plt.legend(artists,[str(x) for x in range(1,self.num_params+1)],loc=legend_loc) + + \ No newline at end of file From e8a87155d61406e8f0d06c986883e085a6c93eff Mon Sep 17 00:00:00 2001 From: Michael Hush Date: Thu, 1 Dec 2016 11:44:39 +1100 Subject: [PATCH 2/2] NerualNet ready for actually net MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There appears to be some issues with multiprocessing and gaussian process but only on MacOS, and possibly just my machine. So I’ve removed all the testing statements I had in the previous commit. Branch should be ready now to integrate in a genuine NN. --- mloop/controllers.py | 8 -------- mloop/learners.py | 20 +------------------- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/mloop/controllers.py b/mloop/controllers.py index 4352a40..486bc3e 100644 --- a/mloop/controllers.py +++ b/mloop/controllers.py @@ -338,7 +338,6 @@ def optimize(self): log.info('Controller finished. Closing down M-LOOP. Please wait a moment...') except ControllerInterrupt: self.log.warning('Controller ended by interruption.') - ''' except (KeyboardInterrupt,SystemExit): log.warning('!!! Do not give the interrupt signal again !!! \n M-LOOP stopped with keyboard interupt or system exit. Please wait at least 1 minute for the threads to safely shut down. \n ') log.warning('Closing down controller.') @@ -348,7 +347,6 @@ def optimize(self): self.log.warning('Safely shut down. Below are results found before exception.') self.print_results() raise - ''' self._shut_down() self.print_results() self.log.info('M-LOOP Done.') @@ -707,23 +705,17 @@ def _optimization_routine(self): ml_count = 0 while self.check_end_conditions(): - print('1-1.') self.log.info('Run:' + str(self.num_in_costs +1)) if ml_consec==self.generation_num or (self.no_delay and self.ml_learner_params_queue.empty()): - print('1-2.') next_params = self._next_params() - print('1-3.') self._put_params_and_out_dict(next_params) ml_consec = 0 else: - print('1-4.') next_params = self.ml_learner_params_queue.get() - print('1-5.') super(MachineLearnerController,self)._put_params_and_out_dict(next_params, param_type=self.machine_learner_type) ml_consec += 1 ml_count += 1 if ml_count==self.generation_num: - print('1-6.') self.new_params_event.set() ml_count = 0 diff --git a/mloop/learners.py b/mloop/learners.py index 9aefa99..a931c93 100644 --- a/mloop/learners.py +++ b/mloop/learners.py @@ -1269,7 +1269,6 @@ def fit_gaussian_process(self): ''' Fit the Gaussian process to the current data ''' - print('3-1') self.log.debug('Fitting Gaussian process.') if self.all_params.size==0 or self.all_costs.size==0 or self.all_uncers.size==0: self.log.error('Asked to fit GP but no data is in all_costs, all_params or all_uncers.') @@ -1279,7 +1278,6 @@ def fit_gaussian_process(self): self.gaussian_process.alpha_ = self.scaled_uncers self.gaussian_process.fit(self.all_params,self.scaled_costs) - print('3-2') if self.update_hyperparameters: self.fit_count += 1 @@ -1297,10 +1295,7 @@ def fit_gaussian_process(self): else: self.length_scale = last_hyperparameters['length_scale'] self.length_scale_history.append(self.length_scale) - print('3-3') - print(repr(self.length_scale)) - print(repr(self.noise_level)) - + def update_bias_function(self): ''' @@ -1317,10 +1312,7 @@ def predict_biased_cost(self,params): Returns: pred_bias_cost (float): Biased cost predicted at the given parameters ''' - #print('2-8-1-1.') - #(pred_cost, pred_uncer) = (self.gaussian_process.predict(params[np.newaxis,:]), 0.1) (pred_cost, pred_uncer) = self.gaussian_process.predict(params[np.newaxis,:], return_std=True) - #print('2-8-1-2.') return self.cost_bias*pred_cost - self.uncer_bias*pred_uncer def find_next_parameters(self): @@ -1331,20 +1323,15 @@ def find_next_parameters(self): next_params (array): Returns next parameters from biased cost search. ''' self.params_count += 1 - print('2-6.') self.update_bias_function() self.update_search_params() next_params = None next_cost = float('inf') - print('2-7.') for start_params in self.search_params: - print('2-8-1.') result = so.minimize(self.predict_biased_cost, start_params, bounds = self.search_region, tol=self.search_precision) - print('2-8-2.') if result.fun < next_cost: next_params = result.x next_cost = result.fun - print('2-9.') return next_params def run(self): @@ -1359,18 +1346,13 @@ def run(self): while not self.end_event.is_set(): #self.log.debug('Learner waiting for new params event') self.save_archive() - print('2-1.') self.wait_for_new_params_event() #self.log.debug('Gaussian process learner reading costs') - print('2-2.') self.get_params_and_costs() - print('2-4.') self.fit_gaussian_process() for _ in range(self.generation_num): - print('2-5.') self.log.debug('Gaussian process learner generating parameter:'+ str(self.params_count+1)) next_params = self.find_next_parameters() - print('2-10.') self.params_out_queue.put(next_params) if self.end_event.is_set(): raise LearnerInterrupt()