def get_optimization_inits(model_name, input_data, output_folder, cl_device_ind=None): """Get better optimization starting points for the given model. Since initialization can make quite a difference in optimization results, this function can generate a good initialization starting point for the given model. The idea is that before you call the :func:`fit_model` function, you call this function to get a better starting point. An usage example would be:: input_data = mdt.load_input_data(..) init_data = get_optimization_inits('BallStick_r1', input_data, '/my/folder') fit_model('BallStick_r1', input_data, '/my/folder', initialization_data={'inits': init_data}) Where the init data returned by this function can directly be used as input to the ``initialization_data`` argument of the :func`fit_model` function. Please note that his function only supports models shipped by default with MDT. Args: model_name (str): The name of a model for which we want the optimization starting points. input_data (:class:`~mdt.utils.MRIInputData`): the input data object containing all the info needed for model fitting of intermediate models. output_folder (string): The path to the folder where to place the output, we will make a subdir with the model name in it. cl_device_ind (int or list): the index of the CL device to use. The index is from the list from the function utils.get_cl_devices(). This can also be a list of device indices. Returns: dict: a dictionary with initialization points for the selected model """ from mdt.lib.model_fitting import get_optimization_inits return get_optimization_inits(model_name, input_data, output_folder, cl_device_ind=cl_device_ind)
def fit_model(model, input_data, output_folder, method=None, recalculate=False, only_recalculate_last=False, cl_device_ind=None, double_precision=False, tmp_results_dir=True, initialization_data=None, use_cascaded_inits=True, post_processing=None, optimizer_options=None): """Run the optimizer on the given model. Since version 0.17.2 fitting cascade models has been deprecated in favor of a slightly more manual setup by using the :func:`get_optimization_inits` function. Args: model (str or :class:`~mdt.models.composite.DMRICompositeModel` or :class:`~mdt.models.cascade.DMRICascadeModelInterface`): An implementation of an AbstractModel that contains the model we want to optimize or the name of an model. input_data (:class:`~mdt.utils.MRIInputData`): the input data object containing all the info needed for the model fitting. output_folder (string): The path to the folder where to place the output, we will make a subdir with the model name in it. method (str): The optimization method to use, one of: - 'Levenberg-Marquardt' - 'Nelder-Mead' - 'Powell' - 'Subplex' If not given, defaults to 'Powell'. recalculate (boolean): If we want to recalculate the results if they are already present. only_recalculate_last (boolean): This is only of importance when dealing with CascadeModels. If set to true we only recalculate the last element in the chain (if recalculate is set to True, that is). If set to false, we recalculate everything. This only holds for the first level of the cascade. cl_device_ind (int or list): the index of the CL device to use. The index is from the list from the function utils.get_cl_devices(). This can also be a list of device indices. double_precision (boolean): if we would like to do the calculations in double precision tmp_results_dir (str, True or None): The temporary dir for the calculations. Set to a string to use that path directly, set to True to use the config value, set to None to disable. initialization_data (dict): provides (extra) initialization data to use during model fitting. If we are optimizing a cascade model this data only applies to the last model in the cascade. This dictionary can contain the following elements: * ``inits``: dictionary with per parameter an initialization point * ``fixes``: dictionary with per parameter a fixed point, this will remove that parameter from the fitting * ``lower_bounds``: dictionary with per parameter a lower bound * ``upper_bounds``: dictionary with per parameter a upper bound * ``unfix``: a list of parameters to unfix For example:: initialization_data = { 'fixes': {'Stick0.theta: np.array(...), ...}, 'inits': {...} } use_cascaded_inits (boolean): if set, we initialize the model parameters using :func:`get_optimization_inits`. You can still overwrite these initializations using the ``initialization_data`` attribute. Please note that this only works for non-cascade models. post_processing (dict): a dictionary with flags for post-processing options to enable or disable. For valid elements, please see the configuration file settings for ``optimization`` under ``post_processing``. Valid input for this parameter is for example: {'covariance': False} to disable automatic calculation of the covariance from the Hessian. optimizer_options (dict): extra options passed to the optimization routines. Returns: dict: The result maps for the given composite model or the last model in the cascade. This returns the results as 3d/4d volumes for every output map. """ import mdt.utils from mdt.lib.model_fitting import ModelFit if not mdt.utils.check_user_components(): init_user_settings(pass_if_exists=True) if cl_device_ind is not None and not isinstance(cl_device_ind, collections.Iterable): cl_device_ind = [cl_device_ind] if isinstance(model, str): model_name = model model_instance = get_model(model)() else: model_name = model.name model_instance = model if isinstance(model_instance, DMRICascadeModelInterface): warnings.warn( dedent(''' Fitting cascade models has been deprecated in favor of specifying 'initialization_data' directly. To replicate old fit results, use the function mdt.get_optimization_inits() Old (deprecated) example: fit_model('NODDI (Cascade)', ...) New example: fit_model('NODDI', ..., use_cascaded_inits=True) Since ``use_cascaded_inits`` is True by default, you can also just use: fit_model('NODDI', ...) '''), FutureWarning) else: if use_cascaded_inits: if initialization_data is None: initialization_data = {} initialization_data['inits'] = initialization_data.get('inits', {}) inits = get_optimization_inits(model_name, input_data, output_folder, cl_device_ind=cl_device_ind) inits.update(initialization_data['inits']) initialization_data['inits'] = inits model_fit = ModelFit(model, input_data, output_folder, method=method, optimizer_options=optimizer_options, recalculate=recalculate, only_recalculate_last=only_recalculate_last, cl_device_ind=cl_device_ind, double_precision=double_precision, tmp_results_dir=tmp_results_dir, initialization_data=initialization_data, post_processing=post_processing) return model_fit.run()
def fit_model(model, input_data, output_folder, method=None, recalculate=False, cl_device_ind=None, double_precision=False, tmp_results_dir=True, initialization_data=None, use_cascaded_inits=True, post_processing=None, optimizer_options=None): """Run the optimizer on the given model. Args: model (str or :class:`~mdt.models.base.EstimableModel`): The name of a composite model or an implementation of a composite model. input_data (:class:`~mdt.utils.MRIInputData`): the input data object containing all the info needed for the model fitting. output_folder (string): The path to the folder where to place the output, we will make a subdir with the model name in it. method (str): The optimization method to use, one of: - 'Levenberg-Marquardt' - 'Nelder-Mead' - 'Powell' - 'Subplex' If not given, defaults to 'Powell'. recalculate (boolean): If we want to recalculate the results if they are already present. cl_device_ind (int or list): the index of the CL device to use. The index is from the list from the function utils.get_cl_devices(). This can also be a list of device indices. double_precision (boolean): if we would like to do the calculations in double precision tmp_results_dir (str, True or None): The temporary dir for the calculations. Set to a string to use that path directly, set to True to use the config value, set to None to disable. initialization_data (dict): provides (extra) initialization data to use during model fitting. This dictionary can contain the following elements: * ``inits``: dictionary with per parameter an initialization point * ``fixes``: dictionary with per parameter a fixed point, this will remove that parameter from the fitting * ``lower_bounds``: dictionary with per parameter a lower bound * ``upper_bounds``: dictionary with per parameter a upper bound * ``unfix``: a list of parameters to unfix For example:: initialization_data = { 'fixes': {'Stick0.theta: np.array(...), ...}, 'inits': {...} } use_cascaded_inits (boolean): if set, we initialize the model parameters using :func:`get_optimization_inits`. You can also overrule the default initializations using the ``initialization_data`` attribute. post_processing (dict): a dictionary with flags for post-processing options to enable or disable. For valid elements, please see the configuration file settings for ``optimization`` under ``post_processing``. Valid input for this parameter is for example: {'covariance': False} to disable automatic calculation of the covariance from the Hessian. optimizer_options (dict): extra options passed to the optimization routines. Returns: dict: The result maps for the given composite model or the last model in the cascade. This returns the results as 3d/4d volumes for every output map. """ logger = logging.getLogger(__name__) if not check_user_components(): init_user_settings(pass_if_exists=True) if cl_device_ind is not None: if not isinstance(cl_device_ind, collections.Iterable): cl_device_ind = [cl_device_ind] cl_runtime_info = CLRuntimeInfo( cl_environments=get_cl_devices(cl_device_ind), double_precision=double_precision) else: cl_runtime_info = CLRuntimeInfo(double_precision=double_precision) if isinstance(model, str): model_name = model model_instance = get_model(model)() else: model_name = model.name model_instance = model if not model_instance.is_input_data_sufficient(input_data): raise InsufficientProtocolError( 'The provided protocol is insufficient for this model. ' 'The reported errors where: {}'.format( model_instance.get_input_data_problems(input_data))) if post_processing: model_instance.update_active_post_processing('optimization', post_processing) if use_cascaded_inits: if initialization_data is None: initialization_data = {} initialization_data['inits'] = initialization_data.get('inits', {}) inits = get_optimization_inits(model_name, input_data, output_folder, cl_device_ind=cl_device_ind) inits.update(initialization_data['inits']) initialization_data['inits'] = inits initialization_data = SimpleInitializationData(**initialization_data) initialization_data.apply_to_model(model_instance, input_data) logger.info('Preparing {0} with the cascaded initializations.'.format( model_name)) if method is None: method, optimizer_options = get_optimizer_for_model(model_name) with mot.configuration.config_context(CLRuntimeAction(cl_runtime_info)): fit_composite_model(model_instance, input_data, output_folder, method, get_temporary_results_dir(tmp_results_dir), recalculate=recalculate, optimizer_options=optimizer_options) return get_all_nifti_data(os.path.join(output_folder, model_name))