2020#
2121# https://www.nipreps.org/community/licensing/
2222#
23- r"""
24- Derivations from scikit-learn for Gaussian Processes.
25-
26- Gaussian Process Model: Pairwise orientation angles
27- ---------------------------------------------------
28- Squared Exponential covariance kernel
29- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30- Kernel based on a squared exponential function for Gaussian processes on
31- multi-shell DWI data following to eqs. 14 and 16 in [Andersson15]_.
32- For a 2-shell case, the :math:`\mathbf{K}` kernel can be written as:
33-
34- .. math::
35- \begin{equation}
36- \mathbf{K} = \left[
37- \begin{matrix}
38- \lambda C_{\theta}(\theta (\mathbf{G}_{1}); a) + \sigma_{1}^{2} \mathbf{I} &
39- \lambda C_{\theta}(\theta (\mathbf{G}_{2}, \mathbf{G}_{1}); a) C_{b}(b_{2}, b_{1}; \ell) \\
40- \lambda C_{\theta}(\theta (\mathbf{G}_{1}, \mathbf{G}_{2}); a) C_{b}(b_{1}, b_{2}; \ell) &
41- \lambda C_{\theta}(\theta (\mathbf{G}_{2}); a) + \sigma_{2}^{2} \mathbf{I} \\
42- \end{matrix}
43- \right]
44- \end{equation}
45-
46- **Squared exponential shell-wise covariance kernel**:
47- Compute the squared exponential smooth function describing how the
48- covariance changes along the b direction.
49- It uses the log of the b-values as the measure of distance along the
50- b-direction according to eq. 15 in [Andersson15]_.
51-
52- .. math::
53- C_{b}(b, b'; \ell) = \exp\left( - \frac{(\log b - \log b')^2}{2 \ell^2} \right).
54-
55- **Squared exponential covariance kernel**:
56- Compute the squared exponential covariance matrix following to eq. 14 in [Andersson15]_.
57-
58- .. math::
59- k(\textbf{x}, \textbf{x'}) = C_{\theta}(\mathbf{g}, \mathbf{g'}; a) C_{b}(|b - b'|; \ell)
60-
61- where :math:`C_{\theta}` is given by:
62-
63- .. math::
64- \begin{equation}
65- C(\theta) =
66- \begin{cases}
67- 1 - \frac{3 \theta}{2 a} + \frac{\theta^3}{2 a^3} & \textnormal{if} \; \theta \leq a \\
68- 0 & \textnormal{if} \; \theta > a
69- \end{cases}
70- \end{equation}
71-
72- :math:`\theta` being computed as:
73-
74- .. math::
75- \theta(\mathbf{g}, \mathbf{g'}) = \arccos(|\langle \mathbf{g}, \mathbf{g'} \rangle|)
76-
77- and :math:`C_{b}` is given by:
78-
79- .. math::
80- C_{b}(b, b'; \ell) = \exp\left( - \frac{(\log b - \log b')^2}{2 \ell^2} \right)
81-
82- :math:`b` and :math:`b'` being the b-values, and :math:`\mathbf{g}` and
83- :math:`\mathbf{g'}` the unit diffusion-encoding gradient unit vectors of the
84- shells; and :math:`{a, \ell}` some hyperparameters.
85-
86- """
23+ """Derivations from scikit-learn for Gaussian Processes."""
8724
8825from __future__ import annotations
8926
10138from sklearn .metrics .pairwise import cosine_similarity
10239from sklearn .utils ._param_validation import Interval , StrOptions
10340
104- BOUNDS_A : tuple [float , float ] = (0.1 , np . pi )
105- """The limits for the parameter *a*."""
41+ BOUNDS_A : tuple [float , float ] = (0.1 , 2.35 )
42+ """The limits for the parameter *a* (angular distance in rad) ."""
10643BOUNDS_LAMBDA : tuple [float , float ] = (1e-3 , 1000 )
107- """The limits for the parameter lambda ."""
44+ """The limits for the parameter λ (signal scaling factor) ."""
10845THETA_EPSILON : float = 1e-5
10946"""Minimum nonzero angle."""
11047LBFGS_CONFIGURABLE_OPTIONS = {"disp" , "maxiter" , "ftol" , "gtol" }
@@ -143,8 +80,7 @@ class EddyMotionGPR(GaussianProcessRegressor):
14380
14481 In principle, Scikit-Learn's implementation normalizes the training data
14582 as in [Andersson15]_ (see
146- `FSL's souce code <https://git.fmrib.ox.ac.uk/fsl/eddy/-/blob/\
147- 2480dda293d4cec83014454db3a193b87921f6b0/DiffusionGP.cpp#L218>`__).
83+ `FSL's souce code <https://git.fmrib.ox.ac.uk/fsl/eddy/-/blob/2480dda293d4cec83014454db3a193b87921f6b0/DiffusionGP.cpp#L218>`__).
14884 From their paper (p. 167, end of first column):
14985
15086 Typically one just substracts the mean (:math:`\bar{\mathbf{f}}`)
@@ -161,7 +97,7 @@ class EddyMotionGPR(GaussianProcessRegressor):
16197 I believe this is overlooked in [Andersson15]_, or they actually did not
16298 use analytical gradient-descent:
16399
164- _A note on optimisation_
100+ *A note on optimisation*
165101
166102 It is suggested, for example in Rasmussen and Williams (2006), that
167103 an optimisation method that uses derivative information should be
@@ -175,6 +111,44 @@ class EddyMotionGPR(GaussianProcessRegressor):
175111 frequently better at avoiding local maxima.
176112 Hence, that was the method we used for all optimisations in the present
177113 paper.
114+
115+ **Multi-shell regression (TODO).**
116+ For multi-shell modeling, the kernel :math:`k(\textbf{x}, \textbf{x'})`
117+ is updated following Eq. (14) in [Andersson15]_.
118+
119+ .. math::
120+ k(\textbf{x}, \textbf{x'}) = C_{\theta}(\mathbf{g}, \mathbf{g'}; a) C_{b}(|b - b'|; \ell)
121+
122+ and :math:`C_{b}` is based the log of the b-values ratio, a measure of distance along the
123+ b-direction, according to Eq. (15) given by:
124+
125+ .. math::
126+ C_{b}(b, b'; \ell) = \exp\left( - \frac{(\log b - \log b')^2}{2 \ell^2} \right),
127+
128+ :math:`b` and :math:`b'` being the b-values, and :math:`\mathbf{g}` and
129+ :math:`\mathbf{g'}` the unit diffusion-encoding gradient unit vectors of the
130+ shells; and :math:`{a, \ell}` some hyperparameters.
131+
132+ The full GP regression kernel :math:`\mathbf{K}` is then updated for a 2-shell case as
133+ follows (Eq. (16) in [Andersson15]_):
134+
135+ .. math::
136+ \begin{equation}
137+ \mathbf{K} = \left[
138+ \begin{matrix}
139+ \lambda C_{\theta}(\theta (\mathbf{G}_{1}); a) + \sigma_{1}^{2} \mathbf{I} &
140+ \lambda C_{\theta}(\theta (\mathbf{G}_{2}, \mathbf{G}_{1}); a) C_{b}(b_{2}, b_{1}; \ell) \\
141+ \lambda C_{\theta}(\theta (\mathbf{G}_{1}, \mathbf{G}_{2}); a) C_{b}(b_{1}, b_{2}; \ell) &
142+ \lambda C_{\theta}(\theta (\mathbf{G}_{2}); a) + \sigma_{2}^{2} \mathbf{I} \\
143+ \end{matrix}
144+ \right]
145+ \end{equation}
146+
147+ References
148+ ----------
149+ .. [Andersson15] J. L. R. Andersson. et al., An integrated approach to
150+ correction for off-resonance effects and subject movement in diffusion MR
151+ imaging, NeuroImage 125 (2016) 1063-11078
178152
179153 """
180154
@@ -184,7 +158,7 @@ class EddyMotionGPR(GaussianProcessRegressor):
184158 "optimizer" : [StrOptions (SUPPORTED_OPTIMIZERS ), callable , None ],
185159 "n_restarts_optimizer" : [Interval (Integral , 0 , None , closed = "left" )],
186160 "copy_X_train" : ["boolean" ],
187- "zeromean_y " : ["boolean" ],
161+ "normalize_y " : ["boolean" ],
188162 "n_targets" : [Interval (Integral , 1 , None , closed = "left" ), None ],
189163 "random_state" : ["random_state" ],
190164 }
@@ -497,9 +471,21 @@ def __repr__(self) -> str:
497471
498472
499473def exponential_covariance (theta : np .ndarray , a : float ) -> np .ndarray :
500- """
474+ r """
501475 Compute the exponential covariance for given distances and scale parameter.
502476
477+ Implements :math:`C_{\theta}`, following Eq. (9) in [Andersson15]_:
478+
479+ .. math::
480+ \begin{equation}
481+ C(\theta) = e^{-\theta/a} \,\, \text{for} \, 0 \leq \theta \leq \pi,
482+ \end{equation}
483+
484+ :math:`\theta` being computed as:
485+
486+ .. math::
487+ \theta(\mathbf{g}, \mathbf{g'}) = \arccos(|\langle \mathbf{g}, \mathbf{g'} \rangle|)
488+
503489 Parameters
504490 ----------
505491 theta : :obj:`~numpy.ndarray`
@@ -517,9 +503,25 @@ def exponential_covariance(theta: np.ndarray, a: float) -> np.ndarray:
517503
518504
519505def spherical_covariance (theta : np .ndarray , a : float ) -> np .ndarray :
520- """
506+ r """
521507 Compute the spherical covariance for given distances and scale parameter.
522508
509+ Implements :math:`C_{\theta}`, following Eq. (10) in [Andersson15]_:
510+
511+ .. math::
512+ \begin{equation}
513+ C(\theta) =
514+ \begin{cases}
515+ 1 - \frac{3 \theta}{2 a} + \frac{\theta^3}{2 a^3} & \textnormal{if} \; \theta \leq a \\
516+ 0 & \textnormal{if} \; \theta > a
517+ \end{cases}
518+ \end{equation}
519+
520+ :math:`\theta` being computed as:
521+
522+ .. math::
523+ \theta(\mathbf{g}, \mathbf{g'}) = \arccos(|\langle \mathbf{g}, \mathbf{g'} \rangle|)
524+
523525 Parameters
524526 ----------
525527 theta : :obj:`~numpy.ndarray`
@@ -583,12 +585,6 @@ def compute_pairwise_angles(
583585 >>> compute_pairwise_angles(X)[0, 1]
584586 0.0
585587
586- References
587- ----------
588- .. [Andersson15] J. L. R. Andersson. et al., An integrated approach to
589- correction for off-resonance effects and subject movement in diffusion MR
590- imaging, NeuroImage 125 (2016) 1063-11078
591-
592588 """
593589
594590 cosines = np .clip (cosine_similarity (X , Y , dense_output = dense_output ), - 1.0 , 1.0 )
0 commit comments