Matlab'da bsxfun kullanmak ne zaman en uygunudur?


135

Benim sorum: Matlab sorularına SO hakkında çok iyi cevapların sık sık işlevi kullandığını fark ettim bsxfun. Neden?

Motivasyon: için Matlab belgelerinde bsxfunaşağıdaki örnek verilmiştir:

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

Tabii ki aynı işlemi kullanarak yapabiliriz:

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

Aslında basit bir hız testi, ikinci yöntemin yaklaşık% 20 daha hızlı olduğunu gösterir. Peki neden ilk yöntemi kullanmalıyım? Sanırım kullanım bsxfun"manuel" yaklaşım daha hızlı olacak bazı durumlar vardır . Böyle bir durumun bir örneğini ve neden daha hızlı olduğuna dair bir açıklama görmekle gerçekten ilgilenirim.

Ayrıca, yine bu sorunun Matlab belgelerinden son bir öğe bsxfun: "C = bsxfun (eğlence, A, B) işlev tutamacı eğlencesi tarafından belirtilen öğe tekli ikili işlemi, singleton ile A ve B dizilerine uygular genişletme etkin. "Singleton genişletmesi etkin" ifadesi ne anlama geliyor?


4
Aldığınız hız okumasının yaptığınız teste bağlı olduğunu unutmayın. Matlab'ı yeniden başlattıktan sonra yukarıdaki kodu çalıştırırsanız ve sadece tic...tocsatırların etrafına koyarsanız , kodun hızı işlevleri belleğe okumak zorunda kalmanıza bağlı olacaktır.
Jonas

@Jonas Evet, bunu timeitsize / angainor / Dan'ın sağladığı bağlantıdaki işlevi okuyarak öğrendim .
Colin T Bowers

Yanıtlar:


152

Kullanmamın üç nedeni var bsxfun( belgeler , blog bağlantısı )

  1. bsxfundaha hızlıdır repmat(aşağıya bakın)
  2. bsxfun daha az yazmayı gerektirir
  3. Kullanmak bsxfun, kullanmak gibi accumarray, Matlab hakkındaki anlayışım hakkında iyi hissettiriyor.

bsxfungirdi dizilerini "tekton boyutları" boyunca, yani dizinin boyutunun 1 olduğu boyutlar boyunca çoğaltır, böylece diğer dizinin karşılık gelen boyutunun boyutuyla eşleşirler. Buna "singleton açılımı" denir. Bir kenara, tekil boyutlar aradığınızda düşürülecek boyutlardır squeeze.

Çok küçük problemler için repmatyaklaşımın daha hızlı olması mümkündür - ancak bu dizi boyutunda, her iki işlem o kadar hızlıdır ki, genel performans açısından herhangi bir fark yaratmayacaktır. bsxfunDaha hızlı iki önemli neden vardır : (1) hesaplama derlenmiş kodda gerçekleşir, yani dizinin gerçek çoğaltması hiçbir zaman olmaz ve (2) bsxfunçok iş parçacıklı Matlab işlevlerinden biridir.

Ben arasında bir hız karşılaştırma yayınlanmış olan repmatve bsxfunbenim terbiyeli hızlı dizüstü R2012b ile.

resim açıklamasını buraya girin

Benim için, bsxfunyaklaşık 3 kat daha hızlı repmat. Diziler büyürse fark daha belirgin hale gelir

resim açıklamasını buraya girin

Çalışma zamanındaki atlama, repmatişlemci önbelleğimin boyutuyla ilgili bir şey olabilen 1Mb'lik bir dizi boyutu etrafında gerçekleşir - bsxfunsadece çıkış dizisini tahsis etmesi gerektiği için bir sıçrama kadar kötü olmaz.

Aşağıda zamanlama için kullandığım kodu bulabilirsiniz:

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

Mükemmel yanıt +1 için teşekkür ederiz. Bu cevabı en kapsamlı tartışma olduğu ve aynı zamanda (bu noktada) en yüksek oyu aldığı için işaretledim.
Colin T Bowers

40

Benim durumumda kullanıyorum bsxfunçünkü sütun veya satır sorunları hakkında düşünmemi engelliyor.

Örneğinizi yazmak için:

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

Birkaç sorunu çözmem gerekiyor:

1) size(A,1)veyasize(A,2)

2) ones(sizes(A,1),1)veyaones(1,sizes(A,1))

3) ones(size(A, 1), 1) * mean(A)veyamean(A)*ones(size(A, 1), 1)

4) mean(A)veyamean(A,2)

Kullandığımda bsxfunsonuncuyu çözmem gerekiyor:

a) mean(A)veyamean(A,2)

Bunu tembel falan olduğunu düşünebilir, ama kullanırken bsxfun, ben az hata ve daha hızlı programlamak .

Dahası, daha kısadır, bu da yazma hızını ve okunabilirliği artırır .


1
Yanıt için teşekkürler Oli. Bu cevabın +1, angainor ve Jonas'ın yanıtlarına ek olarak bir şeyler kattığını düşünüyorum. Özellikle, belirli bir kod satırında çözülmesi gereken kavramsal sorunların sayısını ortaya koyma şeklinizi beğendim.
Colin T Bowers

16

Çok ilginç bir soru! Son zamanlarda bu soruyu cevaplarken tam olarak böyle bir duruma düştüm . 3 boyutlu kayar pencere indekslerini bir vektör üzerinden hesaplayan aşağıdaki kodu göz önünde bulundurun 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

Bu durumda bsxfunneredeyse iki kat daha hızlı! Matrisler için açık bellek tahsisiidx0 ve idx1bunları belleğe kaydetmekten kaçınmak ve daha sonra bunları sadece eklemek için tekrar okumak için yararlı ve hızlıdır . Bellek bant genişliği değerli bir varlık olduğundan ve genellikle günümüz mimarilerindeki darboğaz olduğundan, akıllıca kullanmak ve performansı artırmak için kodunuzun bellek gereksinimlerini azaltmak istersiniz.

bsxfunsadece bunu yapmanıza izin verir: vektörleri çoğaltmak suretiyle elde edilen iki matris üzerinde açıkça çalışmak yerine, iki vektörün tüm eleman çiftlerine keyfi bir operatör uygulanmasına dayalı bir matris oluşturun. Bu singleton genişlemesi . Ayrıca BLAS'ın dış ürünü olarak da düşünebilirsiniz :

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

Bir matris elde etmek için iki vektörü çarparsınız. Sadece dış ürün sadece çarpma gerçekleştirir ve bsxfunrastgele işleçler uygulayabilir. Bir yan not bsxfunolarak, BLAS dış ürünü kadar hızlı olduğunu görmek çok ilginç . Ve BLAS genellikle olarak sunuyor demektir performansı ..

Edit Dan'ın yorumu sayesinde, Loren'in tam olarak tartıştığı harika bir makale .


7
Bu makale alakalı olabilir: blogs.mathworks.com/loren/2008/08/04/…
Dan

@ Dan Harika bir referans için teşekkürler.
angainor

Büyük bir yanıt verdiğiniz için teşekkürler. bsxfunİyi bir örnekle ana avantajını açıkça belirten ilk kişi olduğu için +1 .
Colin T Bowers

13

Matlab, R2016b'den itibaren çok çeşitli operatörler için Örtülü Genişlemeyi destekler , bu nedenle çoğu durumda artık kullanmak gerekmez bsxfun:

Önceden, bu işlevsellik işlev aracılığıyla kullanılabiliyordu bsxfun. Artık, çoğu kullanımını örtülü genişletmeyibsxfun destekleyen işlevlere ve işleçlere yapılan doğrudan çağrılarla değiştirmeniz önerilir . Kullanarak karşılaştırıldığında , örtük genişletme teklifler daha hızlı , daha iyi bellek kullanımı ve kod geliştirilmiş okunabilirliği .bsxfun

Bir var ayrıntılı tartışma ve Örtülü Genişleme ve Loren blogunda performansı. To alıntı MathWorks'un Steve Eddins:

R2016b'de, örtülü genişletmebsxfun çoğu durumda olduğundan daha hızlı veya daha hızlı çalışır . Örtük genişletme için en iyi performans kazançları küçük matris ve dizi boyutlarıdır. Büyük matris boyutları için, örtülü genişleme kabaca aynı hızda olma eğilimindedir bsxfun.


8

İşler her zaman 3 yaygın yöntemle tutarlı değildir:, repmatindeksleme ile genişletme ve bsxfun. Vektör boyutunu daha da büyüttüğünüzde daha ilginç hale gelir. Grafiğe bakınız:

karşılaştırma

bsxfunaslında bir noktada diğer ikisinden biraz yavaşlar, ama vektör boyutunu daha da arttırırsanız (> 13E6 çıkış öğeleri), bsxfun aniden tekrar yaklaşık 3 kat daha hızlı hale gelir. Hızları adım adım atlıyor gibi görünüyor ve düzen her zaman tutarlı değil. Benim tahminim işlemci / bellek boyutuna da bağlı olabilir, ama genellikle bsxfunmümkün olduğunda yapışacağımı düşünüyorum .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.