Sparse and binary mask
Show older comments
I am working on saving computations and speeding up my Matlab code. Here's what I do Perform thresholding on an image and make most of its components as zero run it inside a loop with element by element multiplication with another matrix(full matrix) of the same size
Here is a detailed version of what I am doing
CASE I:When I dont avoid multiplication with zeros
matrix(matrix<threshold) = 0 ;
while the condition is true
matrix = matrix.*phase;
other lines of code ;
end
Result: From MATLAB profiler I see that matrix = matrix.*phase; takes 80 seconds
CASE II:When I avoid multiplication with zeros using SPARSE
matrix(matrix<threshold) = 0 ;
matrix = sparse(matrix);
while the condition is true
matrix = matrix.*phase;
other lines of code ;
end
Result: From MATLAB profiler I see that matrix = matrix.*phase takes 110 seconds
CASE III:When I avoid multiplication with zeros using a mask
matrix(matrix<threshold) = 0 ;
mask = matrix~=0;
while the condition is true
matrix(mask) = matrix(mask).*phase(mask);
other lines of code ;
end
Result: From MATLAB profiler I see that matrix = matrix.*phase takes 130 seconds
Why is my code slow if I try to avoid multiplications with zeros? Since the matrix after thresholding has 75% zeros my speed should be up by 75% as I am avoiding multiplication with zeros. But my time is increased Is there any other way to achieve avoiding multiplication with zeros and speeding up of the code?
MY PRIORITY IS TO SPEED UP THE CODE EXECUTION AND SAVE MUTLIPLICATIONS
4 Comments
Greg
on 14 Sep 2018
In case II, is phase also sparse, or full?
D_coder
on 14 Sep 2018
James Tursa
on 14 Sep 2018
What is the class of your image variable? Do you have a supported C compiler installed for a mex routine?
D_coder
on 14 Sep 2018
Accepted Answer
More Answers (2)
James Tursa
on 15 Sep 2018
Edited: James Tursa
on 15 Sep 2018
Try this simple C mex routine. It avoids the overhead you are creating with your sparse alternate stuff. Could maybe be improved further by multi-threading for large variables but it is currently not coded that way. (Caution, no input checking so it will crash MATLAB if not used properly)
/*
* File: times_threshold.c
*
* C = times_threshold(A,B,threshold) does
*
* C = A .* B but only where A > threshold (C = 0 in the other spots)
*
* A = full real double variable
* B = full real double variable (same size as A)
* C = full real double variable (same size as A)
* threshold = numeric scalar
*
* CAUTION: Bare bones with no argument checking! Will crash MATLAB if the
* inputs are not exactly as expected.
*/
#include "mex.h"
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
double *Apr, *Bpr, *Cpr;
double threshold;
mwSize n;
n = mxGetNumberOfElements(prhs[0]);
plhs[0] = mxCreateNumericArray(mxGetNumberOfDimensions(prhs[0]),
mxGetDimensions(prhs[0]),
mxDOUBLE_CLASS, mxREAL);
Apr = mxGetPr(prhs[0]);
Bpr = mxGetPr(prhs[1]);
Cpr = mxGetPr(plhs[0]);
threshold = mxGetScalar(prhs[2]);
while( n-- ) {
if( *Apr > threshold ) {
*Cpr = *Apr * *Bpr;
}
Apr++; Bpr++; Cpr++;
}
}
8 Comments
D_coder
on 15 Sep 2018
James Tursa
on 15 Sep 2018
>> mex times_threshold.c % <-- one time only
>> result = times_threshold(matrix,phase,threshold);
James Tursa
on 15 Sep 2018
Edited: James Tursa
on 15 Sep 2018
Simply this:
>> matrix = times_threshold(matrix,phase,threshold);
Unless you are asking how to modify matrix inplace?
For multi-threading, the source code would need to be rewritten.
D_coder
on 15 Sep 2018
Walter Roberson
on 15 Sep 2018
James's code combines the threshold operation for efficiency.
D_coder
on 15 Sep 2018
James Tursa
on 16 Sep 2018
What code are you using that is "more efficient" than the mex routine?
Walter Roberson
on 15 Sep 2018
matrix<threshold and matrix~=0 both generate values the same size as matrix. matrix(mask) and phase(mask) and matrix(mask).*phase(mask) generate values with the same number of entries as the number of non-zero values in mask. Those variables get stored in memory and have to be processed.
At the MATLAB level, matrix = matrix.*phase gets dispatched to the high performance libraries that operate on multiple cores. One temporary value the same size as matrix would be involved to hold the results.
The high performance libraries would probably be scheduling multiple multiplies simultaneously, perhaps with SIMD type instructions, possibly able to graduate one result per cycle, or whatever the maximum graduation rate is.
When you select part of the array it has to be conditionally moved to other memory locations, and then that array processed, and then selectively moved back. That involves memory bandwidth and comparisons and loops. Those cost, and the tradeoffs are potentially just not worth the effort compared to SIMD or vector instructions.
You would face different tradeoffs in your FPGA.
To reduce multiplications, it might be worth creating an explicit loop, along the lines of
new_matrix = zeros(size(matrix));
for idx = 1 : numel(matrix)
M = matrix(idx); P = phase(idx);
if M && P; new_matrix(idx) = M .* P;
end
If phase is certain to be non-zero then
new_matrix = zeros(size(matrix));
for idx = 1 : numel(matrix)
M = matrix(idx);
if M; new_matrix(idx) = M .* phase(idx);
end
9 Comments
D_coder
on 15 Sep 2018
Walter Roberson
on 15 Sep 2018
if M && P
is equivalent to
if (M ~= 0) && (P ~= 0)
except in the case where M might be Nan, in which case the explicit comparison will work but the one without will fail. Though if you are expecting nans you might want to test for them, as nan times anything is always nan. On the other hand, if nan are a possibility, that drives up the die area required for FPGA: processing NaN is relatively expensive.
D_coder
on 15 Sep 2018
Walter Roberson
on 15 Sep 2018
Correct,
if M
is equivalent to
if M ~=0
except in the case where M might have NaN. If NaN are present then
if M
will complain that NaN cannot be converted to logicals, but
if M ~= 0
will identify NaN as being non-zero.
D_coder
on 15 Sep 2018
D_coder
on 15 Sep 2018
Walter Roberson
on 15 Sep 2018
new_matrix = zeros(size(matrix));
for idx = 1 : numel(matrix)
M = matrix(idx);
if M ~= 0; new_matrix(idx) = M .* phase(idx); end
end
D_coder
on 15 Sep 2018
Categories
Find more on MATLAB in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!