Matlab中的矢量化代码比for循环运行得快得多(有关Octave的具体结果,请参阅Parallel computing in Octave on a single machine -- package and example)
话虽如此,有没有办法对Matlab或Octave中显示的代码进行矢量化?
x = -2:0.01:2;
y = -2:0.01:2;
[xx,yy] = meshgrid(x,y);
z = sin(xx.^2-yy.^2);
答案 0 :(得分:6)
正如@Jonas所指出的,MATLAB中有一些选项可供选择,其效果最好取决于以下几个因素:
现在MATLAB中的许多元素操作都是多线程的 - 在这种情况下,使用PARFOR通常没什么意义(除非你有多台机器和MATLAB Distributed Computing Server许可证可用)。
真正需要多台机器内存的巨大问题可以从distributed arrays中受益。
如果您的问题适合GPU计算的大小和类型,使用GPU可以击败单台机器的多线程性能。矢量化代码往往最适合通过GPU进行并行化。例如,您可以使用Parallel Computing Toolbox中的gpuArray
编写代码,并将所有内容都运行在GPU上。
x = parallel.gpu.GPUArray.colon(-2,0.01,2);
y = x;
[xx,yy] = meshgrid(x,y); % xx and yy are on the GPU
z = arrayfun( @(u, v) sin(u.*u-v.*v), xx, yy );
我将最后一行转换为arrayfun
调用,因为使用gpuArray
时效率更高。
答案 1 :(得分:5)
在Matlab中,将内置向量化函数用于多线程的唯一方法是等待MathWorks implement them。
或者,您可以将矢量化计算编写为循环,并使用parfor
并行运行它们。
最后,许多函数都是GPU-enabled,因此,通过访问并行处理工具箱,您可以并行化这些操作,包括减法和元素功率。
答案 2 :(得分:5)
meshgrid
和ndgrid
如果您仍然有兴趣找到一个矢量化实现来更快地在问题中使用基于meshgrid
的代码,那么让我建议一个带有bsxfun
的矢量化方法和它的GPU移植版本。我坚信人们必须将vectorization with GPUs
作为加速MATLAB
代码的有希望的选择。使用meshgrid
或ndgrid
并且其输出将通过某些元素操作进行操作的代码设置了将bsxfun
用于这些代码的完美基础。除此之外,使用带有bsxfun
的GPU,可以独立使用数百个CUDA核心的元素,使其非常适合GPU实现。
针对您的具体问题,输入为 -
x = -2:0.01:2;
y = -2:0.01:2;
接下来,你有 -
[xx,yy] = meshgrid(x,y);
z = sin(xx.^2-yy.^2);
使用bsxfun
,这将成为一个单行 -
z = sin(bsxfun(@minus,x.^2,y.^2.'));
GPU基准测试提示取自Measure and Improve GPU Performance。
%// Warm up GPU call with insignificant small scalar inputs
temp1 = sin_sqdiff_vect2(0,0);
N_arr = [50 100 200 500 1000 2000 3000]; %// array elements for N (datasize)
timeall = zeros(3,numel(N_arr));
for k = 1:numel(N_arr)
N = N_arr(k);
x = linspace(-20,20,N);
y = linspace(-20,20,N);
f = @() sin_sqdiff_org(x,y);%// Original CPU code
timeall(1,k) = timeit(f);
clear f
f = @() sin_sqdiff_vect1(x,y);%// Vectorized CPU code
timeall(2,k) = timeit(f);
clear f
f = @() sin_sqdiff_vect2(x,y);%// Vectorized GPU(GTX 750Ti) code
timeall(3,k) = gputimeit(f);
clear f
end
%// Display benchmark results
figure,hold on, grid on
plot(N_arr,timeall(1,:),'-b.')
plot(N_arr,timeall(2,:),'-ro')
plot(N_arr,timeall(3,:),'-kx')
legend('Original CPU','Vectorized CPU','Vectorized GPU (GTX 750 Ti)')
xlabel('Datasize (N) ->'),ylabel('Time(sec) ->')
相关功能
%// Original code
function z = sin_sqdiff_org(x,y)
[xx,yy] = meshgrid(x,y);
z = sin(xx.^2-yy.^2);
return;
%// Vectorized CPU code
function z = sin_sqdiff_vect1(x,y)
z = sin(bsxfun(@minus,x.^2,y.^2.')); %//'
return;
%// Vectorized GPU code
function z = sin_sqdiff_vect2(x,y)
gx = gpuArray(x);
gy = gpuArray(y);
gz = sin(bsxfun(@minus,gx.^2,gy.^2.')); %//'
z = gather(gz);
return;
结果显示,使用GPU的矢量化方法显示出良好的性能改进,对照矢量化的CPU代码约为4.3x
,而对原始代码约为6x
。请记住,GPU必须克服设置所需的最小开销,因此至少需要一个相当大的输入才能看到改进。希望人们能够探索更多的vectorization with GPUs
,因为它不够强调!