1

Why the straight implementation of the mean function is faster?

Ig = rgb2gray(imread('test.png'));
n = 100000;
tic;
for ii=1:n
    M1 = sum(sum(Ig))/numel(Ig);
end
toc
tic;
for ii=1:n
    M2 = mean2(Ig);
end
toc

around n = 1000, still mean2 is faster. But as the number of iteration increases it becomes slower.

Elapsed time is 45.934058 seconds.
Elapsed time is 46.392206 seconds.

I am suspicious that inside mean2 it is doing something like this:

out = sum(x(:),'double') / numel(x)

Could the x(:) and the 'double' be the reason?

peterchen
  • 40,917
  • 20
  • 104
  • 186
NKN
  • 6,482
  • 6
  • 36
  • 55
  • That's exactly it. `mean2` unrolls the 2D matrix into a vector and does the mean directly. The unrolling is probably why you're getting a performance gain. I can't remember for the life of me where I saw it, but there were some timing tests done (here) where unrolling before computing helped make things faster... but then performance degrades as the array gets larger because you're unrolling more elements. – rayryeng Sep 14 '15 at 15:28
  • Perhaps do the timing with `timeit` to be sure? – Luis Mendo Sep 14 '15 at 15:33
  • @rayryeng But here it's not the array that gets larger; it's just the number of repetitions (if I understand the question correctly) – Luis Mendo Sep 14 '15 at 15:35
  • @LuisMendo - That's what happens when I misread code. Yes you're right... that is a curious anomaly. – rayryeng Sep 14 '15 at 15:36
  • The difference is small anyway – Luis Mendo Sep 14 '15 at 15:39

1 Answers1

1

Conclusion after running some test codes: 1) The reason that in your codes, mean2 appear to be slower when iteration number is larger than 1000 is because of the penalty for organizing codes into function. MATLAB needs to create a scope for function and terminates it when function call ends This can been seen from the test condition below in which I implement the mean2 directly in the codes. 2) Per @rayryeng's comment, unrolling first speeds up computation when array is large(at least within my test conditions). 3) The 'double' argument in sum(Ig(:),'double') takes up some time and is actually unnecessary because sum returns double data type even without that argument.

The codes I used for test are as follows:

Img = rgb2gray(imread('test2.tif'));  % this is an rgb image larger than 1000x1000
Ig = Img(1:250,1:250);
n = 100000;
tic
for ii=1:n
    M1 = sum(sum(Ig))/numel(Ig);
end
toc
disp('  for sum(sum(Ig))/numel(Ig) 250x250') 

tic;
for ii=1:n
    M2 = mean2(Ig);
end
toc
disp('  for mean2(Ig) 250x250') 

tic;
for ii=1:n
    M3 = sum(Ig(:),'double')/numel(Ig);
end
toc
disp('  for sum(Ig(:),''double'')/numel(Ig) 250x250') 

tic;
for ii=1:n
    M4 = sum(Ig(:))/numel(Ig);
end
toc
disp('  for sum(Ig(:))/numel(Ig) 250x250')
clear M1 M2 M3 M4 

Ig = Img(1:500,1:500);

tic
for ii=1:n
    M1 = sum(sum(Ig))/numel(Ig);
end
toc
disp('  for sum(sum(Ig))/numel(Ig) 500x500') 

tic
for ii=1:n
    M2 = mean2(Ig);
end
toc
disp('  for mean2(Ig) 500x500') 

tic
for ii=1:n
    M3 = sum(Ig(:),'double')/numel(Ig);
end
toc
disp('  for sum(Ig(:),''double'')/numel(Ig) 500x500') 

tic
for ii=1:n
    M4 = sum(Ig(:))/numel(Ig);
end
toc
disp('  for sum(Ig(:))/numel(Ig) 500x500')

Ig = Img(1:1000,1:1000);
tic
for ii=1:n
    M1 = sum(sum(Ig))/numel(Ig);
end
toc
disp('  for sum(sum(Ig))/numel(Ig) 1000x1000') 

tic
for ii=1:n
    M2 = mean2(Ig);
end
toc
disp('  for mean2(Ig) 1000x1000') 

tic
for ii=1:n
    M3 = sum(Ig(:),'double')/numel(Ig);
end
toc
disp('  for sum(Ig(:),''double'')/numel(Ig) 1000x1000') 

tic
for ii=1:n
    M4 = sum(Ig(:))/numel(Ig);
end
toc
disp('  for sum(Ig(:))/numel(Ig) 1000x1000')

and the results are :

Elapsed time is 2.115313 seconds. for sum(sum(Ig))/numel(Ig) 250x250

Elapsed time is 5.753932 seconds. for mean2(Ig) 250x250

Elapsed time is 5.626373 seconds. for sum(Ig(:),'double')/numel(Ig) 250x250

Elapsed time is 5.425690 seconds. for sum(Ig(:))/numel(Ig) 250x250

Elapsed time is 6.349700 seconds. for sum(sum(Ig))/numel(Ig) 500x500

Elapsed time is 6.810287 seconds. for mean2(Ig) 500x500

Elapsed time is 6.840604 seconds. for sum(Ig(:),'double')/numel(Ig) 500x500

Elapsed time is 6.455498 seconds. for sum(Ig(:))/numel(Ig) 500x500

Elapsed time is 23.772897 seconds. for sum(sum(Ig))/numel(Ig) 1000x1000

Elapsed time is 22.071418 seconds. for mean2(Ig) 1000x1000

Elapsed time is 21.862069 seconds. for sum(Ig(:),'double')/numel(Ig) 1000x1000

Elapsed time is 21.498514 seconds. for sum(Ig(:))/numel(Ig) 1000x1000

user3667217
  • 2,172
  • 2
  • 17
  • 29
  • I'm not sure if I extended this invitation to you, but drop by our MATLAB and Octave chat room if you have time :) I see you've been answering questions here very often. We're there pretty often to talk about things and to connect. Totally up to you though. If not, no worries. Good luck! http://chat.stackoverflow.com/rooms/81987/matlab-and-octave – rayryeng Sep 14 '15 at 18:49
  • 2
    Thanks for the invite :) I'll surely drop by sometimes ! I've learned a lot from your guys ! – user3667217 Sep 14 '15 at 18:53