20
20
#
21
21
# https://www.nipreps.org/community/licensing/
22
22
#
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."""
87
24
88
25
from __future__ import annotations
89
26
101
38
from sklearn .metrics .pairwise import cosine_similarity
102
39
from sklearn .utils ._param_validation import Interval , StrOptions
103
40
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) ."""
106
43
BOUNDS_LAMBDA : tuple [float , float ] = (1e-3 , 1000 )
107
- """The limits for the parameter lambda ."""
44
+ """The limits for the parameter λ (signal scaling factor) ."""
108
45
THETA_EPSILON : float = 1e-5
109
46
"""Minimum nonzero angle."""
110
47
LBFGS_CONFIGURABLE_OPTIONS = {"disp" , "maxiter" , "ftol" , "gtol" }
@@ -143,8 +80,7 @@ class EddyMotionGPR(GaussianProcessRegressor):
143
80
144
81
In principle, Scikit-Learn's implementation normalizes the training data
145
82
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>`__).
148
84
From their paper (p. 167, end of first column):
149
85
150
86
Typically one just substracts the mean (:math:`\bar{\mathbf{f}}`)
@@ -161,7 +97,7 @@ class EddyMotionGPR(GaussianProcessRegressor):
161
97
I believe this is overlooked in [Andersson15]_, or they actually did not
162
98
use analytical gradient-descent:
163
99
164
- _A note on optimisation_
100
+ *A note on optimisation*
165
101
166
102
It is suggested, for example in Rasmussen and Williams (2006), that
167
103
an optimisation method that uses derivative information should be
@@ -175,6 +111,44 @@ class EddyMotionGPR(GaussianProcessRegressor):
175
111
frequently better at avoiding local maxima.
176
112
Hence, that was the method we used for all optimisations in the present
177
113
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
178
152
179
153
"""
180
154
@@ -184,7 +158,7 @@ class EddyMotionGPR(GaussianProcessRegressor):
184
158
"optimizer" : [StrOptions (SUPPORTED_OPTIMIZERS ), callable , None ],
185
159
"n_restarts_optimizer" : [Interval (Integral , 0 , None , closed = "left" )],
186
160
"copy_X_train" : ["boolean" ],
187
- "zeromean_y " : ["boolean" ],
161
+ "normalize_y " : ["boolean" ],
188
162
"n_targets" : [Interval (Integral , 1 , None , closed = "left" ), None ],
189
163
"random_state" : ["random_state" ],
190
164
}
@@ -497,9 +471,21 @@ def __repr__(self) -> str:
497
471
498
472
499
473
def exponential_covariance (theta : np .ndarray , a : float ) -> np .ndarray :
500
- """
474
+ r """
501
475
Compute the exponential covariance for given distances and scale parameter.
502
476
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
+
503
489
Parameters
504
490
----------
505
491
theta : :obj:`~numpy.ndarray`
@@ -517,9 +503,25 @@ def exponential_covariance(theta: np.ndarray, a: float) -> np.ndarray:
517
503
518
504
519
505
def spherical_covariance (theta : np .ndarray , a : float ) -> np .ndarray :
520
- """
506
+ r """
521
507
Compute the spherical covariance for given distances and scale parameter.
522
508
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
+
523
525
Parameters
524
526
----------
525
527
theta : :obj:`~numpy.ndarray`
@@ -583,12 +585,6 @@ def compute_pairwise_angles(
583
585
>>> compute_pairwise_angles(X)[0, 1]
584
586
0.0
585
587
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
-
592
588
"""
593
589
594
590
cosines = np .clip (cosine_similarity (X , Y , dense_output = dense_output ), - 1.0 , 1.0 )
0 commit comments