我有一个非常大的乘法和求和运算,我需要尽可能高效地实现。我到目前为止找到的最好的方法是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。
答案 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秒快一些。