Vectorize 2D 3D matrix product for speedup - performance

I have the following setup
matrix2D_1 = zeros(40,191);
matrix2D_2 = zeros(40,191);
matrix3D_1 = zeros(40,191,191);
for j = 1:40
for jw = 1:191
matrix2D_1(j,jw) = sum(squeeze(matrix3D_1(j,jw,:))'*matrix2D_2' );
end
end
so I want the sum of all products of the 3rd dimension of the 3D matrix with the elements of the of the first 2D matrix which is the matrix product in
squeeze(matrix3D_1(j,jw,:))'*matrix2D_2'
The sum of these results shall then be stored in the first 2D matrix.
As I have to run this in a large loop this takes the most time in my code. I cant get my head around it how to vectorize it in a more elegant way. Any faster solution would be higly appreciated....

Yup! Use matrix-multiplication and reshape magic -
M = size(matrix2D_1,2);
matrix2D_1 = reshape(sum(reshape(matrix3D_1,[],M)*matrix2D_2.',2),[],M)
Or sum and then do matrix-multiplication -
matrix2D_1 = reshape(reshape(matrix3D_1,[],M)*sum(matrix2D_2,1).',[],M)

Related

Vectorize code in MATLAB

How to vectorize this code in MATLAB?
If possible, I wish matrix B to be a sparse matrix.
%% Y is a matrix l*n
%% X is a matrix k*n
B = [];
for i=1:l
for j=1:n
temp1 = zeros(1,n*l);
temp1((i-1)*n+j) = -1;
temp2 = zeros(1,l*k);
temp2((i-1)*k+1:i*k) = (-Y(i,j)).*(X(:,j)');
B = [B;[temp1,temp2]];
end
end
I don't know how to vectorize this code, please help! Thanks!
Making use of bsxfun for masking and vectorized calculations of the elementwise multiplications, here's a vectorized approach -
%// Create left part of the output that is basically an identity matrix
parte1 = -eye(n*l);
%// Setup right part of output
parte2 = zeros(n*l,l*k);
%// Mask to set elements from the calculations of (-Y(i,j)).*(X(:,j)')
M = bsxfun(#eq,reshape(repmat(1:l,n,1),[],1),reshape(repmat(1:l,k,1),1,[]));
%// OR concisely : M = kron(eye(l),ones(n,k))==1
%// Perform vectorized calculations of (-Y(i,j)).*(X(:,j)') and set those
%// into second part at masked places
parte2(M) = -bsxfun(#times,permute(X,[2,1,3]),permute(Y,[2,3,1]));
%// Finally concatenate those parts for final output
out = [parte1,parte2];

Vectorization for array multiplication

I have an 3d array U, and a 2d matrix A. I want to do the multiplication like following way. How can I vectorize my code? The loop is too slow, of course.
for j=1:N
for k=1:N
UU(:,j,k)=A*U(:,j,k);
end
end
Reshape U to 2D and perform the matrix-multiplication, thus reducing the first axis/dimension of U with A's last axis to give us a 2D array. Finally, reshape back to 3D for the final result, like so -
[m1,n1] = size(A);
[~,m2,n2] = size(U);
out = reshape(A*reshape(U,[n1,m2*n2]),[m1,m2,n2])
Depending on the size of your matrices, you might find that eliminating both loops chews up a lot of memory, and that removing just the loop over the columns is sufficient,
for k = 1:N
UU(:,:,k) = A*U(:,:,k);
end

How can I perform this array-slicing and multiplication operation more efficiently?

I used the last two dimensions of this 3D matrix as a 2D matrix. So I just wanna multiply the 2D matrix from the result of Matrix1(i,:,:) (which i-by-i) with the vector Matrix2(i,:).') (which is 1-by-i).
The only way I could do that was using an auxiliary matrix that picked up all the numbers from the 2 dimensions from the 3D matrix:
matrixAux(:,:) = Matrix1(1,:,:)
and then I did the multiplication:
matrixAux * (Matrix2(i,:).')
and it worked. However, this is slow because I need to copy all the 3D matrix to a lot of auxiliary matrices, and I need to speed up my code because I'm doing the same operation many times.
How can I do that more efficiently, without having to copy the matrix?
Approach I: bsxfun Multiplication
One approach would be to use the output of bsxfun with #times whose values you can use instead of calculating the matrix multiplication results in a loop -
sum(bsxfun(#times,Matrix1,permute(Matrix2,[1 3 2])),3).'
Example
As an example, let's suppose Matrix1 and Matrix2 are defined like this -
nrows = 3;
p = 6;
ncols = 2;
Matrix1 = rand(nrows,ncols,p)
Matrix2 = rand(nrows,p)
Then, you have your loop like this -
for i = 1:size(Matrix1,1)
matrixAux(:,:) = Matrix1(i,:,:);
matrix_mult1 = matrixAux * (Matrix2(i,:).') %//'
end
So, instead of the loops, you can directly calculate the matrix multiplication results -
matrix_mult2 = sum(bsxfun(#times,Matrix1,permute(Matrix2,[1 3 2])),3).'
Thus, each column of matrix_mult2 would represent matrix_mult1 at each iteration of the loop, as the output of the codes would make it clearer -
matrix_mult1 =
0.7693
0.8690
matrix_mult1 =
1.0649
1.2574
matrix_mult1 =
1.2949
0.6222
matrix_mult2 =
0.7693 1.0649 1.2949
0.8690 1.2574 0.6222
Approach II: "Full" Matrix Multiplication
Now, this must be exciting! Well you can also leverage MATLAB's fast matrix multiplication to get your intermediate matrix multiplication results again without loops. If Matrix1 is nrows x p x ncols, you can reshape it to nrows*p x ncols and then perform matrix multiplication of it with Matrix2. Then, to get an equivalent of matrix_mult2, you need to select indices from the multiplication result. This is precisely achieved here -
%// Get size of Matrix1 to be used regularly inside the codes later on
[m1,n1,p1] = size(Matrix1);
%// Convert 3D Matrix1 to 2D and thus perform "full" matrix multiplication
fmult = reshape(Matrix1,m1*n1,p1)*Matrix2'; %//'
%// Get valid indices
ind = bsxfun(#plus,[1:m1:size(fmult,1)]',[0:nrows-1]*(size(fmult,1)+1)); %//'
%// Get values from the full matrix multiplication result
matrix_mult3 = fmult(ind);
Here, matrix_mult3 must be the same as matrix_mult2.
Observations: Since we are not using all the values calculated from the full matrix multiplication, rather indexing into it and selecting few of its elements, as such this approach performs better than the other approaches under certain circumstances. This approach seems to be the best one when nrows is a small value as we would be using more number of elements from the full matrix multiplication output in that case.
Benchmark Results
Two cases were tested against the three approaches and the test results seem to support our hypotheses discussed earlier.
Case 1
Matrix 1 as 400 x 400 x 400, the runtimes are -
--------------- With Loops
Elapsed time is 2.253536 seconds.
--------------- With BSXFUN
Elapsed time is 0.910104 seconds.
--------------- With Full Matrix Multiplication
Elapsed time is 4.361342 seconds.
Case 2
Matrix 1 as 40 x 2000 x 2000, the runtimes are -
--------------- With Loops
Elapsed time is 5.402487 seconds.
--------------- With BSXFUN
Elapsed time is 2.585860 seconds.
--------------- With Full Matrix Multiplication
Elapsed time is 1.516682 seconds.

Storing CWT of each row of image in a Cell

I want to compute the morlet wavelet of each row of 480X480 image. I have to save the output of the transform of each row which is a 2d array(matrix).
Then i will be taking the average all 480 2d matrices i have to get one final plot of the average.
clc;
close all;
clear all;
I=imread('lena.jpg');
J=rgb2gray(I);
%K=J(1:480)
%coefs = cwt(K,1:128,'morl','plot');
coefs = cell(480,1);
for i = 1:480
K=J(i,:);
coefs(i) = cwt(K,1:128,'morl');
end
Here i want to take the avg of the 480 coeff matrices. Here am getting the error
Conversion to cell from double is not possible.
Error in soilwave (line 12) coefs(i) = cwt(K,1:128,'morl');
Could anyone suggest a better method or tweaks to this.
Cell arrays are practical if you need to store elements that have inconsistent format or dimensions, but for what you are trying to do, a 3D array is easier to work with. Here is what I would do:
Preassign a 3D array:
coefs = zeros(128, size(J, 2), size(J,1));
then compute and populate the stack:
for ii = 1:size(J, 1)
K=J(ii,:);
coefs(:,:,ii) = cwt(K,1:128,'morl');
end
Finally, compute the mean along the third dimension:
MeanCoeff=mean(coefs, 3);

Male/Female Classification with Matlab- About Finding Mean Image

I am working on a project which is about pattern (male/female)classification with matlab.I have a problem, I need your help, please.
My program should find mean images of datasets. First dataset is women,second dataset is men. So first mean image has to look like a woman and second a man.I have different datasets which all have format of jpeg. I am trying different datasets for my program to check if it is working but when I use different datasets I can not see true mean images all the time, for ex:
They are mean images from a dataset:
But when I use another dataset my mean images are like this, they have no meanings, I mean they dont look like face:
What can be the reason for this? I should work with different datasets. Please help.
`
filenamesA = dir(fullfile(pathfora, '*.jpg'));
Train_NumberA = numel(filenamesA);
%%%%%%%%%%%%%%%%%%%% Finding Image Vectors for A
imagesA= [];
for k = 1 : Train_NumberA
str = int2str(k);
str= strcat(str);
str = strcat('\',str,'b','.jpg');
str = strcat(pathfora,str);
imgA = imread(str);
imgA = rgb2gray(imgA);
[irowA icolA] = size(imgA);
tempA = reshape(imgA',irowA*icolA,1); % Reshaping 2D images into 1D image vectors
imagesA = [imagesA tempA]; % 'imagesA' grows after each turn
imagesA=double(imagesA);
end`
`%%%%%%%%%%%%%%%%%%%%%%%% Calculate the MEAN IMAGE VECTOR for A
mean_vectorA= mean(imagesA,2); % Computing the average vector m = (1/P)*sum(Tj's) (j = 1 : P)
mean_imageA= reshape(mean_vectorA,irowA,icolA); % Average matrix of training set A
meanimgA=mat2gray(mean_imageA);
figure(1);
imshow(rot90(meanimgA,3));`
-------------------------------------And same for dataset B (male)
You could use a 3D matrix to store the images. I also cleaned up the code a bit. Not tested.
filenamesA = dir(fullfile(pathfora, '*.jpg'));
Train_NumberA = numel(filenamesA);
imagesA = [];
for k = 1:Train_NumberA
imgA = imread(strcat(pathfora, '\', int2str(k), 'b', '.jpg'));
imgA = rgb2gray(imgA);
imagesA = cat(3, imagesA, imgA);
end
double command moved out of loop.
imagesA = double(imagesA);
Calculate the mean over the 3rd dimension of the imagesA matrix to get the mean 2D image.
meanimage_A = mean(imagesA, 3);
Convert to grayscale image.
meanimgA = mat2gray(meanimage_A);
I think rot90 is not needed here...
figure(1);
imshow(meanimgA, 3);
Use a 3D array or cell array of images instead of reshaping 2D images into single rows of a matrix. The reshaping is unnecessary and can only add bugs.
If all your images are the same size, you can use a multidimensional array: Matlab documentation on multidimensional arrays
Otherwise, use a cell array: Matlab documentation on cell arrays

Resources