fmincon gets very slow after few time

20 views (last 30 days)
Miguel Ángel
Miguel Ángel on 23 Nov 2021
Edited: Matt J on 30 Nov 2021
Hi all,
I am using fmincon for finding endmembers in each pixel of an image. I have a double for loop which goes pixel by pixel applying fmincon. When the code starts, each pixel optimization is pretty fast (miliseconds), but as the run advances it starts getting slower and slower. It does not have to do with memory allocation issues since I do it. Also, if I close Matlab and reopen it, if I continue in the last pixel it gets fast again for the first pixels, but again slower and slower until it takes lime one minute per pixel.
Here the example of code I am using:
maps = single(zeros(rows,columns,3)); % Create empty maps.
cont = 0;
for row = 1:rows
for col = 1:columns
cont = cont + 1;
C_MSE_subt = fmincon( @(x)SAMSID_subtractive(double(squeeze(cube(row,col,:))),E,x'), init_point, [-1 0 0; 0 -1 0; 0 0 -1 ], [0; 0; 0], [1 1 1], 1, [0 0 0], [1 1 1],[],options);
maps(row,col,:) = reshape(C_MSE_subt,1,1,3);
end
end
The optimizatiob function is pretty simple, just calculating a spectrum and comparing it against the one passed as input:
function SAMSID = SAMSID_subtractive(spectra1,E,C)
spectra2 = subtractive_model(E,C);
[~,~,SAMSID]=samsid(spectra1,spectra2);
It would seem normal to me if every pixel behaved slow. But the few first pixels very fast and then get slower and slower... Also I checked RAM and CPU and none of them are busy.
If I change the optimization function it does not get slow. For instance, using MSE instead of SAMSID metric, it is fast from the beggining to the end:
function MSE = mean_squared_error_subtractive(spectra1,E,C)
spectra2 = subtractive_model(E,C);
MSE = sum((spectra1-spectra2).^2) / size(spectra1,1);
Any ideas of why this could happen?
Thanks in advance!
  2 Comments
Matt J
Matt J on 23 Nov 2021
What do you mean by "getting slower"? How are you observing changes in speed?
Also, what is samsid()? It does not seem to be a Mathworks-provided function.
Matt J
Matt J on 23 Nov 2021
Edited: Matt J on 23 Nov 2021
Incidentally, you should get rid of your inequality constraints,
A=[-1 0 0; 0 -1 0; 0 0 -1 ]; b= [0; 0; 0];
They are redundant with your explicit lower bounds lb=[0 0 0] and are just slowing things down.

Sign in to comment.

Answers (2)

Matt J
Matt J on 23 Nov 2021
I suspect samsid() is just not as smooth or well-conditioned as mse() for some pixels, and therefore takes more iterations to terminate. You can check the fmincon output to see how many iterations are being performed in each pixel and see if it correlates with the slow-down you are observing.
  8 Comments
Miguel Ángel
Miguel Ángel on 30 Nov 2021
I did verify. The task manager has always been open with the resources tab selected. No ram variations. I have 64 GB RAM and not even 15 GB are consumed during the whole process.
Functions are local. They are not nested in the same Matlab script, but they are all as .m files in the same folder of the main code.
It is difficult to say whether it is reasonable or not, since in order to check this I would need to get the entire map and post-process it a bit to get the final presence map. But I only got barely 10 lines of it after more than three days of run. SAMSID metric is a combination of sam and sid metrics. The first one is an angle, and samsid takes the sine of this angle which is bounded in [0, 1]. SID is the spectral information divergence which has no upper bound (the lower the more similar the spectra are). SAMSID multiplies sine(sam)*sid, so also has no bounds.
Matt J
Matt J on 30 Nov 2021
Edited: Matt J on 30 Nov 2021
Functions are local. They are not nested in the same Matlab script, but they are all as .m files in the same folder of the main code.
If so, they are neither local nor nested.

Sign in to comment.


Matt J
Matt J on 23 Nov 2021
A few more performance optimizations that you should consider:
maps = zeros(rows,columns,3,'single'); %<------ post conversion to single is unnecessary
cube=double(cube); %<----pre-cast the whole array to double
cont = 0;
for row = 1:rows
for col = 1:columns
cont = cont + 1;
tmp=squeeze(cube(row,col,:)); %<------ avoid doing this in every function call
C_MSE_subt = fmincon( @(x)SAMSID_subtractive(tmp,E,x'), init_point, [], [], [1 1 1], 1, [0 0 0], [1 1 1],[],options);
maps(row,col,:) = reshape(C_MSE_subt,1,1,3);
init_point(:)=C_MSE_subt(:); %<----- the previous solution might be very close to the next one
end
end
  1 Comment
Miguel Ángel
Miguel Ángel on 26 Nov 2021
Thanks for all valuable tips. I implemented them all:
cube = double(cube);
SAMSID = zeros(rows,columns,'single'); % Create empty SAMSID map.
ti = SAMSID; % Create empty optimization time map.
flag = SAMSID;
iter = SAMSID;
cont = 0;
for row = 1:rows
for col = 1:columns
cont = cont + 1;
clc, disp(['Generating pigments map: ' num2str(cont/num_pixels*100) '%...'])
tmp = squeeze(cube(row,col,:));
tic
[C_SAMSID_subt,SAMSID(row,col),flag(row,col),output] = fmincon( @(x)SAMSID_subtractive(tmp,E,x'), init_point, [], [], [1 1 1], 1, [0 0 0], [1 1 1],[],options);
ti(row,col) = toc;
iter(row,col) = output.iterations;
maps(row,col,:) = reshape(C_SAMSID_subt,1,1,3);
init_pont(:) = C_SAMSID_subt(:);
end
end

Sign in to comment.

Categories

Find more on Introduction to Installation and Licensing in Help Center and File Exchange

Products


Release

R2020a

Community Treasure Hunt

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

Start Hunting!