【问题标题】:Vectorization for meshgrid in Matlab (or Octave)Matlab(或 Octave)中网格网格的矢量化
【发布时间】:2012-05-19 14:01:55
【问题描述】:

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);

【问题讨论】:

  • 查看刚刚添加的 bsxfun 实现,它还谈到了使用 GPU here

标签: matlab parallel-processing octave vectorization


【解决方案1】:

meshgridndgrid 的矢量化

如果您仍然有兴趣找到矢量化实现以使问题中基于meshgrid 的代码更快,让我建议使用bsxfun 的矢量化方法,它是GPU 移植版本。我坚信人们必须将vectorization with GPUs 视为加速MATLAB 代码的有希望的选择。使用meshgridndgrid 并且其输出将通过一些元素操作来操作的代码为在这些代码中使用bsxfun 设置了一个完美的基础。除此之外,将 GPU 与 bsxfun 结合使用,使其能够独立处理具有成百上千个可用 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,因为它的压力还不够!

【讨论】:

    【解决方案2】:

    正如@Jonas 所指出的,MATLAB 中有几个可用的选项,哪个效果最好取决于几个因素,例如:

    • 您的问题有多大
    • 您有多少台机器可用
    • 你有 GPU
    • MATLAB 是否已经对操作进行了多线程处理

    现在 MATLAB 中的许多元素操作都是多线程的 - 在这种情况下,使用 PARFOR 通常没有什么意义(除非您有多台机器和 MATLAB 分布式计算服务器许可证可用)。

    真正需要多台机器内存的大问题可以从distributed arrays 中受益。

    如果您的问题的大小和类型适合 GPU 计算,则使用 GPU 可以超越单台机器的多线程性能。矢量化代码往往最适合通过 GPU 进行并行化。例如,您可以像这样使用 Parallel Computing Toolbox 中的gpuArrays 编写代码,并让所有内容都在 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 调用,因为使用gpuArrays 时效率更高。

    【讨论】:

    • 太棒了!你是对的,Matlab 会自动对我上面给出的计算进行多线程处理。我在没有并行计算工具箱的情况下在家中运行计算,刚才我在一台带有工具箱的机器上运行它,它是并行完成的。并感谢 GPU 示例...我从未使用过 GPU,但我怀疑将来会派上用场,很高兴知道代码看起来很简单
    • 虽然这是一篇旧文章,但我能够在 GPU 上使用 bsxfun 实现它并获得了不错的加速。同样在这里发布了解决方案!
    【解决方案3】:

    在 Matlab 中,将内置向量化函数用于多线程的唯一方法是等待 MathWorks 到 implement them 这样。

    或者,您可以将向量化计算编写为循环,并使用parfor 并行运行它们。

    最后,一些函数是GPU-enabled,因此通过访问并行处理工具箱,您可以并行化这些操作,包括减法和逐元素幂。

    【讨论】:

    • for Matlab 中的循环往往比矢量化计算慢。因此,获得最佳性能的理想情况似乎是尽可能尝试并行化矢量化代码。
    • @dblazevski:parfor 有帮助,但您可能需要考虑在 GPU 上运行一些代码。请参阅我的编辑。此外,在最新版本的 Matlab 中,for-loops 变得非常快。
    • 是的。我测试了stackoverflow.com/questions/10520495/… 中给出的示例,我什至对网格进行了很多改进。在 Matlab 中,for 循环较慢,但只有矢量化版本的 5 倍左右。在 Octave 中,for 循环代码花费了 much 更长的时间(比如超过 100 倍......)。一段时间以来,我一直对 GPU 感到好奇,但还没有尝试过……您知道学习使用/编程 GPU 的起点吗?
    • @dblazevski:如果您想使用 Matlab 中的 GPU,请查看 Parallel Computing Toolbox 的文档。否则,请查看 CUDA 文档及其示例。
    • 我能够通过bsxfunon GPU 实现获得非常好的加速,并发布了一个解决方案here
    猜你喜欢
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-08
    • 1970-01-01
    • 2017-02-05
    • 2014-01-23
    相关资源
    最近更新 更多