I'm trying to speedup the fit of a large amount of data with MATLAB by using parallelism, and I'm facing quite a strange problem.
I tried to isolate the problem hoping someone might have a clue about what's happening. Here's the sample code:
f = @(a, x) a*x;
fitopt = fitoptions(f);
for i = 1:5
disp(fitopt);
end
If I run the code above, the contents of fitopt
will be written 5 times as expected. However, if I replace the for
by a parfor
loop, fitopt
is set to empty and nothing is displayed.
Any clue what could be going wrong?
My config: MATLAB 2014a on windows 7, 64 bit
The following is based on MATLAB version R2016b...
As best as I can tell, this appears to be an issue with MATLAB's ability to correctly broadcast (or not) certain class objects to the parfor
workers. The fitoptions
function returns an object of class curvefit.nlsqoptions
in your example. Going through the Curve Fitting Toolbox code, one can see that these objects are still defined using an older UDD class system (a good introduction by Donn Shull can be found on Undocumented MATLAB). Although the newer MCOS (MATLAB Class Object System) was introduced many years ago, you can still find a number of objects defined using UDD.
In your example, fitopt
should be broadcast (i.e. copied) to each of the workers, but instead fitopt
is set to []
within the parfor
loop. If we try this with another class object defined using the newer class system (like those created by fittype
), then the broadcasting works fine. For example, this test code:
f = @(a, x) a*x;
uddObj = fitoptions(f);
mcosObj = fittype(f);
parfor i = 1:3
fprintf('\nWorker %d:\n', i);
uddObj
mcosObj
end
produces this output:
Worker 2:
uddObj =
[]
mcosObj =
General model:
mcosObj(a,x) = a*x
Worker 1:
uddObj =
[]
mcosObj =
General model:
mcosObj(a,x) = a*x
Worker 3:
uddObj =
[]
mcosObj =
General model:
mcosObj(a,x) = a*x
So, in short, it appears that parfor
loops can't correctly broadcast UDD style objects. One workaround would be to create these objects within the parfor loop, avoiding the broadcasting:
f = @(a, x) a*x;
parfor i = 1:5
fitopt = fitoptions(f); % Function handle f broadcasts just fine
disp(fitopt);
end
You could also create a sliced variable by creating an array of objects that you index into:
f = @(a, x) a*x;
fitopt = repmat(fitoptions(f), [1 5]);
parfor i = 1:5
disp(fitopt(i));
end