web-dev-qa-db-ja.com

Matlabでは、bsxfunを使用するのが最適なのはいつですか?

私の質問: SO関数bsxfunを頻繁に使用する]に関するMatlabの質問に対する多くの良い答えに気付きました。

動機:bsxfunのMatlabドキュメントでは、次の例が提供されています。

A = magic(5);
A = bsxfun(@minus, A, mean(A))

もちろん、次を使用して同じ操作を実行できます。

A = A - (ones(size(A, 1), 1) * mean(A));

実際、簡単な速度テストでは、2番目の方法が約20%高速であることを実証しています。では、なぜ最初の方法を使用するのでしょうか? bsxfunの使用が「手動」アプローチよりもはるかに高速になる状況があると推測しています。このような状況の例と、なぜそれが速いのかについての説明を見ることに本当に興味があります。

また、bsxfunのMatlabドキュメントからのこの質問に対する最後の要素: "C = bsxfun(fun、A、B)は、関数ハンドルfunで指定された要素ごとのバイナリ演算を配列に適用しますAとB、シングルトン拡張が有効になっています。」 「シングルトン展開を有効にした」という語句はどういう意味ですか?

130
Colin T Bowers

bsxfunを使用する3つの理由があります( documentationblog link

  1. bsxfunrepmatよりも高速です(以下を参照)
  2. bsxfunは入力が少なくて済みます
  3. bsxfunを使用するのと同様に、accumarrayを使用すると、Matlabの理解が良くなります。

bsxfunは、「単一次元」、つまり配列のサイズが1である次元に沿って入力配列を複製し、他の配列の対応する次元のサイズに一致させます。これが「シングルトンエクスパション」と呼ばれるものです。余談ですが、シングルトン次元は、squeezeを呼び出した場合に削除される次元です。

非常に小さな問題の場合、repmatアプローチの方が高速である可能性がありますが、その配列サイズでは、両方の操作が非常に高速であるため、全体的なパフォーマンスの面で違いが生じない可能性があります。 bsxfunの方が高速である2つの重要な理由があります。(1)計算はコンパイルされたコードで行われます。つまり、配列の実際の複製は行われません。(2)bsxfunマルチスレッドMatlab関数。

repmatbsxfunの速度比較をR2012bでかなり高速なラップトップで実行しました。

enter image description here

私にとって、bsxfunrepmatの約3倍高速です。配列が大きくなると、差はより顕著になります

enter image description here

repmatの実行時のジャンプは、1Mbの配列サイズで発生します。これは、プロセッサキャッシュのサイズと関係がある可能性があります-bsxfunはジャンプほど悪くありません。出力配列を割り当てるだけです。

以下に、タイミングに使用したコードを示します。

n = 300;
k=1; %# k=100 for the second graph
a = ones(10,1);
rr = zeros(n,1);
bb=zeros(n,1);
ntt=100;
tt=zeros(ntt,1);
for i=1:n;
   r = Rand(1,i*k);
   for it=1:ntt;
      tic,
      x=bsxfun(@plus,a,r);
      tt(it)=toc;
   end;
   bb(i)=median(tt);
   for it=1:ntt;
      tic,
      y=repmat(a,1,i*k)+repmat(r,10,1);
      tt(it)=toc;
   end;
   rr(i)=median(tt);
end
151
Jonas

私の場合、bsxfunを使用します。列または行の問題について考える必要がなくなるからです。

あなたの例を書くには:

_A = A - (ones(size(A, 1), 1) * mean(A));
_

私はいくつかの問題を解決しなければなりません:

1)size(A,1)またはsize(A,2)

2)ones(sizes(A,1),1)またはones(1,sizes(A,1))

3)ones(size(A, 1), 1) * mean(A)またはmean(A)*ones(size(A, 1), 1)

4)mean(A)またはmean(A,2)

bsxfunを使用する場合、最後の1つを解決する必要があります。

a)mean(A)またはmean(A,2)

あなたはそれが怠zyだと思うかもしれませんが、bsxfunを使用すると、バグが少ないプログラムの高速化になります。

さらに、より短くなり、タイピング速度および読みやすさが向上します。

40
Oli

非常に興味深い質問です! this 質問に答えている間、私は最近そのような状況につまずいた。ベクトルaを介してサイズ3のスライディングウィンドウのインデックスを計算する次のコードを考えます。

a = Rand(1e7,1);

tic;
idx = bsxfun(@plus, [0:2]', 1:numel(a)-2);
toc

% equivalent code from im2col function in MATLAB
tic;
idx0 = repmat([0:2]', 1, numel(a)-2);
idx1 = repmat(1:numel(a)-2, 3, 1);
idx2 = idx0+idx1;
toc;

isequal(idx, idx2)

Elapsed time is 0.297987 seconds.
Elapsed time is 0.501047 seconds.

ans =

 1

この場合、bsxfunはほぼ2倍高速です! 行列idx0およびidx1のメモリの明示的な割り当てを回避し、メモリに保存してから再び読み込むため、便利で高速です。それらを追加します。メモリ帯域幅は貴重な資産であり、今日のアーキテクチャのボトルネックとなることが多いため、パフォーマンスを改善するためにコードのメモリ要件を適切に減らして使用する必要があります。

bsxfunを使用すると、ベクトルを複製して得られた2つの行列を明示的に操作するのではなく、2つのベクトルの要素のすべてのペアに任意の演算子を適用して行列を作成できます。それはシングルトン展開です。 BLASの outer product と考えることもできます。

v1=[0:2]';
v2 = 1:numel(a)-2;
tic;
vout = v1*v2;
toc
Elapsed time is 0.309763 seconds.

2つのベクトルを乗算して行列を取得します。外積は乗算のみを実行し、bsxfunは任意の演算子を適用できます。補足として、bsxfunがBLAS外積と同じくらい速いことを見るのは非常に興味深いです。また、BLASは通常 the パフォーマンスを提供すると見なされます。

Edit Danのコメントのおかげで、ここに素晴らしい Lorenによる記事 まさにそれについて議論しています。

16
angainor

R2016bの時点で、Matlabは Implicit Expansion をさまざまな演算子に対してサポートしているため、ほとんどの場合、bsxfunを使用する必要はありません。 :

以前は、この機能はbsxfun関数を介して利用できました。現在、bsxfunのほとんどの使用を、暗黙的展開をサポートする関数および演算子の直接呼び出しに置き換えることをお勧めしますbsxfunを使用する場合と比較して、暗黙的な拡張より速い速度メモリ使用量の改善、およびコードの可読性の向上.

詳細な議論 ofImplicit ExpansionとそのパフォーマンスがLorenのブログにあります。宛先 引用 MathWorksのSteve Eddins:

R2016bでは、暗黙的な展開は、ほとんどの場合、bsxfunよりも高速または高速に動作します。 暗黙的展開の最良のパフォーマンスの向上は、小さなマトリックスと配列サイズの場合です。マトリックスサイズが大きい場合、暗黙的な展開はbsxfunとほぼ同じ速度になる傾向があります。

12
nirvana-msu

物事は、3つの一般的な方法:repmat、物事のインデックスによる拡張、およびbsxfunと常に一貫しているわけではありません。ベクトルのサイズをさらに大きくすると、より興味深いものになります。プロットを参照してください:

comparison

bsxfunは実際にはある時点で他の2つよりわずかに遅くなりますが、驚いたのは、ベクトルサイズをさらに大きくすると(> 13E6出力要素)、bsxfunが突然約3倍速くなります。それらの速度は段階的にジャンプするようであり、順序は常に一貫しているとは限りません。私の推測では、プロセッサ/メモリのサイズにも依存する可能性がありますが、一般的には可能な限りbsxfunに固執すると思います。

8
Justin Wong