I have been using nlinfit to extract two parameters (p1 and p2) from a simple exponential equation on a pixel basis for medical images. The dependent variable values are stored in Y (e.g. 53248x5 for an image of 208x256 pixels and 5 variable values). The 5 independent variables values are stored in X (e.g. 1x5 for 5 values). I am doing the fitting using the following bit of code:
equation=@(p,X) p(1)*exp(-X*p(2)); options=statset('FunValCheck','off');
parfor i=1:d1*d2 if sum(Y(i,:))>60; B(i,:)=nlinfit(X,Y(i,:),equation,[Y(i,1) 0.001],options); end end
The threshold of 60 is to make sure that fitting only takes place in pixels with useful signal (above noise level). The issue with the code above is that it takes almost 25sec to complete the pixel-based fitting for an image of 208x256 pixels and this is too long (even with parfor and 4 workers). I have tried various ways to vectorize the code above and speed things up, but with no success.
I would really appreciate any ideas.
No products are associated with this question.
If the fit can be done with 5 data points only, I assume the data errors are very small, in which case, you might get a pretty accurate fit just by doing a linear fit to the log of your model
logY = log(p(1)) - X*p(2)
This can be solved for a=log(p(1)) and b=-p(2) using any of MATLAB's solvers, and of course it can be further vectorized across all Y(i,:),
Xcell=[ones(size(X)), X].'; Xcell= num2cell(reshape(Xcell, 5,2,),[1,2] ); Xcell=cellfun(@sparse,Xcell,'uni',0);
If nothing else, this might give you a better beta0 than [Y(i,1) 0.001] and that, of course, could speed things up.
I have tried various ways to vectorize the code above and speed things up, but with no success.
It would help to know what you tried. Obviously, if N is the number of pixels, you could write your modelfun in terms of your entire 5xN array X and a 2*N parameter vector beta
function Y=totalmodel(beta,X) %beta - length 2N vector % X - 5xN data set
beta=reshape(beta,2,); p1=beta(1,:); p2=beta(2,:);
Y=exp(bsxfun(@times,X,-p1)); Y=bsxfun(@times,Y,p2); Y=Y(:);
As I mentioned to Lennart, it would probably also be of benefit to use nlinfit's Jacobian option with this. The Jacobian should turn out to be a very sparse block diagonal matrix. By computing it yourself, you would communicate that sparsity to nlinfit, as well as the separable structure of the problem.