Differential Evolution for NODDIx

In the previous post, we took a loot at how the NODDIx model could be made faster with Cython. In this post, we will take a look at how we need to set up the differential evolution with for optimizing and finding the minima for the parameters of the NODDIx model. The code to this function can be found at the branch here: https://github.com/ShreyasFadnavis/dipy/tree/noddix_speed .

In this post I will be explaining about how Differential Evolution works and in what context we have used it for optimization:

Setting the Parameters in SciPy for Differential Evolution Optimization:

On evaluating this, we see that the NODDIx model converges in 81 steps within 6 seconds approximately when f(x)  = 1.10912e-07

The accuracy we get is:

References: 

[1]. Differential Evolution: A Practical Approach to Global Optimization https://www.springer.com/us/book/9783540209508

[2]. Numerical optimization by differential evolution https://www.youtube.com/watch?v=UZGiapWcoA4&t=2151s

 

Cythonizing Bottlenecks in the NODDIx Model

+

Over the past few days, I have been trying to remove the bottlenecks in the Python code by vector implementation using Numpy extensions and a variety of other code optimization techniques.

However, I have come to realize that even Numpy at times does not solve problems like Global Interpreter Lock and Bounds Checking. Cython, on the other hand gives a very nice interface with the lower level C implementations by inserting an intermediate layer between Python and its interpreted code in C. The following diagram will help demonstrate what I mean:

Courtesy: https://www.software.ac.uk/blog/2017-07-25-speeding-python-cython-some-thoughts-python-programmers

Typed MemoryViews in Cython… Blissful interaction with NumPy Arrays!

So, it is often the case that we need to cythonize only a part of our code and not all of it. This requires smooth interaction of other functions with the cythonized functions. MemoryView provides a really good way of  doing this by allowing efficient access to memory buffers, such as those underlying NumPy arrays, without incurring any Python overhead. Memoryviews are similar to the current NumPy array buffer support (np.ndarray[np.float64_t, ndim=2]), but they have more features and cleaner syntax.

Memoryviews are more general than the old NumPy array buffer support, because they can handle a wider variety of sources of array data. For example, they can handle C arrays and the Cython array type (Cython arrays).

A memoryview can be used in any context (function parameters, module-level, cdef class attribute, etc) and can be obtained from nearly any object that exposes writable buffer through the `PEP 3118`_ buffer interface.

Following is an example of the Legendre Gauss Integral in Python and its Cythonized equivalent following it:

The Cythonized Version:

Need to Zoom in for this one..

The entire code for along with other cythonized functions can be found on this branch: noddix_speed !

References:

https://cython.readthedocs.io/en/latest/src/userguide/memoryviews.html

Visualizing the NODDI Signal with GQI and Shore 3D models

In the previous post, we looked at how we can improve the speedup of fitting the simulated signal with Cython and what tweaks did we perform with the Legendre-Gauss Integration.

In this post, we will look at how the simulated signal can be visualized using the SHORE-3D Model and the GQI Model from the DIPY Library:

SHORE-3D Model: Exploits the ability of Compressed Sensing (CS) to recover the whole 3D Diffusion MRI (dMRI) signal from a limited number of samples while efficiently recovering important diffusion features such as the Ensemble Average Propagator (EAP) and the Orientation Distribution Function (ODF). 

Following are the crossings generated from the NODDIx model with crossings. The model helps visualize in the form of lobes:

GQI (Generalized q-sampling imaging):

Based on the Fourier transform relation between diffusion magnetic resonance (MR) signals and the underlying diffusion displacement, a new relation is derived to estimate the spin distribution function (SDF) directly from diffusion MR signals. This relation leads to an imaging method called generalized -sampling imaging (GQI), which can obtain the SDF from the shell sampling scheme used in -ball imaging (QBI) or the grid sampling scheme used in diffusion spectrum imaging (DSI). The GQI method can be applied to grid or shell sampling schemes and can provide directional and quantitative information about the crossing fibers.

The code for these visualizations can be found here.

 

References:

  1. “Generalized q-Sampling Imaging”, IEEE Trans Med Imaging. 2010 Sep;29(9):1626-35. doi: 10.1109/TMI.2010.2045126. Epub 2010 Mar 18
  2. Continuous diffusion signal, EAP and ODF estimation via Compressive Sensing in diffusion MRI”, Merlet, Sylvain. L et al., Medical Image Analysis , Volume 17 , Issue 5 , 556 – 572