5 views (last 30 days)

Hi there,

Here goes a piece of testing code, yet arrayfun runs more slowly. Any thoughts? Many thanks.

function Test_GPU1()

EP = gpuArray(eps*ones(10000, 1, 'single'));

ONE = gpuArray(ones(10000, 1, 'single'));

ZERO = gpuArray(zeros(10000, 1, 'single'));

Cur_FF_Output = gpuArray(0.5*ones(10000, 1, 'single'));

Cur_Desired_Output = gpuArray(0.5*ones(10000, 1, 'single'));

for iter = 1:1000

% In output layer, Cur_Delta = Del(C)/Del(z) = Del(C)/Del(a) * Del(a)/Del(z)

% [~, Cur_Delta0] = Cost_Function_GPU(Cur_FF_Output, Cur_Desired_Output, Hyper_Para);

temp00 = Cur_FF_Output + eps;

temp11 = log(temp00);

temp22 = log(1-Cur_FF_Output+eps);

temp33 = Cur_Desired_Output.*temp11;

temp44 = 1-Cur_FF_Output.*temp22;

Cur_Delta = Cur_FF_Output-Cur_Desired_Output;

Cost = 0-sum(temp33+temp44);

temp00 = arrayfun(@plus, Cur_FF_Output, EP);

temp11 = arrayfun(@log, temp00);

temp22 = arrayfun(@log, arrayfun(@minus, ONE, arrayfun(@plus, Cur_FF_Output, EP)));

temp33 = arrayfun(@times, Cur_Desired_Output, temp11);

temp44 = arrayfun(@minus, ONE, arrayfun(@times, Cur_FF_Output, temp22));

Cur_Delta = arrayfun(@minus, Cur_FF_Output, Cur_Desired_Output);

Cost = arrayfun(@minus, ZERO, sum(temp33+temp44));

end

end

Joss Knight
on 28 May 2019

You are misunderstanding the use of arrayfun for gpuArray. Combine all those operations into a single function.

temp00 = arrayfun(@plus, Cur_FF_Output, EP);

temp11 = arrayfun(@log, temp00);

temp22 = arrayfun(@log, arrayfun(@minus, ONE, arrayfun(@plus, Cur_FF_Output, EP)));

temp33 = arrayfun(@times, Cur_Desired_Output, temp11);

temp44 = arrayfun(@minus, ONE, arrayfun(@times, Cur_FF_Output, temp22));

Cur_Delta = arrayfun(@minus, Cur_FF_Output, Cur_Desired_Output);

Cost = arrayfun(@minus, ZERO, sum(temp33+temp44));

becomes

function Cur_Delta = stuff(Cur_FF_Output, Cur_Desired_Output, EP)

temp00 = Cur_FF_Output + EP;

temp11 = log(temp00);

temp22 = log(1 - (Cur_FF_Output + EP));

temp33 = Cur_Desired_Output .* temp11;

temp44 = 1 - (Cur_FF_Output .* temp22);

Cur_Delta = Cur_FF_Output - Cur_Desired_Output;

end

Cur_Delta = arrayfun(@stuff, Cur_FF_Output, Cur_Desired_Output, EP);

Obviously, this can be extremely simplified. I've made a start, by removing the unnecessary ONE and ZERO variables.

After this, question whether you really need arrayfun, or should just call this function directly? MATLAB uses some clever optimisations that, for most sequences of element-wise operations, make using arrayfun unnecessary.

Joss Knight
on 1 Jun 2019

Jan
on 28 May 2019

Edited: Jan
on 28 May 2019

Of course arrayfun has a certain overhead. It is expected to run slower than calling the operators directly with arrays as inputs. In addition, in

Cur_FF_Output + eps

the second operand is a scalar, while in

arrayfun(@plus, Cur_FF_Output, EP)

Matlab has to process a vector. Addressing the elements of an array needs to access memory using a loop. Accessing a scalar is much cheaper.

What is the purpose of:

arrayfun(@minus, ZERO, sum(temp33+temp44))

? This is faster:

-sum(temp33+temp44)

Joss Knight
on 29 May 2019

Jan
on 31 May 2019

Even arrayfun(@minus, 0, sum(temp33+temp44)) is too complicated compared to

-sum(temp33+temp44)

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!
## 1 Comment

## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/464361-why-is-arrayfun-for-gpu-slower-than-normal-operations#comment_709543

⋮## Direct link to this comment

https://ch.mathworks.com/matlabcentral/answers/464361-why-is-arrayfun-for-gpu-slower-than-normal-operations#comment_709543

Sign in to comment.