:py:mod:`cubnm.optimize` ####################### .. py:module:: cubnm.optimize .. autoapi-nested-parse:: Optimizers of the model free parameters .. autoapisummary:: cubnm.optimize.GridSearch cubnm.optimize.BNMProblem cubnm.optimize.Optimizer cubnm.optimize.PymooOptimizer cubnm.optimize.CMAESOptimizer cubnm.optimize.NSGA2Optimizer cubnm.optimize.BayesOptimizer .. autoapisummary:: cubnm.optimize.batch_optimize .. py:class:: GridSearch(model, params, **kwargs) Grid search of model free parameters Parameters --------- model: :obj:`str`, {'rWW', 'rWWEx', 'Kuramoto'} model name params: :obj:`dict` of :obj:`tuple` or :obj:`float` a dictionary including parameter names as keys and their fixed values (:obj:`float`) or discrete range of values (:obj:`tuple` of (min, max, n)) as values. **kwargs Keyword arguments passed to :class:`cubnm.sim.SimGroup` Example ------- Run a grid search of rWW model with 10 G and 10 wEE values with fixed wEI: :: from cubnm import datasets, optimize gs = optimize.GridSearch( model = 'rWW', params = { 'G': (0.5, 2.5, 10), 'wEE': (0.05, 0.75, 10), 'wEI': 0.21 }, duration = 60, TR = 1, sc_path = datasets.load_sc('strength', 'schaefer-100', return_path=True), states_ts = True ) emp_fc_tril = datasets.load_functional('FC', 'schaefer-100') emp_fcd_tril = datasets.load_functional('FCD', 'schaefer-100') scores = gs.evaluate(emp_fc_tril, emp_fcd_tril) .. py:method:: evaluate(emp_fc_tril=None, emp_fcd_tril=None, bold=None) Runs the grid simulations and evaluates their goodness of fit to the empirical FC and FCD Parameters ---------- emp_fc_tril: :obj:`np.ndarray` or :obj:`None` lower triangular part of empirical FC. Shape: (edges,) emp_fcd_tril: :obj:`np.ndarray` or :obj:`None` lower triangular part of empirical FCD. Shape: (window_pairs,) emp_bold: :obj:`np.ndarray` or None cleaned and parcellated empirical BOLD time series. Shape: (nodes, volumes) Motion outliers should either be excluded (not recommended as it disrupts the temporal structure) or replaced with zeros. If provided emp_fc_tril and emp_fcd_tril will be ignored. Returns ------- :obj:`pd.DataFrame` The goodness of fit measures (columns) of each simulation (rows) .. py:class:: BNMProblem(model, params, emp_fc_tril=None, emp_fcd_tril=None, emp_bold=None, het_params=[], maps=None, maps_coef_range='auto', node_grouping=None, multiobj=False, **kwargs) Bases: :py:obj:`pymoo.core.problem.Problem` Brain network model problem. A :class:`pymoo.core.problem.Problem` that defines the model, free parameters and their ranges, and target empirical data (FC and FCD), and the simulation configurations (through :class:`cubnm.sim.SimGroup`). :class:`cubnm.optimize.Optimizer` classes can be used to optimize the free parameters of this problem. Parameters ---------- model: :obj:`str`, {'rWW', 'rWWEx', 'Kuramoto'} model name params: :obj:`dict` of :obj:`tuple` or :obj:`float` a dictionary including parameter names as keys and their fixed values (:obj:`float`) or continuous range of values (:obj:`tuple` of (min, max)) as values. emp_fc_tril: :obj:`np.ndarray` or :obj:`None` lower triangular part of empirical FC. Shape: (edges,) emp_fcd_tril: :obj:`np.ndarray` or :obj:`None` lower triangular part of empirical FCD. Shape: (window_pairs,) emp_bold: :obj:`np.ndarray` or None cleaned and parcellated empirical BOLD time series. Shape: (nodes, volumes) Motion outliers should either be excluded (not recommended as it disrupts the temporal structure) or replaced with zeros. If provided emp_fc_tril and emp_fcd_tril will be ignored. het_params: :obj:`list` of :obj:`str`, optional which regional parameters are heterogeneous across nodes maps: :obj:`str`, optional path to heterogeneity maps as a text file or a numpy array. Shape: (n_maps, nodes). If provided one free parameter per regional parameter per each map will be added. maps_coef_range: 'auto' or :obj:`tuple` or :obj:`list` of :obj:`tuple` - 'auto': uses (-1/max, -1/min) for maps with positive and negative values (assuming they are z-scored) and (0, 1) otherwise - :obj:`tuple`: uses the same range for all maps - :obj:`list` of :obj:`tuple`: n-map element list specifying the range of coefficients for each map node_grouping: {None, 'node', 'sym', :obj:`str`, :obj:`np.ndarray`}, optional - None: does not use region-/group-specific parameters - 'node': each node has its own regional free parameters - 'sym': uses the same regional free parameters for each pair of symmetric nodes (e.g. L and R hemispheres). Assumes symmetry of parcels between L and R hemispheres. - :obj:`str`: path to a text file including node grouping array. Shape: (nodes,) - :obj:`np.ndarray`: a numpy array. Shape: (nodes,) multiobj: :obj:`bool`, optional instead of combining the objectives into a single objective function (via summation) defines each objective separately. This must not be used with single-objective optimizers **kwargs Keyword arguments passed to :class:`cubnm.sim.SimGroup` .. py:method:: get_config(include_sim_group=True, include_N=False) Get the problem configuration Parameters ---------- include_sim_group: :obj:`bool`, optional whether to include the configuration of the associated :class:`cubnm.sim.SimGroup` include_N: :obj:`bool`, optional whether to include the current population size in the configuration Returns ------- :obj:`dict` the configuration of the problem .. py:method:: eval(X, skip_run=False) Runs the simulations based on normalized candidate free parameters `X` and evaluates their goodness of fit to the empirical FC and FCD of the problem. Parameters ---------- X: :obj:`np.ndarray` the normalized parameters of current population in range [0, 1]. Shape: (N, ndim) skip_run: :obj:`bool`, optional will only be true in batch optimization where the simulations are already run and only the GOF calculation is needed Returns ------- :obj:`pd.DataFrame` The goodness of fit measures (columns) of each simulation (rows) .. py:class:: Optimizer(**kwargs) Bases: :py:obj:`abc.ABC` Base class for evolutionary optimizers .. py:method:: setup_problem(problem, **kwargs) :abstractmethod: .. py:method:: optimize() :abstractmethod: .. py:method:: save(save_opt=True, save_obj=False) Saves the output of the optimizer, including history of particles, history of optima, the optimal point, and its simulation data. The output will be saved to `out_dir` of the problem's :class:`cubnm.sim.SimGroup`. If a directory with the same type of optimizer already exists, a new directory with a new index will be created. Parameters --------- save_opt: :obj:`bool`, optional reruns and saves the optimal simulation(s) data save_obj: :obj:`bool`, optional saves the optimizer object which also includes the simulation data of all simulations and therefore can be large file. Warning: this file is very large. .. py:method:: get_config() Get the optimizer configuration Returns ------- :obj:`dict` the configuration of the optimizer .. py:class:: PymooOptimizer(termination=None, n_iter=2, seed=0, print_history=True, save_history_sim=False, **kwargs) Bases: :py:obj:`Optimizer` Generic wrapper for `pymoo` optimizers. Parameters: ---------- termination: :obj:`pymoo.termination.Termination`, optional The termination object that defines the stopping criteria for the optimization process. If not provided, the termination criteria will be based on the number of iterations (`n_iter`). n_iter: :obj:`int`, optional The maximum number of iterations for the optimization process. This parameter is only used if `termination` is not provided. seed: :obj:`int`, optional The seed value for the random number generator used by the optimizer. print_history: :obj:`bool`, optional Flag indicating whether to print the optimization history during the optimization process. save_history_sim: :obj:`bool`, optional Flag indicating whether to save the simulation data of each iteration. Default is False to avoid consuming too much memory across iterations. **kwargs Additional keyword arguments that can be passed to the `pymoo` optimizer. .. py:method:: setup_problem(problem, pymoo_verbose=False, **kwargs) Registers a :class:`cubnm.optimizer.BNMProblem` with the optimizer, so that the optimizer can optimize its free parameters. Parameters ---------- problem: :obj:`cubnm.optimizer.BNMProblem` The problem to be set up with the algorithm. pymoo_verbose: :obj:`bool`, optional Flag indicating whether to enable verbose output from pymoo. Default is False. **kwargs Additional keyword arguments to be passed to the algorithm setup method. .. py:method:: optimize() Optimizes the associated :class:`cubnm.optimizer.BNMProblem` free parameters through an evolutionary optimization approach by running multiple generations of parallel simulations until the termination criteria is met or maximum number of iterations is reached. .. py:method:: save(save_opt=True, save_obj=False) Saves the output of the optimizer, including history of particles, history of optima, the optimal point, and its simulation data. The output will be saved to `out_dir` of the problem's :class:`cubnm.sim.SimGroup`. If a directory with the same type of optimizer already exists, a new directory with a new index will be created. Parameters --------- save_opt: :obj:`bool`, optional reruns and saves the optimal simulation(s) data save_obj: :obj:`bool`, optional saves the optimizer object which also includes the simulation data of all simulations and therefore can be large file. Warning: this file is very large. .. py:method:: get_config() Get the optimizer configuration Returns ------- :obj:`dict` the configuration of the optimizer .. py:class:: CMAESOptimizer(popsize, x0=None, sigma=0.5, use_bound_penalty=False, algorithm_kws={}, **kwargs) Bases: :py:obj:`PymooOptimizer` Covariance Matrix Adaptation Evolution Strategy (CMA-ES) optimizer Parameters ---------- popsize: :obj:`int` The population size for the optimizer x0: array-like, optional The initial guess for the optimization. If None (default), the initial guess will be estimated based on 20 random samples as the first generation sigma: :obj:`float`, optional The initial step size for the optimization use_bound_penalty: :obj:`bool`, optional Whether to use a bound penalty for the optimization algorithm_kws: :obj:`dict`, optional Additional keyword arguments for the CMAES algorithm **kwargs Additional keyword arguments Example ------- Run a CMAES optimization for 10 iterations with a population size of 20: :: from cubnm import datasets, optimize problem = optimize.BNMProblem( model = 'rWW', params = { 'G': (0.5, 2.5), 'wEE': (0.05, 0.75), 'wEI': 0.15, }, emp_fc_tril = datasets.load_functional('FC', 'schaefer-100'), emp_fcd_tril = datasets.load_functional('FCD', 'schaefer-100'), duration = 60, TR = 1, sc_path = datasets.load_sc('strength', 'schaefer-100', return_path=True), states_ts = True ) cmaes = optimize.CMAESOptimizer(popsize=20, n_iter=10, seed=1) cmaes.setup_problem(problem) cmaes.optimize() cmaes.save() .. py:attribute:: max_obj :value: 1 .. py:method:: setup_problem(problem, **kwargs) Extends :meth:`cubnm.optimizer.PymooOptimizer.setup_problem` to set up the optimizer with the problem and set the bound penalty option based on the optimizer's `use_bound_penalty` attribute. Parameters ---------- problem: :obj:`cubnm.optimizer.BNMProblem` The problem to be set up with the algorithm. **kwargs Additional keyword arguments to be passed to :meth:`cubnm.optimizer.PymooOptimizer.setup_problem` .. py:method:: optimize() Optimizes the associated :class:`cubnm.optimizer.BNMProblem` free parameters through an evolutionary optimization approach by running multiple generations of parallel simulations until the termination criteria is met or maximum number of iterations is reached. .. py:method:: save(save_opt=True, save_obj=False) Saves the output of the optimizer, including history of particles, history of optima, the optimal point, and its simulation data. The output will be saved to `out_dir` of the problem's :class:`cubnm.sim.SimGroup`. If a directory with the same type of optimizer already exists, a new directory with a new index will be created. Parameters --------- save_opt: :obj:`bool`, optional reruns and saves the optimal simulation(s) data save_obj: :obj:`bool`, optional saves the optimizer object which also includes the simulation data of all simulations and therefore can be large file. Warning: this file is very large. .. py:method:: get_config() Get the optimizer configuration Returns ------- :obj:`dict` the configuration of the optimizer .. py:class:: NSGA2Optimizer(popsize, algorithm_kws={}, **kwargs) Bases: :py:obj:`PymooOptimizer` Non-dominated Sorting Genetic Algorithm II (NSGA-II) optimizer Parameters ---------- popsize: int The population size for the optimizer algorithm_kws: dict, optional Additional keyword arguments for the NSGA2 algorithm kwargs: dict Additional keyword arguments for the base class .. py:attribute:: max_obj :value: 3 .. py:method:: setup_problem(problem, pymoo_verbose=False, **kwargs) Registers a :class:`cubnm.optimizer.BNMProblem` with the optimizer, so that the optimizer can optimize its free parameters. Parameters ---------- problem: :obj:`cubnm.optimizer.BNMProblem` The problem to be set up with the algorithm. pymoo_verbose: :obj:`bool`, optional Flag indicating whether to enable verbose output from pymoo. Default is False. **kwargs Additional keyword arguments to be passed to the algorithm setup method. .. py:method:: optimize() Optimizes the associated :class:`cubnm.optimizer.BNMProblem` free parameters through an evolutionary optimization approach by running multiple generations of parallel simulations until the termination criteria is met or maximum number of iterations is reached. .. py:method:: save(save_opt=True, save_obj=False) Saves the output of the optimizer, including history of particles, history of optima, the optimal point, and its simulation data. The output will be saved to `out_dir` of the problem's :class:`cubnm.sim.SimGroup`. If a directory with the same type of optimizer already exists, a new directory with a new index will be created. Parameters --------- save_opt: :obj:`bool`, optional reruns and saves the optimal simulation(s) data save_obj: :obj:`bool`, optional saves the optimizer object which also includes the simulation data of all simulations and therefore can be large file. Warning: this file is very large. .. py:method:: get_config() Get the optimizer configuration Returns ------- :obj:`dict` the configuration of the optimizer .. py:class:: BayesOptimizer(popsize, n_iter, seed=0) Bases: :py:obj:`Optimizer` Bayesian optimizer Parameters ---------- popsize: :obj:`int` The population size for the optimizer n_iter: :obj:`int` The number of iterations for the optimization process seed: :obj:`int`, optional The seed value for the random number generator used by the optimizer. .. py:attribute:: max_obj :value: 1 .. py:method:: setup_problem(problem, **kwargs) Sets up the optimizer with the problem Parameters ---------- problem: :obj:`cubnm.optimizer.BNMProblem` The problem to be set up with the algorithm. **kwargs Additional keyword arguments to be passed to :class:`skopt.Optimizer` .. py:method:: optimize() Optimizes the associated :class:`cubnm.optimizer.BNMProblem` free parameters through an evolutionary optimization approach by running multiple generations of parallel simulations until the termination criteria is met or maximum number of iterations is reached. .. py:method:: save(save_opt=True, save_obj=False) Saves the output of the optimizer, including history of particles, history of optima, the optimal point, and its simulation data. The output will be saved to `out_dir` of the problem's :class:`cubnm.sim.SimGroup`. If a directory with the same type of optimizer already exists, a new directory with a new index will be created. Parameters --------- save_opt: :obj:`bool`, optional reruns and saves the optimal simulation(s) data save_obj: :obj:`bool`, optional saves the optimizer object which also includes the simulation data of all simulations and therefore can be large file. Warning: this file is very large. .. py:method:: get_config() Get the optimizer configuration Returns ------- :obj:`dict` the configuration of the optimizer .. py:function:: batch_optimize(optimizers, problems, save=True, setup_kwargs={}) Optimize a batch of optimizers in parallel (without requiring multiple CPU cores when using GPUs). Parameters ---------- optimizers: :obj:`list` of :obj:`cubnm.optimize.PymooOptimizer` or :obj:`cubnm.optimize.PymooOptimizer` A (list of) optimizer instance(s) to be run in parallel. If not a list, the same optimizer will be used for all problems and problems must be a list. problems: :obj:`list` of :obj:`cubnm.optimize.BNMProblem` or :obj:`cubnm.optimize.BNMProblem` A (list of) problem instance(s) to be set up with the optimizers. Will be mapped one-to-one with the optimizers. If not a list, the same problem will be used in all optimizers and optimizers must be a list. save: :obj:`bool`, optional save the optimizers and their results. This is more efficient than saving each optimizer separately as saving involves rerunning the optimal simulations, which is done in a batch in this function. setup_kwargs: :obj:`dict`, optional kwargs passed on to :meth:`cubnm.optimize.PymooOptimizer.setup_problem` Returns ------- optimizers: :obj:`list` of :obj:`cubnm.optimize.PymooOptimizer` A list of optimizer instances which have been run in parallel Example ------- Run CMAES for two subjects (with different SC and functional data) in a batch: :: from cubnm import datasets, optimize # assuming sub1 and sub2 SC and BOLD are available as # numpy arrays `sc_sub1`, `sc_sub2`, `bold_sub1`, `bold_sub2` # shared problem configuration problem_kwargs = dict( model = 'rWW', params = { 'G': (1.0, 3.0), 'wEE': (0.05, 0.5), 'wEI': 0.15, }, duration = 60, TR = 1, ) # problem for subject 1 p_sub1 = optimize.BNMProblem( sc = sc_sub1, emp_bold = bold_sub1, **problem_kwargs ) # problem for subject 2 p_sub2 = optimize.BNMProblem( sc = sc_sub2, emp_bold = bold_sub2, **problem_kwargs ) # optimizer cmaes = optimize.CMAESOptimizer(popsize=20, n_iter=10, seed=1) # batch optimization optimizers = optimize.batch_optimize(cmaes, [p_sub1, p_sub2]) # print optima print(optimizers[0].opt) print(optimizers[1].opt)