在matlab中有效地计算许多内部产品

时间:2013-06-06 22:32:36

标签: matlab vectorization bsxfun

我正在开发一个项目,我需要在这个项目中计算大量的内部产品。我知道我们应该总是尝试在matlab中对操作进行矢量化,但我不知道该怎么做...

假设我们有两个大小为A的{​​{1}}和B矩阵,其中N x d是要在N维中计算的内积的数量。

使用for循环很容易实现,但我怀疑存在更有效的方法。 for循环实现可能如下所示:

d

有没有人有想法如何对此进行矢量化?我想innerprods=zeros(N,1); for i=1:N innerprods(i)=A(i,:)*B(i,:)'; end 应该在某个时候发挥作用,但我无法弄清楚如何使用它...

提前致谢!

2 个答案:

答案 0 :(得分:5)

简单来说:

sum(A.*B,2)

一个简单的测试(R2013a WinVista 32bit Core duo):

N = 8e3;
A = rand(N);
B = rand(N);

tic
out = zeros(N,1);
for ii = 1:N
    out(ii) = A(ii,:)*B(ii,:)';
end
toc

tic
out2 = sum(A.*B,2);
toc

all(out-out2 < 1e5*eps) % note difference in precision

时报

loop     5.6 sec
multsum  0.8 sec

R2013a Win7 64 Xeon E5的附加测试

Avg time loop:           2.00906 seconds
Avg time multSum:        0.18114 seconds
Avg time bsxfun:         0.18203 seconds
Avg time reshapeMultSum: 0.18088 seconds

主要外卖点:

    在这种情况下,
  • 循环非常低效(预期);
  • bsxfun()完全冗余,虽然开销不大(预期);
  • 由于MATLAB引擎对列式操作的内部“偏好”(即首先是行),重新整理成一列然后再回到矩阵也可以带来好处;
  • 语法清晰度我仍然建议使用multSum:sum(A.*B,2)

测试套件(100次试验的平均时间,固定矩阵大小8e3,结果等于1e5 * eps):

N = 8e3;
A = rand(N);
B = rand(N);

tic
for r = 1:100
    out = zeros(N,1);
    for ii = 1:N
        out(ii) = A(ii,:)*B(ii,:)';
    end
end
sprintf('Avg time loop: %.5f seconds', toc/100)

tic
for r = 1:100; out2 = sum(A.*B,2);                                  end
sprintf('Avg time multSum: %.5f seconds', toc/100)

tic
for r = 1:100; out3 = sum(reshape(bsxfun(@times,A(:),B(:)),N,N),2); end
sprintf('Avg time bsxfun: %.5f seconds', toc/100)

tic
for r = 1:100; out4 = sum(reshape(A(:).*B(:),N,N),2);               end
sprintf('Avg time reshapeMultSum: %.5f seconds', toc/100)

答案 1 :(得分:2)

您对bsxfun的怀疑是完全合理的!您可以使用以下带有bsxfun的单行和良好的旧colon operator来有效地计算内部产品:

innerprods=sum(reshape(bsxfun(@times,A(:),B(:)),N,d),2);

有关此处发生的事情的更详细说明:

    bsxfun(@times,A(:),B(:)) --> element-wise product, returns Nd x 1 vector
    reshape( ^^^ , N, d)      --> reshape into N x d matrix
    sum( ^^^ , 2)             --> sum over columns to get N x 1 vector

编辑:我做了一些时间来了解性能差异。我使用 R2010b(不要问......)。该图显示了在您的问题中使用循环的一些实证结果以及我建议的N=500和不同维数的单线程。使用循环比使用bsxfun的方法慢2到8倍。由于更好的并行化,的较新版本的速度差异可能更大。

enter image description here