【问题标题】:Multiplication of corresponding 2d slices of two arrays and inversion of array slices两个数组的对应二维切片的乘法和数组切片的反转
【发布时间】:2014-10-28 11:20:49
【问题描述】:

我有两个数组AB 具有相同的维度1000 x 3 x 20 x 20。我想生成维度为3 x 3 x 20 x 20 的第三个数组C,这将是AB 的对应切片矩阵相乘的结果,即C(:,:,i,j) = A(:,:,i,j)'*B(:,:,i,j)。然后我需要通过反转相应的3 x 3 矩阵,即D(:,:,i,j) = inv(C(:,:,i,j)),将数组C 转换为新数组D。同样,很清楚如何使用循环来做到这一点。有没有办法避免循环遍历 400 项目?

编辑:比较不同解决方案性能的基准代码是 -

%// Inputs
n1 = 50;
n2 = 200;
A = rand(n1,3,n2,n2);
B = rand(n1,3,n2,n2);

%// A. CPU loopy code
tic
C = zeros(3,3,n2,n2);
for ii = 1:n2
    for jj = 1:n2
        C(:,:,ii,jj) = A(:,:,ii,jj)'*B(:,:,ii,jj); %//'
    end
end
toc

%// B. Vectorized code (using squeeze)
tic
C1 = squeeze(sum(bsxfun(@times,permute(A,[2 1 5 3 4]),permute(B,[5 1 2 3 4])),2));
toc

%// C. Vectorized code (avoiding squeeze)
tic
C2 = sum(bsxfun(@times,permute(A,[2 5 3 4 1]),permute(B,[5 2 3 4 1])),5);
toc

%// D. GPU vectorized code
tic
A = gpuArray(A);
B = gpuArray(B);
C3 = sum(bsxfun(@times,permute(A,[2 5 3 4 1]),permute(B,[5 2 3 4 1])),5);
C3 = gather(C3);
toc

运行时结果 -

Elapsed time is 0.287511 seconds.
Elapsed time is 0.250663 seconds.
Elapsed time is 0.337628 seconds.
Elapsed time is 1.259207 seconds.

【问题讨论】:

  • 哇!这是一些有用且有趣的运行时结果。谢谢!
  • 另外,我忘了提到的另一件事是您需要在基准测试之前“预热”GPU。因此,实现这一目标的最简单方法是按原样运行基准测试代码并再次运行它并观察第二次运行的运行时。对 GPU 代码进行基准测试的可靠方法是使用 gputimeit,但这会使代码复杂化,因此暂时不要这样做。

标签: arrays matlab vectorization matrix-multiplication


【解决方案1】:

代码

%// Part - 1
C = sum(bsxfun(@times,permute(A,[2 5 3 4 1]),permute(B,[5 2 3 4 1])),5);

%// Part - 2: Use MATLAB file-exchange tool multinv
D = multinv(C);

multinv 的功能码可在here 使用,它声称非常高效。

第一部分,你也可以试试这个-

C = squeeze(sum(bsxfun(@times,permute(A,[2 1 5 3 4]),permute(B,[5 1 2 3 4])),2));

这似乎是重新排列元素不像上面代码中提到的那样“破坏性”,但缺点是需要squeeze,这可能会减慢它的速度。我会把它留给您,并鼓励您进行基准测试并选择更好的。


为什么是bsxfun + GPU

我增加了循环限制,因为这可能是循环代码和矢量化代码之间的真正测试。所以,这是第 1 部分的修改代码 -

%// Inputs
n1 = 50;
n2 = 200;
A = rand(n1,3,n2,n2);
B = rand(n1,3,n2,n2);

%// A. CPU loopy code
tic
C = zeros(3,3,n2,n2);
for ii = 1:n2
    for jj = 1:n2
        C(:,:,ii,jj) = A(:,:,ii,jj)'*B(:,:,ii,jj); %//'
    end
end
toc

%// B. GPU vectorized code
tic
A = gpuArray(A);
B = gpuArray(B);
C1 = sum(bsxfun(@times,permute(A,[2 5 3 4 1]),permute(B,[5 2 3 4 1])),5);
C1 = gather(C1);
toc

我系统上的运行时结果是 -

Elapsed time is 0.310056 seconds.
Elapsed time is 0.172499 seconds.

所以,你看!

【讨论】:

  • 对于 bsxfun 如何处理多维数组,我仍然缺乏直觉。非常感谢您再次回答类似问题,并感谢您提及 multinv。
  • @Laimond 关于bsxfun 的剧本与permute 非常紧密地结合使用,大多数时候(与bsxfun 一起工作时)创建单一维度,在内部由bsxfun 扩展在执行句柄@ 提到的操作之前。这需要时间,但真的要玩弄它!
  • @Laimond 另外,如果你有一个不错的 GPU,你会看到使用 bsxfun 的疯狂好处。
  • 看来第二种方案稍微快一些。我的 GPU 是一个非常基本的 GPU,GeForce 410M。你的意思是某种并行计算,或者你的意思是如果我的 GPU 更好,代码会运行得更快?
  • @Laimond 使用 GPU 代码编辑了解决方案。如果您不介意为此烦恼,我也很想看到您的结果。
猜你喜欢
  • 2012-11-10
  • 2013-04-12
  • 1970-01-01
  • 1970-01-01
  • 2018-05-06
  • 2014-04-14
  • 2019-08-08
相关资源
最近更新 更多