Пример #1
0
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)
Пример #2
0
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()
Пример #3
0
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))