3

高次元で多くの内積を計算する必要があるプロジェクトに取り組んでいます。常に matlab で操作をベクトル化する必要があることは承知していますが、これを行う方法がわかりません...

2 つの行列がAあり、 が次元で計算する内積の数であるとしBますN x dNd

for ループを使用して実装するのは簡単ですが、もっと効率的な方法があるのではないかと思います。for ループの実装は次のようになります。

innerprods=zeros(N,1);
for i=1:N
    innerprods(i)=A(i,:)*B(i,:)';
end

これをベクトル化する方法を知っている人はいますか? bsxfunある時点で出てくるはずだと思いますが、これを使用する方法がわかりません...

前もって感謝します!

4

2 に答える 2

6

簡単なことはどうですか:

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)
于 2013-06-06T22:50:38.910 に答える
2

に関するあなたの疑いbsxfunは完全に正当化されます! bsxfun次のワンライナーと古き良きコロン演算子を使用して、内積を効率的に計算できます。

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とさまざまな次元数を使用したいくつかの経験的結果を示しています。ループを使用すると、 を使用する方法よりも 2 倍から 8 倍遅くなりますbsxfun。新しいバージョンのでは、並列化が改善されているため、速度の差が大きくなる可能性があります。

ここに画像の説明を入力

于 2013-06-06T22:35:19.533 に答える