fit options in a parfor loop

조회 수: 12 (최근 30일)
Elizabeth Jones
Elizabeth Jones 2019년 11월 14일
답변: Elizabeth Jones 2019년 11월 19일
I am performing a fit of data multiple times using a loop. When I use a "for" loop, everything works as expected. However, if I use a "parfor" loop, I get an error. If I remove the fit options (fo), then the parfor loop works as expected. Does anyone know why the parfor loop generates an error when I specify the fit method using the fitoptions?
% Generate some data
Npts = 50;
Ntime = 10;
tau = 10;
x = repmat( (1:Npts)',1,Ntime);
y = exp(-x/tau) + (rand(Npts,Ntime)-0.5)/10;
% Plot the data
figure;
plot(x(:,1),y(:,1),'-o')
title('Data for first time step')
% Fit options
ft = fittype('exp1');
fo = fitoptions( 'Method', 'NonlinearLeastSquares' );
% Pre-allocate the decay constant, tau
tau = NaN(1,Ntime);
parfor q = 1:Ntime
% Perform the exponential fit at time step q
fitresult = fit( x(:,q), y(:,q), ft, fo);
% Save the decay constant, tau
tau(q) = -1/fitresult.b;
end
  댓글 수: 2
Walter Roberson
Walter Roberson 2019년 11월 14일
I confirm that the fo object is arriving empty on the worker, the way you would expect a global variable to look.
The work-around for the moment appears to be to assign fo inside the parfor loop.
Matt J
Matt J 2019년 11월 15일
편집: Matt J 2019년 11월 15일
Also confirmed in R2018a. Possibly it's because fo is a handle object?
>> ishandle(fo)
ans =
logical
1
Handle objects are supposed to be cloned to the workers, but who knows if there are weird exceptions...

댓글을 달려면 로그인하십시오.

채택된 답변

Elizabeth Jones
Elizabeth Jones 2019년 11월 19일
Thanks all for the support. I ended up setting the fit method as a character string outside of the loop (near the top, where I usually keep such "manual/hard-coded" values), and then constructing the fitoptions inside the parfor loop.
% Generate some data
Npts = 50;
Ntime = 10;
tau = 10;
x = repmat( (1:Npts)',1,Ntime);
y = exp(-x/tau) + (rand(Npts,Ntime)-0.5)/10;
% Plot the data
figure;
plot(x(:,1),y(:,1),'-o')
title('Data for first time step')
% Fit options
fiteqn = 'exp1';
fitmethod = 'NonlinearLeastSquares';
% Pre-allocate the decay constant, tau
tau = NaN(1,Ntime);
parfor q = 1:Ntime
% Perform the exponential fit at time step q
ft = fittype(fiteqn);
fo = fitoptions( 'Method', fitmethod);
fitresult = fit( x(:,q), y(:,q), ft, fo);
% Save the decay constant, tau
tau(q) = -1/fitresult.b;
end

추가 답변 (2개)

Matt J
Matt J 2019년 11월 15일
편집: Matt J 2019년 11월 15일
A guess as to why this might be happening is that fitoptions objects don't seem to implement proper save/load behavior, as indicated by this small experiment,
>> fo = fitoptions( 'Method', 'NonlinearLeastSquares' );
>> save fo_file fo
>> S=load('fo_file');
>> isequal(S.fo,fo)
ans =
logical
0
This is signifcant, because parpools use save/load operations to clone objects to the workers, as is alluded here.
However, this does not explain why the version of fo that gets loaded on the workers ends up empty. Reloading a fitoptions object outside a parpool doesn't have that effect:
>> isempty(S.fo)
ans =
logical
0

Edric Ellis
Edric Ellis 2019년 11월 15일
Unfortunately, this is a limitation in the implementation of the fitoptions class. You can work around this either by constructing the fitoptions inside the parfor loop, or you can use parallel.pool.Constant, like this:
% Use the "function handle" form constructor of parallel.pool.Constant to
% ensure that the fitoptions object is constructed on the workers
fo_c = parallel.pool.Constant(@() fitoptions( 'Method', 'NonlinearLeastSquares' ));
parfor ...
...
% Extract the fitoptions from the Constant
fo = fo_c.Value;
% Perform the exponential fit at time step q
fitresult = fit( x(:,q), y(:,q), ft, fo);
end

카테고리

Help CenterFile Exchange에서 Functional Programming에 대해 자세히 알아보기

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by