How to save intermediate iterations during SPMD in MATLAB? - matlab

I am experimenting with MATLAB SPDM. However, I have the following problem to solve:
I am running a quite long algorithm and I would like to save the progress along the way in case the power gets cut, someone unplugs the power plug or memory error.
The loop has 144 iterations that take each around 30 minutes to complete => 72h. A lot of problems can occur in that interval.
Of course, I have the distributed computing toolbox on my machine. The computer has 4 physical cores. I run MATLAB R2016a.
I do not really want to use a parfor loop because I concatenate results and have dependency across iterations. I think SPMD is the best choice for what I want to do.
I'll try to describe what I want as best as I can:
I want to be able to save at a set iteration of the loop the results so far, and I want to save the results by worker.
Below is a Minimum (non)-Working Example. The last four lines should be put in a different .m file. This function, called within a parfor loop, allows to save intermediate iterations. It is working properly in other routines that I use. The error is at line 45 (output_save). Somehow, I would like to "pull" the composite object into a "regular" object (cell/structure).
My hunch is that I do not quite understand how Composite objects work and especially how they can be saved into "regular" objects (cells, structures, etc).
% SPMD MWE
% Clear necessary things
clear output output2 output_temp iter kk
% Useful thing that will be used later on
Rorder=perms(1:4);
% Stem of the file to save the data to
stem='MWE_MATLAB_spmd';
% Create empty cells where the results of the kk loop will be stored
output1{1,1}=[];
output2{1,2}=[];
% Start the parpool
poolobj=gcp;
% Define which worker/lab will do which iteration
iterperworker=ceil(size(Rorder,1)/poolobj.NumWorkers);
for i=1:poolobj.NumWorkers
if i<poolobj.NumWorkers
itertodo{1,i}=1+(iterperworker)*(i-1):iterperworker*i;
else
itertodo{1,i}=1+(iterperworker)*(i-1):size(Rorder,1);
end
end
%Start the spmd
% try
spmd
iter=1;
for kk=itertodo{1,labindex}
% Print which iteration is done at the moment
fprintf('\n');
fprintf('Ordering %d/%d \r',kk,size(Rorder,1));
for j=1:size(Rorder,2)
output_temp(1,j)=Rorder(kk,j).^j; % just to populate a structure
end
output.output1{1,1}=cat(2,output.output1{1,1},output_temp); % Concatenate the results
output.output2{1,2}=cat(2,output.output1{1,2},0.5*output_temp); % Concatenate the results
labindex_save=labindex;
if mod(iter,2)==0
output2.output=output; % manually put output in a structure
dosave(stem,labindex_save,output2); % Calls the function that allows me to save in parallel computing
end
iter=iter+1;
end
end
% catch me
% end
% Function to paste in another m-file
% function dosave(stem,i,vars)
% save(sprintf([stem '%d.mat'],i),'-struct','vars')
% end

A Composite is created only outside an spmd block. In particular, variables that you define inside an spmd block exist as a Composite outside that block. When the same variable is used back inside an spmd block, it is transformed back into the original value. Like so:
spmd
x = labindex;
end
isa(x, 'Composite') % true
spmd
isa(x, 'Composite') % false
isequal(x, labindex) % true
end
So, you should not be transforming output using {:} indexing - it is not a Composite. I think you should simply be able to use
dosave(stem, labindex, output);

Related

Using a for loop inside a parallel for loop in Matlab

I am trying to use a for loop inside of a parfor loop in Matlab.
The for loop is equivalent to the ballode example in here.
Inside the for loop a function ballBouncing is called which is a system of 6 differential equations.
So, what I am trying to do is to use 500 different sets of parameter values for the ODE system and run it, but for each parameter set, a sudden impulse is added, which is handled through the code in 'for' loop.
However, I don't understand how to implement this using a parfor and a for loop as below.
I could run this code by using two for loops but when the outer loop is made to be a parfor it gives the errors,
the PARFOR loop cannot run due to the way variable results is used,
the PARFOR loop cannot run due to the way variable y0 is used and
Valid indices for results are restricted in PARFOR loops
results=NaN(500,100);
x=rand(500,10);
parfor j=1:500
bouncingTimes=[10,50];%at time 10 a sudden impulse is added
refine=2;
tout=0;
yout=y0;%initial conditions of ODE system
paras=x(j,:);%parameter values for the ODE
for i=1:2
tfinal=bouncingTimes(i);
[t,y]=ode45(#(t,y)ballBouncing(t,y,paras),tstart:1:tfinal,y0,options);
nt=length(t);
tout=[tout;t(2:nt)];
yout=[yout;y(2:nt,:)];
y0(1:5)=y(nt,1:5);%updating initial conditions with the impulse
y0(6)=y(nt,6)+paras(j,10);
options = odeset(options,'InitialStep',t(nt)-t(nt-refine),...
'MaxStep',t(nt)-t(1));
tstart =t(nt);
end
numRows=length(yout(:,1));
results(1:numRows,j)=yout(:,1);
end
results;
Can someone help me to implement this using a parfor outer loop.
Fixing the assignment into results is relatively straightforward - what you need to do is ensure you always assign a whole column. Here's how I would do that:
% We will always need the full size of results in dimension 1
numRows = size(results, 1);
parfor j = ...
yout = ...; % variable size
yout(end:numRows, :) = NaN; % Expand if necessary
results(:, j) = yout(1:numRows, 1); % Shrink 'yout' if necessary
end
However, y0 is harder to deal with - the iterations of your parfor loop are not order-independent because of the way you're passing information from one iteration to the next. parfor can only handle loops where the iterations are order-independent.

How to use SPMD for different input variables and save the output in order?

I am using a simulated annealing algorithm to optimize my problem, I have to do it for 100 different input variables and save the output for all variables in order. the problem is that I don't know how to implement spmd in my code to do parallel computing so that each input run on one CPU core and the final results stored in a matrix with 100 rows. I've tried to put it before the first for loop but it only returns a composite consists of 4 elements, since my CPU has 4 cores. Here is my code
spmd
for v=1:100
posmat=loading_param(Matrix,v);
nvar=size(posmat,2);
popsize=50;
maxiter=20;
T0=1000;
Tf=1;
Tdamp=((T0-Tf)/maxiter);
nn=5;
T=T0;
%% initial population
tic
emp.var=[];
emp.fit=inf;
pop=repmat(emp,popsize,1);
for i=1:popsize
pop(i).var=randperm(nvar);
pop_double=pop(i).var;
posmat_new=tabdil(nvar,pop_double,posmat);
dis=cij(posmat_new);
pop(i).fit=fittness(dis);
end
[value,index]=min([pop.fit]);
gpop=pop(index);
%% algorithm main loop
BEST=zeros(maxiter,1);
for iter=1:maxiter
for i=1:popsize
bnpop=emp;
for j=1:nn
npop=create_new_pop(pop(j),nvar,posmat);
if npop.fit<bnpop.fit
bnpop=npop;
end
end
if bnpop.fit<pop(i).fit
pop(i)=bnpop;
else
E=bnpop.fit-pop(i).fit;
pr=exp(-E/T);
if rand<pr
pop(i)=bnpop;
end
end
end
T=T-Tdamp;
[value,index]=min([pop.fit]);
if value<gpop.fit
gpop=pop(index);
BEST(iter)=gpop.fit;
disp([ 'iter= ' num2str(iter) 'BEST=' num2str(BEST(iter))])
end
end
%% algorithm results
disp([ ' Best solution=' num2str(gpop.var)])
disp([ ' Best fittness=' num2str(gpop.fit)])
disp([ ' Best time=' num2str(toc)])
bnpop_all(d,:)=bnpop.var;
d=d+1;
end %end of main for loop
end % end of spmd
From the documentation on spmd:
Values returning from the body of an spmd statement are converted to Composite objects on the MATLAB client. A Composite object contains references to the values stored on the remote MATLAB workers, and those values can be retrieved using cell-array indexing. The actual data on the workers remains available on the workers for subsequent spmd execution, so long as the Composite exists on the client and the parallel pool remains open.
Thus the output is a composite with 4 elements, since you have 4 CPU cores, so output{1} gives you the first element, output{2} the second etc. Just concatenate those to get your output in a single matrix.
Your code at this point just runs four times, one complete 100 iteration for loop per worker. An easier way to solve this, is to use parfor instead of spmd, as you can leave your loop the same. If you want to use spmd, first cut your v into four pieces (of 25 elements each), then on each worker iterate over just those 25 elements.
Seeing your code, with its three nested loops, I suggest not parallellising now, but instead try to profile your code, find out where the bottlenecks are, and try to speed up those. Probably trying to vectorise your nested loops will improve a lot already.

Order of graphics creation and data processing in MATLAB

I'm processing vast amount of data (>>100k lines) with variable step.
I would like to create figure and plot the processed data as they are counted (for termination of the running script when something goes wrong, or for impressing the "customers" with the fancy progress "animation").
Suppose we have `sourcefile.txt' with one column of positive numbers X(n) on row n and:
There is plenty of lines with X(n+1) < X(n),
X(n+N) > X(n); where N goes from thousands for small n to tens for large n.
I've thought of:
fID=fopen('sourcefile.txt');
figure;axes; % create figure
act='0';threshold=0;N=0;DATA=0;ii=0;
while ischar(act) % loop until end of file.
ii=ii+1;N=0;
while temp<threshold&&ischar(act) % loop until threshold is overflown (next step) or end-of-file is reached.
act=fgetl(fID);
temp=temp+str2double(act);
N=N+1;
end
line('xdata',ii,'ydata',temp/N,'Marker','o') % New point should appear
threshold=threshold+0.5; % Continue with new stopping rule.
end
The problem is that the loops are entered and processed and then figure is created. How can I force MATLAB to create a figure and then to calculate/update plotted data?
Try inserting drawnow after you draw the line using line. This will flush the graphics buffer and update your figure immediately. If you don't do this, your figure will appear blank until the loop finishes, and then the figure will appear with your objects that you added to the figure.
So to be specific with what I talked about:
fID=fopen('sourcefile.txt');
figure;axes; % create figure
act='0';threshold=0;N=0;DATA=0;ii=0;
while ischar(act) % loop until end of file.
ii=ii+1;N=0;
while temp<threshold&&ischar(act) % loop until threshold is overflown (next step) or end-of-file is reached.
act=fgetl(fID);
temp=temp+str2double(act);
N=N+1;
end
line('xdata',ii,'ydata',temp/N,'Marker','o') % New point should appear
%%%%%%%%%%%%// Change here
drawnow;
threshold=threshold+0.5; % Continue with new stopping rule.
end
Therefore, once you draw a line, the figure should immediately update itself and so for each iteration, the figure should update with a new line object.

Vectorizing disparityMap in Matlab

I am implementing an Sum of Square Distances based disparity Map function in Matlab for computer vision. Currently the code has a nested for loop and runs very slow. Any suggestions on vectorizing it to make it more efficient? Thanks
%im1 and im2 are images and win1, win2 are window sizes
for i=win1+1:1:bottom-win1
parfor j=win2+1:1:right-win2
%j=[win2+1:bottom-win2];
template=im1(i-win1:i+win1,j-win2:j+win2);
arg1=conv2(im2.^2,ones(size(template))/2,'same');
arg2=conv2(im2,rot90(template,2),'same');
arg=arg1-arg2;
[xj]=find(arg==min(arg(:)));
disparityMap(i,j)=1-xj(1);
end
end
Three suggestions to try to speed things up:
move the parfor to the outer loop to reduce the overhead of the parallel construct ;
compute im2.^2 once before the loop and save its value in a temporary variable as it does not depend on the loop variables there is no need to compute it again and again, and actually
move the whole computation of arg1 out of the loops as it only depends on the size of template and not its value, and if I see correctly, the size is constant ;
replace the [xj]=find(arg==min(arg(:))); construct with something along the lines of [tmp, ind] = min(arg(:)) ; xj=ind2sub(size(arg), ind) to avoid the call to find and rescan the matrix while the indices can be computed simply.
Untested, but it should give you a start
arg1=conv2(im2.^2,ones([2*win1+1, 2*win2+1])/2,'same');
parfor i=win1+1:1:bottom-win1
for j=win2+1:1:right-win2
%j=[win2+1:bottom-win2];
template=im1(i-win1:i+win1,j-win2:j+win2);
arg2=conv2(im2,rot90(template,2),'same');
arg=arg1-arg2;
[tmp, ind] = min(arg(:)) ;
xj=ind2sub(size(arg), ind);
disparityMap(i,j)=1-xj(1);
end
end
Also make sure the number of workers is chosen appropriately, and try to compile the code to mex to see if there is improvement.

will same variable name cause conflict in parfor

I have a basic code like this :
parfor i=1:8
[t,y]=ode15s(#rate,tspan,cin,options,i); % the option i is evaluated in the rate function
figure(1)
subplot(3,3,i+1)
plot(t,y)
hold on
end
Will any conflict arise because the variable name y is same in all iterations ?
No, every worker has its unique namespace.
However, a worker cannot open figures that display on the client (thanks for the reminder, #Edric), so everything after the call to ode15s will not produce any useful result.
To move the plotting outside the parfor loop, you can do the following (there are more efficient solutions, this one will work for sure):
tCell = cell(8,1);
yCell = cell(8,1);
parfor i=1:8
[tCell{i},yCell{i}]=ode15s(#rate,tspan,cin,options,i); % the option i is evaluated in the rate function
end
figure(1)
for i=1:8
subplot(3,3,i+1)
plot(tCell{i},yCell{i})
hold on
end
Following on from #Jonas' answer, just a note to point out that if you're using R2013b or later, and you wish to display graphics while waiting for your parallel computations to complete, you could use PARFEVAL, like in this example: http://www.mathworks.co.uk/help/distcomp/examples/parfeval-blackjack.html .