使用 MATLAB 的 GPU 功能计算 sum(a.*exp(b.*c),1) 的有效方法
Efficient way to calculate sum(a.*exp(b.*c),1) using MATLAB's GPU functionality
我有 GPU 加速的 MATLAB 代码,其 80%-90% 的时间用于计算
sum(a.*exp(b.*c),1)
其中
size(a) = [n 1]
size(b) = [n 1]
size(c) = [1 m]
n可以选择任意大(在内存限制内)
5000 < 米 < 20000
我想通过使用 gpuArrays(双精度大约 17 倍)来加快速度。
基准测试
使用 MATLAB 2018b 和 NVIDIA P100 GPU,我有 运行 以下脚本旨在找到 n 的最佳大小。它表明与使用双精度的 CPU(双路英特尔至强 E5-2650v2)相比,我实现了 17 倍的加速。我可以通过做一些更高级的事情来改进这一点吗,比如使用 GPU 编码器,甚至如下所述的共享内存或纹理内存?
https://uk.mathworks.com/help/parallel-computing/examples/accessing-advanced-cuda-features-using-mex.html
%% Optimisation MWE
nVec = 1000:1000:60000; % Vector of candidate n values
m = 5000;
f1 = figure(1);
ax(1) = subplot(3,1,1);
ax(2) = subplot(3,1,2);
ax(3) = subplot(3,1,3);
% Preallocate time outputs
t = nan(length(nVec),3);
speedupGPU = nan(length(nVec),2);
% Loop over candidate n values
for n = 1:length(nVec)
%% CPU code
a = rand(nVec(n),1);
b = rand(nVec(n),1);
c = rand(1,m);
f1 = @() sum(a.*exp(b.*c),1);
t(n,1) = timeit(f1,1);
%% GPU code (double precision)
a = gpuArray(a);
b = gpuArray(b);
c = gpuArray(c);
f2 = @() sum(a.*exp(b.*c),1);
t(n,2) = gputimeit(f2);
%% GPU code (single precision)
a = single(a);
b = single(b);
c = single(c);
f3 = @() sum(a.*exp(b.*c),1);
t(n,3) = gputimeit(f3);
%% Calculate speedup
speedupGPU(n,1) = t(n,1)/t(n,2);
speedupGPU(n,2) = t(n,1)/t(n,3);
%% Plot
plot(ax(1),nVec,t,'.-') % Plot compute time
plot(ax(2),nVec,t./nVec(:),'.-') % Plot normalised compute time
plot(ax(3),nVec,speedupGPU,'.-') % Plot Speedup
%% Label plots
xlabel(ax(1),'n')
ylabel(ax(1),'Time')
legend(ax(1),'CPU','GPU double','GPU single')
xlabel(ax(2),'n')
ylabel(ax(2),'Normalised Time')
legend(ax(2),'CPU','GPU double','GPU single')
xlabel(ax(3),'n')
ylabel(ax(3),'Speedup')
legend(ax(3),'CPU/GPU double','CPU/GPU single')
drawnow
end
结果如下图(上图:随着n的增加执行时间(越小越好),中图:n归一化后的执行时间(越小越好),下图:相对于CPU的加速(越大更好)):
我知道它可能不会给你你正在寻找的加速,但使这段代码更高效的一种方法是通过使用矩阵乘法来摆脱 sum
:
sum(a.*exp(b.*c),1) --> a.'*exp(b.*c)
在我的系统上,这导致加速从 ~10 增加到 ~15。
我还应该提到,对于 n
的最低值,我通过将数组乘法 (.*
) 替换为矩阵乘法 (*
,获得了大约 20 倍的加速): a.'*exp(b.*c) --> a.'*exp(b*c)
.
在 R2019b、Win10、GTX660 上测试。
我有 GPU 加速的 MATLAB 代码,其 80%-90% 的时间用于计算
sum(a.*exp(b.*c),1)
其中
size(a) = [n 1]
size(b) = [n 1]
size(c) = [1 m]
n可以选择任意大(在内存限制内)
5000 < 米 < 20000
我想通过使用 gpuArrays(双精度大约 17 倍)来加快速度。
基准测试
使用 MATLAB 2018b 和 NVIDIA P100 GPU,我有 运行 以下脚本旨在找到 n 的最佳大小。它表明与使用双精度的 CPU(双路英特尔至强 E5-2650v2)相比,我实现了 17 倍的加速。我可以通过做一些更高级的事情来改进这一点吗,比如使用 GPU 编码器,甚至如下所述的共享内存或纹理内存? https://uk.mathworks.com/help/parallel-computing/examples/accessing-advanced-cuda-features-using-mex.html
%% Optimisation MWE
nVec = 1000:1000:60000; % Vector of candidate n values
m = 5000;
f1 = figure(1);
ax(1) = subplot(3,1,1);
ax(2) = subplot(3,1,2);
ax(3) = subplot(3,1,3);
% Preallocate time outputs
t = nan(length(nVec),3);
speedupGPU = nan(length(nVec),2);
% Loop over candidate n values
for n = 1:length(nVec)
%% CPU code
a = rand(nVec(n),1);
b = rand(nVec(n),1);
c = rand(1,m);
f1 = @() sum(a.*exp(b.*c),1);
t(n,1) = timeit(f1,1);
%% GPU code (double precision)
a = gpuArray(a);
b = gpuArray(b);
c = gpuArray(c);
f2 = @() sum(a.*exp(b.*c),1);
t(n,2) = gputimeit(f2);
%% GPU code (single precision)
a = single(a);
b = single(b);
c = single(c);
f3 = @() sum(a.*exp(b.*c),1);
t(n,3) = gputimeit(f3);
%% Calculate speedup
speedupGPU(n,1) = t(n,1)/t(n,2);
speedupGPU(n,2) = t(n,1)/t(n,3);
%% Plot
plot(ax(1),nVec,t,'.-') % Plot compute time
plot(ax(2),nVec,t./nVec(:),'.-') % Plot normalised compute time
plot(ax(3),nVec,speedupGPU,'.-') % Plot Speedup
%% Label plots
xlabel(ax(1),'n')
ylabel(ax(1),'Time')
legend(ax(1),'CPU','GPU double','GPU single')
xlabel(ax(2),'n')
ylabel(ax(2),'Normalised Time')
legend(ax(2),'CPU','GPU double','GPU single')
xlabel(ax(3),'n')
ylabel(ax(3),'Speedup')
legend(ax(3),'CPU/GPU double','CPU/GPU single')
drawnow
end
结果如下图(上图:随着n的增加执行时间(越小越好),中图:n归一化后的执行时间(越小越好),下图:相对于CPU的加速(越大更好)):
我知道它可能不会给你你正在寻找的加速,但使这段代码更高效的一种方法是通过使用矩阵乘法来摆脱 sum
:
sum(a.*exp(b.*c),1) --> a.'*exp(b.*c)
在我的系统上,这导致加速从 ~10 增加到 ~15。
我还应该提到,对于 n
的最低值,我通过将数组乘法 (.*
) 替换为矩阵乘法 (*
,获得了大约 20 倍的加速): a.'*exp(b.*c) --> a.'*exp(b*c)
.
在 R2019b、Win10、GTX660 上测试。