136

スタック オーバーフローに関する MATLAB の質問に対する多くの適切な回答で、関数 が頻繁に使用されていることに気付きましたbsxfun。なんで?

動機:の MATLAB ドキュメンテーションでbsxfunは、次の例が提供されています。

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

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

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

実際、単純な速度テストでは、2 番目の方法が約 20% 高速であることを示しています。では、なぜ最初の方法を使用するのでしょうか。bsxfun「手動」アプローチよりも使用がはるかに高速になる状況がいくつかあると思います。このような状況の例と、なぜ高速なのかについての説明を見てみたいと思います。

また、この質問の最後の要素の 1 つは、MATLAB のドキュメンテーションから再びbsxfun引用したものです。拡張可能。」「シングルトン拡張が有効になっている」というフレーズはどういう意味ですか?

4

5 に答える 5

153

私が使用する理由は 3 つありますbsxfun(ドキュメントブログ リンク)

  1. bsxfunよりも高速ですrepmat(以下を参照)
  2. bsxfunタイピングが少なくてすむ
  3. を使用するbsxfunと、 を使用するのと同じようaccumarrayに、MATLAB を理解していることに満足できます。

bsxfunは、入力配列を「単一次元」、つまり配列のサイズが 1 になる次元に沿って複製し、他の配列の対応する次元のサイズと一致するようにします。これが「シングルトン展開」と呼ばれるものです。余談ですが、シングルトン ディメンションは、 を呼び出すと削除されるディメンションですsqueeze

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

repmatかなり高速なラップトップで、MATLAB R2012bとbsxfunMATLAB R2012bの速度を比較しました。

ここに画像の説明を入力してください

私にとって、bsxfunは よりも約 3 倍高速ですrepmat。配列が大きくなると、違いはより顕著になります。

ここに画像の説明を入力してください

実行時のジャンプはrepmat、1 MB の配列サイズ前後で発生します。これは、プロセッサ キャッシュのサイズと関係がある可能性があり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
于 2012-10-18T13:19:42.440 に答える
41

私の場合は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、最後の問題を解決するだけです。

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

怠け者か何かと思うかもしれませんが、 を使用すると、バグbsxfun少なくなりプログラミングが速くなります。

さらに、短いため、タイピング速度読みやすさが向上します。

于 2012-10-18T19:54:27.287 に答える
17

とても興味深い質問です!私は最近、この質問に答えているときにまさにそのような状況に出くわしました。vector を介してサイズ 3 のスライディング ウィンドウのインデックスを計算する次のコードを検討してくださいa

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 倍高速です。行列とのメモリの明示的な割り当てを回避し、それらをメモリに保存し、それらを追加するためだけに再度読み取るため、便利で高速です。メモリ帯域幅は貴重な資産であり、多くの場合、今日のアーキテクチャのボトルネックであるため、それを賢く使用してコードのメモリ要件を減らしてパフォーマンスを向上させたいと考えています。idx0idx1

bsxfunベクトルを複製して得られた 2 つの行列を明示的に操作する代わりに、任意の演算子を 2 つのベクトルの要素のすべてのペアに適用することに基づいて行列を作成します。それがシングルトン展開です。BLASの外側の製品と考えることもできます。

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

行列を取得するには、2 つのベクトルを乗算します。外積は乗算のみを実行し、bsxfun任意の演算子を適用できるというだけです。bsxfun余談ですが、BLASのアウター製品と同じくらい速いのは非常に興味深いです。そして、BLASは通常、パフォーマンスを提供すると考えられてます...

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

于 2012-10-18T09:45:29.577 に答える
16

R2016b の時点で、MATLAB はさまざまな演算子のImplicit Expansionbsxfunをサポートしているため、ほとんどの場合、 を使用する必要はなくなりました。

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

Loren のブログには、Implicit Expansion とそのパフォーマンスに関する詳細議論があります。MathWorksから Steve Eddinsを引用するには:

In R2016b, implicit expansion works as fast or faster than bsxfun in most cases. The best performance gains for implicit expansion are with small matrix and array sizes. For large matrix sizes, implicit expansion tends to be roughly the same speed as bsxfun.

于 2016-10-07T20:27:53.040 に答える
9

repmat物事は、3 つの一般的な方法と常に一致するとは限りませんbsxfun。ベクトルのサイズをさらに大きくすると、さらに面白くなります。プロットを参照してください:

比較

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

于 2013-10-19T10:52:31.927 に答える