def _maximize_over_fixed_effects(self): """ Update the model fixed effects for which no closed-form update is available (i.e. based on sufficient statistics). """ # Default optimizer, if not initialized in the launcher. # Should better be done in a dedicated initializing method. TODO. if self.statistical_model.has_maximization_procedure is not None \ and self.statistical_model.has_maximization_procedure: self.statistical_model.maximize(self.individual_RER, self.dataset) else: if self.gradient_based_estimator is None: self.gradient_based_estimator = ScipyOptimize() self.gradient_based_estimator.statistical_model = self.statistical_model self.gradient_based_estimator.dataset = self.dataset self.gradient_based_estimator.optimized_log_likelihood = 'class2' self.gradient_based_estimator.max_iterations = 5 self.gradient_based_estimator.max_line_search_iterations = 10 self.gradient_based_estimator.memory_length = 5 self.gradient_based_estimator.convergence_tolerance = 1e-6 self.gradient_based_estimator.print_every_n_iters = 1 self.gradient_based_estimator.save_every_n_iters = 100000 # Print information only when wanted. self.gradient_based_estimator.verbose = not self.current_iteration % self.print_every_n_iters if self.gradient_based_estimator.verbose > 0: print('') print('[ maximizing over the fixed effects with the ' + self.gradient_based_estimator.name + ' optimizer ]') self.gradient_based_estimator.individual_RER = self.individual_RER success = False while not success: try: self.gradient_based_estimator.update() success = True except RuntimeError as error: print('>> ' + str(error.args[0]) + ' [ in mcmc_saem ]') self.statistical_model.adapt_to_error(error.args[1]) if self.gradient_based_estimator.verbose > 0: print('') print('[ end of the gradient-based maximization ]')
def estimate_geodesic_regression(xml_parameters): print('') print('[ estimate_geodesic_regression function ]') print('') """ Create the dataset object. """ dataset = create_dataset(xml_parameters.dataset_filenames, xml_parameters.visit_ages, xml_parameters.subject_ids, xml_parameters.template_specifications) assert dataset.is_time_series( ), "Cannot run a geodesic regression on a non-time_series dataset." """ Create the model object. """ model = instantiate_geodesic_regression_model(xml_parameters, dataset) """ Create the estimator object. """ if xml_parameters.optimization_method_type == 'GradientAscent'.lower(): estimator = GradientAscent() estimator.initial_step_size = xml_parameters.initial_step_size estimator.scale_initial_step_size = xml_parameters.scale_initial_step_size estimator.line_search_shrink = xml_parameters.line_search_shrink estimator.line_search_expand = xml_parameters.line_search_expand elif xml_parameters.optimization_method_type == 'ScipyLBFGS'.lower(): estimator = ScipyOptimize() estimator.memory_length = xml_parameters.memory_length if not model.freeze_template and model.use_sobolev_gradient and estimator.memory_length > 1: print( '>> Using a Sobolev gradient for the template data with the ScipyLBFGS estimator memory length ' 'being larger than 1. Beware: that can be tricky.') # estimator.memory_length = 1 # msg = 'Impossible to use a Sobolev gradient for the template data with the ScipyLBFGS estimator memory ' \ # 'length being larger than 1. Overriding the "memory_length" option, now set to "1".' # warnings.warn(msg) else: estimator = GradientAscent() estimator.initial_step_size = xml_parameters.initial_step_size estimator.scale_initial_step_size = xml_parameters.scale_initial_step_size estimator.line_search_shrink = xml_parameters.line_search_shrink estimator.line_search_expand = xml_parameters.line_search_expand msg = 'Unknown optimization-method-type: \"' + xml_parameters.optimization_method_type \ + '\". Defaulting to GradientAscent.' warnings.warn(msg) estimator.max_iterations = xml_parameters.max_iterations estimator.max_line_search_iterations = xml_parameters.max_line_search_iterations estimator.convergence_tolerance = xml_parameters.convergence_tolerance estimator.print_every_n_iters = xml_parameters.print_every_n_iters estimator.save_every_n_iters = xml_parameters.save_every_n_iters estimator.dataset = dataset estimator.statistical_model = model """ Launch. """ if not os.path.exists(Settings().output_dir): os.makedirs(Settings().output_dir) model.name = 'GeodesicRegression' print('') print('[ update method of the ' + estimator.name + ' optimizer ]') start_time = time.time() estimator.update() estimator.write() end_time = time.time() print('>> Estimation took: ' + str(time.strftime("%H:%M:%S", time.gmtime(end_time - start_time)))) return model
def estimate_longitudinal_atlas(xml_parameters): print('') print('[ estimate_longitudinal_atlas function ]') print('') """ Create the dataset object. """ dataset = create_dataset(xml_parameters.dataset_filenames, xml_parameters.visit_ages, xml_parameters.subject_ids, xml_parameters.template_specifications) """ Create the model object. """ model, individual_RER = instantiate_longitudinal_atlas_model( xml_parameters, dataset) """ Create the estimator object. """ if xml_parameters.optimization_method_type == 'GradientAscent'.lower(): estimator = GradientAscent() estimator.initial_step_size = xml_parameters.initial_step_size estimator.scale_initial_step_size = xml_parameters.scale_initial_step_size estimator.max_line_search_iterations = xml_parameters.max_line_search_iterations estimator.line_search_shrink = xml_parameters.line_search_shrink estimator.line_search_expand = xml_parameters.line_search_expand elif xml_parameters.optimization_method_type == 'ScipyLBFGS'.lower(): estimator = ScipyOptimize() estimator.max_line_search_iterations = xml_parameters.max_line_search_iterations estimator.memory_length = xml_parameters.memory_length if not model.is_frozen[ 'template_data'] and model.use_sobolev_gradient and estimator.memory_length > 1: print( '>> Using a Sobolev gradient for the template data with the ScipyLBFGS estimator memory length ' 'being larger than 1. Beware: that can be tricky.') # estimator.memory_length = 1 # msg = 'Impossible to use a Sobolev gradient for the template data with the ScipyLBFGS estimator memory ' \ # 'length being larger than 1. Overriding the "memory_length" option, now set to "1".' # warnings.warn(msg) elif xml_parameters.optimization_method_type == 'McmcSaem'.lower(): sampler = SrwMhwgSampler() # Onset age proposal distribution. onset_age_proposal_distribution = MultiScalarNormalDistribution() onset_age_proposal_distribution.set_variance_sqrt( xml_parameters.onset_age_proposal_std) sampler.individual_proposal_distributions[ 'onset_age'] = onset_age_proposal_distribution # Log-acceleration proposal distribution. log_acceleration_proposal_distribution = MultiScalarNormalDistribution( ) log_acceleration_proposal_distribution.set_variance_sqrt( xml_parameters.log_acceleration_proposal_std) sampler.individual_proposal_distributions[ 'log_acceleration'] = log_acceleration_proposal_distribution # Sources proposal distribution. sources_proposal_distribution = MultiScalarNormalDistribution() sources_proposal_distribution.set_variance_sqrt( xml_parameters.sources_proposal_std) sampler.individual_proposal_distributions[ 'sources'] = sources_proposal_distribution estimator = McmcSaem() estimator.sampler = sampler estimator.sample_every_n_mcmc_iters = xml_parameters.sample_every_n_mcmc_iters estimator.print_every_n_iters = xml_parameters.print_every_n_iters # Gradient-based estimator. # estimator.gradient_based_estimator = ScipyOptimize() # estimator.gradient_based_estimator.memory_length = 5 estimator.gradient_based_estimator = GradientAscent() estimator.gradient_based_estimator.initial_step_size = xml_parameters.initial_step_size estimator.gradient_based_estimator.scale_initial_step_size = False estimator.gradient_based_estimator.line_search_shrink = xml_parameters.line_search_shrink estimator.gradient_based_estimator.line_search_expand = xml_parameters.line_search_expand estimator.gradient_based_estimator.statistical_model = model estimator.gradient_based_estimator.dataset = dataset estimator.gradient_based_estimator.optimized_log_likelihood = 'class2' estimator.gradient_based_estimator.max_iterations = 5 estimator.gradient_based_estimator.max_line_search_iterations = xml_parameters.max_line_search_iterations estimator.gradient_based_estimator.convergence_tolerance = xml_parameters.convergence_tolerance estimator.gradient_based_estimator.print_every_n_iters = 1 estimator.gradient_based_estimator.save_every_n_iters = 100000 else: estimator = GradientAscent() estimator.initial_step_size = xml_parameters.initial_step_size estimator.scale_initial_step_size = xml_parameters.scale_initial_step_size estimator.max_line_search_iterations = xml_parameters.max_line_search_iterations estimator.line_search_shrink = xml_parameters.line_search_shrink estimator.line_search_expand = xml_parameters.line_search_expand msg = 'Unknown optimization-method-type: \"' + xml_parameters.optimization_method_type \ + '\". Defaulting to GradientAscent.' warnings.warn(msg) estimator.optimized_log_likelihood = xml_parameters.optimized_log_likelihood estimator.max_iterations = xml_parameters.max_iterations estimator.convergence_tolerance = xml_parameters.convergence_tolerance estimator.print_every_n_iters = xml_parameters.print_every_n_iters estimator.save_every_n_iters = xml_parameters.save_every_n_iters estimator.dataset = dataset estimator.statistical_model = model # Initial random effects realizations estimator.individual_RER = individual_RER """ Launch. """ if not os.path.exists(Settings().output_dir): os.makedirs(Settings().output_dir) model.name = 'LongitudinalAtlas' print('') print('[ update method of the ' + estimator.name + ' optimizer ]') print('') start_time = time.time() estimator.update() estimator.write() end_time = time.time() print('>> Estimation took: ' + str(time.strftime("%H:%M:%S", time.gmtime(end_time - start_time)))) return model
class McmcSaem(AbstractEstimator): """ GradientAscent object class. An estimator is an algorithm which updates the fixed effects of a statistical model. """ #################################################################################################################### ### Constructor: #################################################################################################################### def __init__(self): AbstractEstimator.__init__(self) self.name = 'McmcSaem' self.current_mcmc_iteration = 0 self.gradient_based_estimator = None self.sample_every_n_mcmc_iters = None self.sampler = None self.sufficient_statistics = None # Dictionary of numpy arrays. self.number_of_burn_in_iterations = None # Number of iterations without memory. self.current_acceptance_rates = { } # Acceptance rates of the current iteration. self.average_acceptance_rates = { } # Mean acceptance rates, computed over all past iterations. self.memory_window_size = 1 # Size of the averaging window for the acceptance rates. self.current_acceptance_rates_in_window = None # Memory of the last memory_window_size acceptance rates. self.average_acceptance_rates_in_window = None # Moving average of current_acceptance_rates_in_window. self.model_parameters_trajectory = None # Memory of the model parameters along the estimation. self.save_model_parameters_every_n_iters = None # Resolution of the model parameters trajectory. self.individual_random_effects_samples_stack = None # Stack of the last individual random effect samples. #################################################################################################################### ### Public methods: #################################################################################################################### def update(self): """ Runs the MCMC-SAEM algorithm and updates the statistical model. """ # Initialization ----------------------------------------------------------------------------------------------- self._initialize_number_of_burn_in_iterations() self._initialize_acceptance_rate_information() sufficient_statistics = self._initialize_sufficient_statistics() self._initialize_model_parameters_trajectory() self._initialize_individual_random_effects_samples_stack() # Ensures that all the model fixed effects are initialized. self.statistical_model.update_fixed_effects(self.dataset, sufficient_statistics) # Print initial console information. print('------------------------------------- Iteration: ' + str(self.current_iteration) + ' -------------------------------------') print('>> MCMC-SAEM algorithm launched for ' + str(self.max_iterations) + ' iterations (' + str(self.number_of_burn_in_iterations) + ' iterations of burn-in).') self.statistical_model.print(self.individual_RER) # Initialization of the average random effects realizations. averaged_population_RER = { key: np.zeros(value.shape) for key, value in self.population_RER.items() } averaged_individual_RER = { key: np.zeros(value.shape) for key, value in self.individual_RER.items() } # Main loop ---------------------------------------------------------------------------------------------------- while self.current_iteration < self.max_iterations: self.current_iteration += 1 step = self._compute_step_size() # Simulation. current_model_terms = None for n in range(self.sample_every_n_mcmc_iters): self.current_mcmc_iteration += 1 # Single iteration of the MCMC. self.current_acceptance_rates, current_model_terms = self.sampler.sample( self.statistical_model, self.dataset, self.population_RER, self.individual_RER, current_model_terms) # Adapt proposal variances. self._update_acceptance_rate_information() if not (self.current_mcmc_iteration % self.memory_window_size): self.average_acceptance_rates_in_window \ = {key: np.mean(self.current_acceptance_rates_in_window[key]) for key in self.sampler.individual_proposal_distributions.keys()} self.sampler.adapt_proposal_distributions( self.average_acceptance_rates_in_window, self.current_mcmc_iteration, not self.current_iteration % self.print_every_n_iters and n == self.sample_every_n_mcmc_iters - 1) # Maximization for the class 1 fixed effects. sufficient_statistics = self.statistical_model.compute_sufficient_statistics( self.dataset, self.population_RER, self.individual_RER, model_terms=current_model_terms) self.sufficient_statistics = { key: value + step * (sufficient_statistics[key] - value) for key, value in self.sufficient_statistics.items() } self.statistical_model.update_fixed_effects( self.dataset, self.sufficient_statistics) # Maximization for the class 2 fixed effects. fixed_effects_before_maximization = self.statistical_model.get_fixed_effects( ) self._maximize_over_fixed_effects() fixed_effects_after_maximization = self.statistical_model.get_fixed_effects( ) fixed_effects = { key: value + step * (fixed_effects_after_maximization[key] - value) for key, value in fixed_effects_before_maximization.items() } self.statistical_model.set_fixed_effects(fixed_effects) # Averages the random effect realizations in the concentration phase. if step < 1.0: coefficient_1 = float(self.current_iteration + 1 - self.number_of_burn_in_iterations) coefficient_2 = (coefficient_1 - 1.0) / coefficient_1 averaged_population_RER = { key: value * coefficient_2 + self.population_RER[key] / coefficient_1 for key, value in averaged_population_RER.items() } averaged_individual_RER = { key: value * coefficient_2 + self.individual_RER[key] / coefficient_1 for key, value in averaged_individual_RER.items() } self._update_individual_random_effects_samples_stack() # Saving, printing, writing. if not (self.current_iteration % self.save_model_parameters_every_n_iters): self._update_model_parameters_trajectory() if not (self.current_iteration % self.print_every_n_iters): self.print() if not (self.current_iteration % self.save_every_n_iters): self.write() # Finalization ------------------------------------------------------------------------------------------------- self.population_RER = averaged_population_RER self.individual_RER = averaged_individual_RER def print(self): """ Prints information. """ # Iteration number. print('') print('------------------------------------- Iteration: ' + str(self.current_iteration) + ' -------------------------------------') # Averaged acceptance rates over all the past iterations. print('>> Average acceptance rates (all past iterations):') for random_effect_name, average_acceptance_rate in self.average_acceptance_rates.items( ): print('\t\t %.2f \t[ %s ]' % (average_acceptance_rate, random_effect_name)) # Let the model under optimization print information about itself. self.statistical_model.print(self.individual_RER) def write(self, population_RER=None, individual_RER=None): """ Save the current results. """ # Call the write method of the statistical model. if population_RER is None: population_RER = self.population_RER if individual_RER is None: individual_RER = self.individual_RER self.statistical_model.write(self.dataset, self.population_RER, self.individual_RER, update_fixed_effects=False) # Save the recorded model parameters trajectory. # self.model_parameters_trajectory is a list of dictionaries np.save( os.path.join( Settings().output_dir, self.statistical_model.name + '__EstimatedParameters__Trajectory.npy'), np.array(self.model_parameters_trajectory)) # Save the memorized individual random effects samples. if self.current_iteration > self.number_of_burn_in_iterations: np.save( os.path.join( Settings().output_dir, self.statistical_model.name + '__EstimatedParameters__IndividualRandomEffectsSamples.npy' ), self.individual_random_effects_samples_stack) #################################################################################################################### ### Private_maximize_over_remaining_fixed_effects() method and associated utilities: #################################################################################################################### def _maximize_over_fixed_effects(self): """ Update the model fixed effects for which no closed-form update is available (i.e. based on sufficient statistics). """ # Default optimizer, if not initialized in the launcher. # Should better be done in a dedicated initializing method. TODO. if self.statistical_model.has_maximization_procedure is not None \ and self.statistical_model.has_maximization_procedure: self.statistical_model.maximize(self.individual_RER, self.dataset) else: if self.gradient_based_estimator is None: self.gradient_based_estimator = ScipyOptimize() self.gradient_based_estimator.statistical_model = self.statistical_model self.gradient_based_estimator.dataset = self.dataset self.gradient_based_estimator.optimized_log_likelihood = 'class2' self.gradient_based_estimator.max_iterations = 5 self.gradient_based_estimator.max_line_search_iterations = 10 self.gradient_based_estimator.memory_length = 5 self.gradient_based_estimator.convergence_tolerance = 1e-6 self.gradient_based_estimator.print_every_n_iters = 1 self.gradient_based_estimator.save_every_n_iters = 100000 # Print information only when wanted. self.gradient_based_estimator.verbose = not self.current_iteration % self.print_every_n_iters if self.gradient_based_estimator.verbose > 0: print('') print('[ maximizing over the fixed effects with the ' + self.gradient_based_estimator.name + ' optimizer ]') self.gradient_based_estimator.individual_RER = self.individual_RER success = False while not success: try: self.gradient_based_estimator.update() success = True except RuntimeError as error: print('>> ' + str(error.args[0]) + ' [ in mcmc_saem ]') self.statistical_model.adapt_to_error(error.args[1]) if self.gradient_based_estimator.verbose > 0: print('') print('[ end of the gradient-based maximization ]') #################################################################################################################### ### Other private methods: #################################################################################################################### def _compute_step_size(self): aux = self.current_iteration - self.number_of_burn_in_iterations + 1 if aux <= 0: return 1.0 else: return aux**-0.9 def _initialize_number_of_burn_in_iterations(self): if self.number_of_burn_in_iterations is None: # Because some models will set it manually (e.g. deep Riemannian models) if self.max_iterations > 4000: self.number_of_burn_in_iterations = self.max_iterations - 2000 else: self.number_of_burn_in_iterations = int(self.max_iterations / 2) def _initialize_acceptance_rate_information(self): # Initialize average_acceptance_rates. self.average_acceptance_rates = { key: 0.0 for key in self.sampler.individual_proposal_distributions.keys() } # Initialize current_acceptance_rates_in_window. self.current_acceptance_rates_in_window = { key: np.zeros((self.memory_window_size, )) for key in self.sampler.individual_proposal_distributions.keys() } self.average_acceptance_rates_in_window = { key: 0.0 for key in self.sampler.individual_proposal_distributions.keys() } def _update_acceptance_rate_information(self): # Update average_acceptance_rates. coefficient_1 = float(self.current_mcmc_iteration) coefficient_2 = (coefficient_1 - 1.0) / coefficient_1 self.average_acceptance_rates = { key: value * coefficient_2 + self.current_acceptance_rates[key] / coefficient_1 for key, value in self.average_acceptance_rates.items() } # Update current_acceptance_rates_in_window. for key in self.current_acceptance_rates_in_window.keys(): self.current_acceptance_rates_in_window[key][(self.current_mcmc_iteration - 1) % self.memory_window_size] \ = self.current_acceptance_rates[key] def _initialize_sufficient_statistics(self): sufficient_statistics = self.statistical_model.compute_sufficient_statistics( self.dataset, self.population_RER, self.individual_RER) self.sufficient_statistics = { key: np.zeros(value.shape) for key, value in sufficient_statistics.items() } return sufficient_statistics #################################################################################################################### ### Model parameters trajectory saving methods: #################################################################################################################### def _initialize_model_parameters_trajectory(self): number_of_trajectory_points = min(self.max_iterations, 500) self.save_model_parameters_every_n_iters = max( 1, int(self.max_iterations / float(number_of_trajectory_points))) self.model_parameters_trajectory = {} for (key, value) in self.statistical_model.get_fixed_effects( mode='all').items(): self.model_parameters_trajectory[key] = np.zeros( (number_of_trajectory_points + 1, value.size)) self.model_parameters_trajectory[key][0, :] = value.flatten() def _update_model_parameters_trajectory(self): for (key, value) in self.statistical_model.get_fixed_effects( mode='all').items(): self.model_parameters_trajectory[key][ int(self.current_iteration / float(self.save_model_parameters_every_n_iters) ), :] = value.flatten() def _get_vectorized_individual_RER(self): return np.concatenate( [value.flatten() for value in self.individual_RER.values()]) def _initialize_individual_random_effects_samples_stack(self): number_of_concentration_iterations = self.max_iterations - self.number_of_burn_in_iterations self.individual_random_effects_samples_stack = {} for (key, value) in self.individual_RER.items(): self.individual_random_effects_samples_stack[key] = np.zeros( (number_of_concentration_iterations, value.size)) self.individual_random_effects_samples_stack[key][ 0, :] = value.flatten() def _update_individual_random_effects_samples_stack(self): for (key, value) in self.individual_RER.items(): self.individual_random_effects_samples_stack[key][ self.current_iteration - self.number_of_burn_in_iterations - 1, :] = value.flatten()
def estimate_longitudinal_metric_model(xml_parameters): print('') print('[ estimate_longitudinal_metric_model function ]') print('') dataset = None # Two alternatives: scalar dataset or image dataset for now. observation_type = 'None' template_specifications = xml_parameters.template_specifications for val in template_specifications.values(): if val['deformable_object_type'].lower() == 'scalar': dataset = read_and_create_scalar_dataset(xml_parameters) observation_type = 'scalar' #dataset.order_observations() break if dataset is None: dataset = read_and_create_image_dataset( xml_parameters.dataset_filenames, xml_parameters.visit_ages, xml_parameters.subject_ids, xml_parameters.template_specifications) observation_type = 'image' model, individual_RER = instantiate_longitudinal_metric_model( xml_parameters, dataset, observation_type=observation_type) if xml_parameters.optimization_method_type == 'GradientAscent'.lower(): estimator = GradientAscent() estimator.initial_step_size = xml_parameters.initial_step_size estimator.scale_initial_step_size = xml_parameters.scale_initial_step_size estimator.max_line_search_iterations = xml_parameters.max_line_search_iterations estimator.line_search_shrink = xml_parameters.line_search_shrink estimator.line_search_expand = xml_parameters.line_search_expand estimator.optimized_log_likelihood = xml_parameters.optimized_log_likelihood elif xml_parameters.optimization_method_type == 'ScipyLBFGS'.lower(): estimator = ScipyOptimize() estimator.max_line_search_iterations = xml_parameters.max_line_search_iterations estimator.memory_length = xml_parameters.memory_length # estimator.memory_length = 1 # msg = 'Impossible to use a Sobolev gradient for the template data with the ScipyLBFGS estimator memory ' \ # 'length being larger than 1. Overriding the "memory_length" option, now set to "1".' # warnings.warn(msg) elif xml_parameters.optimization_method_type == 'McmcSaem'.lower(): sampler = SrwMhwgSampler() estimator = McmcSaem() estimator.sampler = sampler # Onset age proposal distribution. onset_age_proposal_distribution = MultiScalarNormalDistribution() onset_age_proposal_distribution.set_variance_sqrt( xml_parameters.onset_age_proposal_std) sampler.individual_proposal_distributions[ 'onset_age'] = onset_age_proposal_distribution # Log-acceleration proposal distribution. log_acceleration_proposal_distribution = MultiScalarNormalDistribution( ) log_acceleration_proposal_distribution.set_variance_sqrt( xml_parameters.log_acceleration_proposal_std) sampler.individual_proposal_distributions[ 'log_acceleration'] = log_acceleration_proposal_distribution # Sources proposal distribution if model.number_of_sources > 0: sources_proposal_distribution = MultiScalarNormalDistribution() sources_proposal_distribution.set_variance_sqrt( xml_parameters.sources_proposal_std) sampler.individual_proposal_distributions[ 'sources'] = sources_proposal_distribution estimator.sample_every_n_mcmc_iters = xml_parameters.sample_every_n_mcmc_iters # Gradient-based estimator. estimator.gradient_based_estimator = GradientAscent() estimator.gradient_based_estimator.statistical_model = model estimator.gradient_based_estimator.dataset = dataset estimator.gradient_based_estimator.optimized_log_likelihood = 'class2' estimator.gradient_based_estimator.max_iterations = 5 estimator.gradient_based_estimator.max_line_search_iterations = 5 estimator.gradient_based_estimator.convergence_tolerance = 1e-2 estimator.gradient_based_estimator.print_every_n_iters = 1 estimator.gradient_based_estimator.save_every_n_iters = 100000 estimator.gradient_based_estimator.initial_step_size = xml_parameters.initial_step_size estimator.gradient_based_estimator.line_search_shrink = 0.5 estimator.gradient_based_estimator.line_search_expand = 1.2 estimator.gradient_based_estimator.scale_initial_step_size = True estimator.number_of_burn_in_iterations = xml_parameters.max_iterations else: estimator = GradientAscent() estimator.initial_step_size = xml_parameters.initial_step_size estimator.max_line_search_iterations = xml_parameters.max_line_search_iterations estimator.line_search_shrink = xml_parameters.line_search_shrink estimator.line_search_expand = xml_parameters.line_search_expand msg = 'Unknown optimization-method-type: \"' + xml_parameters.optimization_method_type \ + '\". Defaulting to GradientAscent.' warnings.warn(msg) estimator.max_iterations = xml_parameters.max_iterations estimator.convergence_tolerance = xml_parameters.convergence_tolerance estimator.print_every_n_iters = xml_parameters.print_every_n_iters estimator.save_every_n_iters = xml_parameters.save_every_n_iters estimator.dataset = dataset estimator.statistical_model = model # Initial random effects realizations estimator.individual_RER = individual_RER """ Launch. """ if not os.path.exists(Settings().output_dir): os.makedirs(Settings().output_dir) model.name = 'LongitudinalMetricModel' print('') print('[ update method of the ' + estimator.name + ' optimizer ]') start_time = time.time() estimator.update() estimator.write() end_time = time.time() print('>> Estimation took: ' + str( time.strftime("%d days, %H hours, %M minutes and %S seconds.", time.gmtime(end_time - start_time))))
def estimate_longitudinal_registration_for_subject(args, overwrite=True): i, general_settings, xml_parameters, registration_output_path, \ full_subject_ids, full_dataset_filenames, full_visit_ages = args Settings().initialize(general_settings) """ Create the dataset object. """ xml_parameters.dataset_filenames = [full_dataset_filenames[i]] xml_parameters.visit_ages = [full_visit_ages[i]] xml_parameters.subject_ids = [full_subject_ids[i]] dataset = create_dataset([full_dataset_filenames[i]], [full_visit_ages[i]], [full_subject_ids[i]], xml_parameters.template_specifications) """ Create a dedicated output folder for the current subject, adapt the global settings. """ subject_registration_output_path = os.path.join( registration_output_path, 'LongitudinalRegistration__subject_' + full_subject_ids[i]) if not overwrite and os.path.isdir(subject_registration_output_path): return None print('') print('[ longitudinal registration of subject ' + full_subject_ids[i] + ' ]') print('') if os.path.isdir(subject_registration_output_path): shutil.rmtree(subject_registration_output_path) os.mkdir(subject_registration_output_path) Settings().output_dir = subject_registration_output_path Settings().state_file = os.path.join(Settings().output_dir, 'pydef_state.p') """ Create the model object. """ model, individual_RER = instantiate_longitudinal_atlas_model(xml_parameters, dataset) # In case of given initial random effect realizations, select only the relevant ones. for (xml_parameter, random_effect_name) \ in zip([xml_parameters.initial_onset_ages, xml_parameters.initial_log_accelerations, xml_parameters.initial_sources], ['onset_age', 'log_acceleration', 'sources']): if xml_parameter is not None and individual_RER[random_effect_name].shape[0] > 1: individual_RER[random_effect_name] = np.array([individual_RER[random_effect_name][i]]) """ Create the estimator object. """ if xml_parameters.optimization_method_type == 'GradientAscent'.lower(): estimator = GradientAscent() estimator.initial_step_size = xml_parameters.initial_step_size estimator.max_line_search_iterations = xml_parameters.max_line_search_iterations estimator.line_search_shrink = xml_parameters.line_search_shrink estimator.line_search_expand = xml_parameters.line_search_expand elif xml_parameters.optimization_method_type == 'ScipyLBFGS'.lower(): estimator = ScipyOptimize() estimator.max_line_search_iterations = xml_parameters.max_line_search_iterations estimator.memory_length = xml_parameters.memory_length if not model.is_frozen['template_data'] and model.use_sobolev_gradient and estimator.memory_length > 1: print('>> Using a Sobolev gradient for the template data with the ScipyLBFGS estimator memory length ' 'being larger than 1. Beware: that can be tricky.') elif xml_parameters.optimization_method_type == 'ScipyPowell'.lower(): estimator = ScipyOptimize() estimator.method = 'Powell' elif xml_parameters.optimization_method_type == 'McmcSaem'.lower(): sampler = SrwMhwgSampler() momenta_proposal_distribution = MultiScalarNormalDistribution() # initial_control_points = model.get_control_points() # momenta_proposal_distribution.set_mean(np.zeros(initial_control_points.size,)) momenta_proposal_distribution.set_variance_sqrt(xml_parameters.momenta_proposal_std) sampler.individual_proposal_distributions['momenta'] = momenta_proposal_distribution estimator = McmcSaem() estimator.sampler = sampler estimator.sample_every_n_mcmc_iters = xml_parameters.sample_every_n_mcmc_iters else: estimator = GradientAscent() estimator.initial_step_size = xml_parameters.initial_step_size estimator.max_line_search_iterations = xml_parameters.max_line_search_iterations estimator.line_search_shrink = xml_parameters.line_search_shrink estimator.line_search_expand = xml_parameters.line_search_expand msg = 'Unknown optimization-method-type: \"' + xml_parameters.optimization_method_type \ + '\". Defaulting to GradientAscent.' warnings.warn(msg) estimator.max_iterations = xml_parameters.max_iterations estimator.convergence_tolerance = xml_parameters.convergence_tolerance estimator.print_every_n_iters = xml_parameters.print_every_n_iters estimator.save_every_n_iters = xml_parameters.save_every_n_iters estimator.dataset = dataset estimator.statistical_model = model # Initial random effects realizations estimator.individual_RER = individual_RER """ Launch. """ if not os.path.exists(Settings().output_dir): os.makedirs(Settings().output_dir) model.name = 'LongitudinalRegistration' print('') print('[ update method of the ' + estimator.name + ' optimizer ]') try: start_time = time.time() estimator.update() model._write_model_parameters(estimator.individual_RER) end_time = time.time() except RuntimeError as error: print('>> Failure of the longitudinal registration procedure for subject %s: %s' % (full_subject_ids[i], error)) if not (estimator.name.lower() == 'scipyoptimize' and estimator.method.lower() == 'scipypowell'): print('>> Second try with the ScipyPowell optimiser.') estimator = ScipyOptimize() estimator.method = 'Powell' estimator.max_iterations = xml_parameters.max_iterations estimator.convergence_tolerance = xml_parameters.convergence_tolerance estimator.print_every_n_iters = xml_parameters.print_every_n_iters estimator.save_every_n_iters = xml_parameters.save_every_n_iters estimator.dataset = dataset estimator.statistical_model = model estimator.individual_RER = individual_RER start_time = time.time() estimator.update() model._write_model_parameters(estimator.individual_RER) end_time = time.time() print('') print('>> Estimation took: ' + str(time.strftime("%H:%M:%S", time.gmtime(end_time - start_time)))) return model
def estimate_longitudinal_registration_for_subject(args): i, general_settings, xml_parameters, registration_output_path, \ full_dataset = args Settings().initialize(general_settings) print('') print('[ longitudinal registration of subject ' + full_dataset.subject_ids[i] + ' ]') print('') """ Create the dataset object. """ dataset = create_image_dataset([ full_dataset.subject_ids[i] for _ in range(len(full_dataset.times[i])) ], full_dataset.deformable_objects[i], full_dataset.times[i]) """ Create a dedicated output folder for the current subject, adapt the global settings. """ subject_registration_output_path = os.path.join( registration_output_path, 'LongitudinalMetricRegistration__subject_' + full_dataset.subject_ids[i]) if os.path.isdir(subject_registration_output_path): shutil.rmtree(subject_registration_output_path) os.mkdir(subject_registration_output_path) Settings().output_dir = subject_registration_output_path Settings().state_file = os.path.join(subject_registration_output_path, 'pydef_state.p') """ Create the model object. """ Settings().number_of_threads = 1 model, individual_RER = instantiate_longitudinal_metric_model( xml_parameters, dataset, observation_type='image') model.is_frozen['v0'] = True model.is_frozen['p0'] = True model.is_frozen['reference_time'] = True model.is_frozen['onset_age_variance'] = True model.is_frozen['log_acceleration_variance'] = True model.is_frozen['noise_variance'] = True model.is_frozen['metric_parameters'] = True model.is_frozen['noise_variance'] = True # In case of given initial random effect realizations, select only the relevant ones. for (xml_parameter, random_effect_name) \ in zip([xml_parameters.initial_onset_ages, xml_parameters.initial_log_accelerations], ['onset_age', 'log_acceleration']): if xml_parameter is not None and len( individual_RER[random_effect_name].shape) > 1: individual_RER[random_effect_name] = np.array( [individual_RER[random_effect_name][i, :]]) """ Create the estimator object. """ if xml_parameters.optimization_method_type == 'ScipyPowell'.lower(): estimator = ScipyOptimize() estimator.method = 'Powell' elif xml_parameters.optimization_method_type == 'ScipyLBFGS'.lower(): estimator = ScipyOptimize() estimator.max_line_search_iterations = xml_parameters.max_line_search_iterations estimator.memory_length = xml_parameters.memory_length estimator.max_iterations = xml_parameters.max_iterations estimator.convergence_tolerance = xml_parameters.convergence_tolerance estimator.print_every_n_iters = xml_parameters.print_every_n_iters estimator.save_every_n_iters = xml_parameters.save_every_n_iters estimator.dataset = dataset estimator.statistical_model = model # Initial random effects realizations estimator.individual_RER = individual_RER """ Launch. """ if not os.path.exists(Settings().output_dir): os.makedirs(Settings().output_dir) model.name = 'LongitudinalMetricRegistration' print('') print('[ update method of the ' + estimator.name + ' optimizer ]') start_time = time.time() estimator.update() model._write_model_parameters() model._write_model_predictions(dataset, estimator.individual_RER, sample=False) model._write_individual_RER(dataset, estimator.individual_RER) end_time = time.time() print('') print('>> Estimation took: ' + str(time.strftime("%H:%M:%S", time.gmtime(end_time - start_time)))) return model