Hi all,
I am using pymc to perform a 3-parameter mono-exponential decay fitting (y = A exp(-t/T2)+B); However, it takes 4 seconds to complete one fitting task. For comparison, it only takes scipy.curve_fit 1.5ms to complete the same fit.
With the current implementation, it takes (256x256x256*4/60/60/24) ~ 777 days to complete one 3D MRI volume with 256x256x256 resolution. It would be too long to be used in practice.
Maybe my naive implementation is not efficient. If you have any suggestions to make it faster, please let me know. Thanks!
Below is the code to reproduce the computation times.
import pymc as pm
from pymc import HalfCauchy, Model, Normal, sample, Uniform, Rice, HalfNormal, TruncatedNormal
import numpy as np
from scipy.optimize import curve_fit
import tqdm
def exp_decay(x, T2, A, B):
return A*np.exp(-x/T2) + B
# set the true values of the model parameters for creating the data
T2 = 5 # T2 relaxation 1 ms
A = 1.0
B = 0.0
SNR = 30
M = 6
x = np.array([0.1, 2.7, 5.3, 7.9, 10.5, 13.1]) #ms
np.random.seed(202006)
# create the data - the model plus Rician noise
y0 = exp_decay(x, T2, A, B)
sigma = y0[0]/SNR # standard deviation of the noise
y = np.abs(y0 + sigma*np.random.randn(M))
y = y/np.max(y)
sigma_est = np.std(y[len(y)//2:])
T2mean_est = -(x[1]-x[0])/np.log(y[1]/y[0])
sigma_est, T2mean_est
%%time
with Model() as model:
# Define priors
sigmamodel = HalfNormal('sigma', sigma=sigma_est)
Amodel = HalfNormal('A', sigma=y[0])
Bmodel = HalfNormal('B', sigma=sigma_est)
T2model = TruncatedNormal('T2', mu=T2mean_est, sigma=T2mean_est, lower=0, upper=2*T2mean_est)
linkfunc = exp_decay(x, T2model, Amodel, Bmodel)
likelihood = Rice('data', nu=linkfunc, sigma=sigmamodel, observed=y)
idata = sample(draws=2048, chains=4, cores=1, tune=2048, target_accept=.9999,
nuts_sampler="nutpie",
progressbar=False)
%%time
popt, pcov = curve_fit(exp_decay, x, y, p0 =(T2mean_est, y[0], 0), maxfev=50000000)

