4
votes

I am having issues using arrayfun in MATLAB using GPU processing. I have simplified my situation below.

I have 4 large matrices (video data as (x,y,t)). Ill use random for this example.

A = gpuArray(rand(10,10,100));
B = gpuArray(rand(10,10,100));
C = gpuArray(rand(10,10,100));
D = gpuArray(rand(10,10,100));

I wish to take each pixel of each matrix;(1,1,1) then (2,1,1) etc; and perform the least squares calculation (values are examples)

X = [10 10 ; 20 20 ; 30 30 ; 40 40]\[A;B;C;D];

Performing this as a for loop takes too long for my data. Since I want to perform a function on each element individually I thought using the GPU would be the way to go.

To do this I created the function

function [x] = GPUTestFun (A,B,C,D)
X = [10 10 ; 20 20 ; 30 30 ; 40 40]\[A;B;C;D];
end

Which I then call with arrayfun (I don't think matlab has GPU support for leastsquares?)

[x] = arrayfun(@GPUTestFun,[A;B;C;D]);

My understanding is that this should take each element of the 4 matricies individually and perform the calculations.

The error I get it: Error using gpuArray/arrayfun Array concatenation is not supported. error at line: 4.

Line 4 being :

X = [10 10 ; 20 20 ; 30 30 ; 40 40]\[A;B;C;D];

Its obvious that the issue is that I am concatenating the matrix within the arrayfun. I have thought about what my options are and cant seem to see a solution. I considered concatenating the matrices before I call the function, however array fun will try to perform the function on every element, which now wont line up. I considered maybe solving the least squares manually rather than using \, however am hesitant to attempt this without checking if I've missed an easier solution first.

I also realise the output X will probably need tweaking since the single calculation produces 2 outputs, so will probably need to separate these so my outputs are the same size as my inputs. This isn't the current issue however.

Any help will be greatly appreciated.

Thanks Jordan

EDIT: Working CPU code:

A = (rand(10,10,100));
B = (rand(10,10,100));
C = (rand(10,10,100));
D = (rand(10,10,100));

[X1,X2] = arrayfun(@GPUTestFun,A,B,C,D);

Function:

function [X1,X2] = GPUTestFun (A,B,C,D)
    [X] = [10 11 ; 20 8 ; 30 30 ; 40 30]\[A;B;C;D];
    X1 = X(1);
    X2 = X(2);
end
1
I'm not quite clear what you're trying to achieve here - could you show a working CPU version of the code? Your original line calculating X doesn't work even for CPU data... - Edric
Can you try to create a new matrix, E that consists of size(E)=size([A;B;C;D])? Additionally, the ` \ ` operator does A LOT OF THINGS. Some of them iterative and not ready for GPU computing, so most likely you are not going to get any advantage (even if it is possible to make ` \ ` in the GPU, eich i am not sure) - Ander Biguri
@Edric Thanks for your reply. You're right that it doesn't quite work for CPU. I have made a few changes and added the working CPU code. When I do convert to GPU I get the same issue. "Array concatenation is not supported." So I guess my issue can be summarized as: Is there a way to concatenate in arrayfun GPU processing? Or is there a way around it? - Jordan T
@Ander Biguri Thanks for suggestion. Do you mean create the matrix within the function? I don't think I can. I tried N = zeros(size(4,1)); Zeros (and presumably other matrix creates are not supported. also N(1) =1; N(2)=2...etc. But Array indexing is not supported either. If you meant create the matrix outside the function, then my issue is that arrayfun will try to perform the action on every element. so having a single matrix wont work. Perhaps where is a way to perform arrayfun down only one dimension? I think this might be a way around it, and pass 4x10000 matrix in. Ill play around more. - Jordan T

1 Answers

3
votes

In this case, you can simply recast the whole problem as a multiple-right-hand-side call to \, like so:

%# with A,B,C,D defined as per question
AA = [10 11 ; 20 8 ; 30 30 ; 40 30];
x  = [A(:)'; B(:)'; C(:)'; D(:)'];
x1x2 = AA \ x;
X1 = reshape(x1x2(1,:), size(A));
X2 = reshape(x1x2(2,:), size(A));

This will work on the GPU.