私の質問: 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、シングルトン拡張が有効になっています。」 「シングルトン展開を有効にした」という語句はどういう意味ですか?
bsxfun
を使用する3つの理由があります( documentation 、 blog link )
bsxfun
はrepmat
よりも高速です(以下を参照)bsxfun
は入力が少なくて済みますbsxfun
を使用するのと同様に、accumarray
を使用すると、Matlabの理解が良くなります。bsxfun
は、「単一次元」、つまり配列のサイズが1である次元に沿って入力配列を複製し、他の配列の対応する次元のサイズに一致させます。これが「シングルトンエクスパション」と呼ばれるものです。余談ですが、シングルトン次元は、squeeze
を呼び出した場合に削除される次元です。
非常に小さな問題の場合、repmat
アプローチの方が高速である可能性がありますが、その配列サイズでは、両方の操作が非常に高速であるため、全体的なパフォーマンスの面で違いが生じない可能性があります。 bsxfun
の方が高速である2つの重要な理由があります。(1)計算はコンパイルされたコードで行われます。つまり、配列の実際の複製は行われません。(2)bsxfun
マルチスレッドMatlab関数。
repmat
とbsxfun
の速度比較をR2012bでかなり高速なラップトップで実行しました。
私にとって、bsxfun
はrepmat
の約3倍高速です。配列が大きくなると、差はより顕著になります
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
私の場合、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
を使用すると、バグが少ないとプログラムの高速化になります。
さらに、より短くなり、タイピング速度および読みやすさが向上します。
非常に興味深い質問です! 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による記事 まさにそれについて議論しています。
R2016bの時点で、Matlabは Implicit Expansion をさまざまな演算子に対してサポートしているため、ほとんどの場合、bsxfun
を使用する必要はありません。 :
以前は、この機能は
bsxfun
関数を介して利用できました。現在、bsxfun
のほとんどの使用を、暗黙的展開をサポートする関数および演算子の直接呼び出しに置き換えることをお勧めします。bsxfun
を使用する場合と比較して、暗黙的な拡張はより速い速度、メモリ使用量の改善、およびコードの可読性の向上.
詳細な議論 ofImplicit ExpansionとそのパフォーマンスがLorenのブログにあります。宛先 引用 MathWorksのSteve Eddins:
R2016bでは、暗黙的な展開は、ほとんどの場合、
bsxfun
よりも高速または高速に動作します。 暗黙的展開の最良のパフォーマンスの向上は、小さなマトリックスと配列サイズの場合です。マトリックスサイズが大きい場合、暗黙的な展開はbsxfun
とほぼ同じ速度になる傾向があります。
物事は、3つの一般的な方法:repmat
、物事のインデックスによる拡張、およびbsxfun
と常に一貫しているわけではありません。ベクトルのサイズをさらに大きくすると、より興味深いものになります。プロットを参照してください:
bsxfun
は実際にはある時点で他の2つよりわずかに遅くなりますが、驚いたのは、ベクトルサイズをさらに大きくすると(> 13E6出力要素)、bsxfunが突然約3倍速くなります。それらの速度は段階的にジャンプするようであり、順序は常に一貫しているとは限りません。私の推測では、プロセッサ/メモリのサイズにも依存する可能性がありますが、一般的には可能な限りbsxfun
に固執すると思います。