MATLAB的bsxfun是最好的吗? Python的numpy.einsum?

时间:2017-10-19 18:22:48

标签: python arrays matlab vectorization bsxfun

我有一个非常大的乘法和求和运算,我需要尽可能高效地实现。我到目前为止找到的最好的方法是MATLAB中的bsxfun,我将问题表述为:

L = 10000;
x = rand(4,1,L+1);
A_k = rand(4,4,L);
tic
for k = 2:L
    i = 2:k;
    x(:,1,k+1) = x(:,1,k+1)+sum(sum(bsxfun(@times,A_k(:,:,2:k),x(:,1,k+1-i)),2),3);
end
toc

请注意L在实践中会更大。有更快的方法吗?奇怪的是,我需要首先将单身尺寸标注添加到x然后sum覆盖它,但我无法将其工作。

它仍然比我尝试的任何其他方法快得多,但对我们的应用程序来说还不够。我听说过有关Python函数numpy.einsum可能更有效的传闻,但我想在我考虑移植代码之前先问这里。

我正在使用MATLAB R2017b。

2 个答案:

答案 0 :(得分:5)

由于您使用的是新版本的Matlab,因此您可以尝试广播/ implicit expansion而不是bsxfun

x(:,1,k+1) = x(:,1,k+1)+sum(sum(A_k(:,:,2:k).*x(:,1,k-1:-1:1),3),2);

我还更改了求和的顺序并删除了i变量以进一步改进。在我的机器上,使用Matlab R2017b,L = 10000的速度提高了大约25%。

答案 1 :(得分:5)

我相信你的两个总结都可以删除,但我暂时只删除了更简单的总结。第二维的总和是微不足道的,因为它只影响A_k数组:

B_k = sum(A_k,2);
for k = 2:L
    i = 2:k;
    x(:,1,k+1) = x(:,1,k+1) + sum(bsxfun(@times,B_k(:,1,2:k),x(:,1,k+1-i)),3);
end

通过这一次更改,我的笔记本电脑上的运行时间从~8秒减少到约2.5秒。

通过将时间+和转换为矩阵向量乘积,也可以去除第二个求和。它需要一些单独的摆弄以获得正确的尺寸,但是如果你定义一个辅助数组B_k并且第二个维度反转,你可以使用这个辅助数组生成剩余的总和为x*C_k {{ 1}},拨打或拨打C_k

所以仔细观察之后,我意识到我原来的评估过于乐观了:你在剩下的学期中在两个方面都有乘法,所以它不是一个简单的矩阵乘积。无论如何,我们可以将该术语重写为矩阵乘积的对角线。这意味着我们正在计算一堆不必要的矩阵元素,但这似乎仍然比reshape方法略快,我们也可以摆脱你讨厌的单例维度:

bsxfun

这在我的笔记本电脑上运行约2.2秒,比之前获得的~2.5秒快一些。