How can I decrease the runtime for a function (using cellfun or parfor)?
5 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
I am trying to speed some code up. Right now each iteration takes about 6 seconds to run and over the course of many iterations the runtime drastically increases. I tried two different running strategies: using cellfun and parallelization. Will paralization ever be slower than using cellfun? I get hugely varying times for the parfor on different computers due to different number of cores. Will the cellfun be more consistent (but slower) across computers? Below is my code. Thank you in advance.
Here is the function call:
%First way
testOut = cellfun(@testDFF_trial, num2cell(fReflect, 2), num2cell(fReflect2, 2), ...
num2cell(fSom, 2), num2cell(ones(size(fReflect, 1), 1) .* numFrames), 'UniformOutput', false);
%Second way
parfor numCell = 1:size(fReflect, 1)
dffAll{numCell} = testDFF(fReflect, fReflect2, fSom, numFrames, numCell); %slightly altered function for parfor compatibility
end
Here is the function that I am trying to speed up:
function dffTest = testDFF(fReflect, fReflect2, fSom, numFrames)
stepSize = 1;
windowSize = 900 / 2; %12
startLoc = 451; %20
endLoc = numFrames + 450; %80
%Gets the starting numbers
usedRange = startLoc:stepSize:endLoc;
%Gets the index that matter for each window
aOut = arrayfun(@(a, window) a-window:a+window, usedRange, ones(size(fReflect(usedRange))) .* windowSize, 'UniformOutput', false);
aOut2 = arrayfun(@(a, window) a-window:a+window, usedRange, ones(size(fReflect2(usedRange))) .* windowSize, 'UniformOutput', false);
%Makes ones array for later input
onesAll = (ones(1, length(fReflect)) .* fReflect);
onesAll2 = (ones(1, length(fReflect2)) .* fReflect2);
%Gets the values within each index
myfun = @(input, index) input(index);
datOut = cellfun(@(index) myfun(onesAll, index), aOut, 'UniformOutput', false);
datOut2 = cellfun(@(index) myfun(onesAll2, index), aOut2, 'UniformOutput', false);
%Find the 8th percentile
prcDat = cellfun(@prctile, datOut, num2cell(ones(1, length(datOut)) .* 8));
prcDat2 = cellfun(@prctile, datOut2, num2cell(ones(1, length(datOut2)) .* 8));
%Find the dff
dffFunct = @(rawF, prcF, baseline) (rawF - prcF) ./ baseline;
dffTest = arrayfun(dffFunct, fSom, prcDat, prcDat2);
tInter = toc;
display(['Cell processed - time: ', num2str(tInter / 60, '%0.2f')]);
end
4 comentarios
Steven Lord
el 12 de Mzo. de 2024
FYI, another tool to add to your programming arsenal is the Profiler. This can help you understand what the most expensive location or segment of your code is. Using that you can also experiment with different approaches to determine if a change is better, worse, or the same in terms of performance. [That reminds me of my last eye exam ;)]
Respuesta aceptada
Voss
el 11 de Mzo. de 2024
Editada: Voss
el 12 de Mzo. de 2024
Before worrying about cellfun vs parfor to call the function, try to make the function itself more efficient.
Compare the function testDFF_modified below with the original testDFF.
I don't know what typical inputs to the function are, but with these made-up inputs:
fReflect = rand(1,1000);
fReflect2 = rand(1,1100);
fSom = rand(1,50);
numFrames = 50;
The result is the same:
out1 = testDFF(fReflect, fReflect2, fSom, numFrames);
out2 = testDFF_modified(fReflect, fReflect2, fSom, numFrames);
isequal(out1,out2)
And the modified function is about 3-4 times faster:
t1 = timeit(@()testDFF(fReflect, fReflect2, fSom, numFrames));
t2 = timeit(@()testDFF_modified(fReflect, fReflect2, fSom, numFrames));
fprintf('old: %5.3f ms\nnew: %5.3f ms\n',t1*1000,t2*1000);
function dffTest = testDFF_modified(fReflect, fReflect2, fSom, numFrames)
stepSize = 1;
windowSize = 900 / 2; %12
startLoc = 451; %20
endLoc = numFrames + 450; %80
%Gets the starting numbers
usedRange = startLoc:stepSize:endLoc;
% matrix of indices:
idx = usedRange+(-windowSize:windowSize).';
% simple indexing, and taking advantage of the fact that prctile
% given a matrix operates by column:
dffTest = (fSom-prctile(fReflect(idx),8))./prctile(fReflect2(idx),8);
end
function dffTest = testDFF(fReflect, fReflect2, fSom, numFrames)
stepSize = 1;
windowSize = 900 / 2; %12
startLoc = 451; %20
endLoc = numFrames + 450; %80
%Gets the starting numbers
usedRange = startLoc:stepSize:endLoc;
%Gets the index that matter for each window
aOut = arrayfun(@(a, window) a-window:a+window, usedRange, ones(size(fReflect(usedRange))) .* windowSize, 'UniformOutput', false);
aOut2 = arrayfun(@(a, window) a-window:a+window, usedRange, ones(size(fReflect2(usedRange))) .* windowSize, 'UniformOutput', false);
%Makes ones array for later input
onesAll = (ones(1, length(fReflect)) .* fReflect);
onesAll2 = (ones(1, length(fReflect2)) .* fReflect2);
%Gets the values within each index
myfun = @(input, index) input(index);
datOut = cellfun(@(index) myfun(onesAll, index), aOut, 'UniformOutput', false);
datOut2 = cellfun(@(index) myfun(onesAll2, index), aOut2, 'UniformOutput', false);
%Find the 8th percentile
prcDat = cellfun(@prctile, datOut, num2cell(ones(1, length(datOut)) .* 8));
prcDat2 = cellfun(@prctile, datOut2, num2cell(ones(1, length(datOut2)) .* 8));
%Find the dff
dffFunct = @(rawF, prcF, baseline) (rawF - prcF) ./ baseline;
dffTest = arrayfun(dffFunct, fSom, prcDat, prcDat2);
% tInter = toc;
% display(['Cell processed - time: ', num2str(tInter / 60, '%0.2f')]);
end
6 comentarios
Más respuestas (0)
Ver también
Categorías
Más información sobre Loops and Conditional Statements en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!