Kiedy w Matlab jest optymalne użycie bsxfun?

Moje pytanie: zauważyłem, że wiele dobrych odpowiedzi na pytania Matlab na tak często korzysta z funkcji bsxfun. Dlaczego?

Motywacja: w dokumentacji Matlab dla bsxfun podano następujący przykład:

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

Oczywiście możemy wykonać tę samą operację używając:

A = A - (ones(size(A, 1), 1) * mean(A));
W rzeczywistości prosty test prędkości pokazuje, że druga metoda jest o około 20% szybsza. Po co więc stosować pierwszą metodę? Domyślam się, że są pewne okoliczności, w których używanie bsxfun będzie znacznie szybszy niż podejście "ręczne". Chciałbym zobaczyć przykład takiej sytuacji i wyjaśnienie, dlaczego jest ona szybsza.

Również ostatni element na to pytanie, ponownie z Dokumentacji Matlab dla bsxfun: "C = bsxfun(fun,A,B) stosuje operację binarną element po elemencie określoną przez funkcję handle fun do tablic A i B, z włączonym rozszerzeniem Singletona.". Co oznacza wyrażenie "z włączoną ekspansją Singletona"?

Author: George Stocker, 2012-10-18

5 answers

Są trzy powody, dla których używam bsxfun (dokumentacja, blog link )

  1. bsxfun jest szybszy niż repmat (patrz niżej)
  2. bsxfun wymaga mniej typowania
  3. używanie bsxfun, Jak używanie accumarray, sprawia, że czuję się dobrze ze zrozumieniem Matlaba.

bsxfun replikuje tablice wejściowe wzdłuż ich "singleton dimensions" , tzn. wymiarów, wzdłuż których rozmiar tablicy wynosi 1, tak aby pasowały do rozmiaru odpowiadającego wymiar drugiej tablicy. To się nazywa "singleton expasion". Na marginesie, wymiary Singletona to te, które zostaną zrzucone, jeśli wywołasz squeeze.

Jest możliwe, że w przypadku bardzo małych problemów podejście repmat jest szybsze - ale przy tej wielkości tablicy obie operacje są tak szybkie, że prawdopodobnie nie będzie to miało żadnej różnicy pod względem ogólnej wydajności. Istnieją dwa ważne powody bsxfun jest szybszy: (1) obliczenia odbywają się w skompilowanym kodzie, co oznacza, że (2) bsxfun jest jedną z wielowątkowych funkcji Matlab.

Przeprowadziłem porównanie prędkości między repmat i bsxfun z R2012b na moim przyzwoicie szybkim laptopie.

Tutaj wpisz opis obrazka

Dla mnie, bsxfun jest około 3 razy szybszy niż repmat. Różnica staje się bardziej wyraźna, jeśli tablice stają się większe

Tutaj wpisz opis obrazka

Skok w uruchomieniu repmat odbywa się wokół tablicy o rozmiarze 1MB, co może mieć coś wspólnego z rozmiar pamięci podręcznej mojego procesora - bsxfun nie jest tak zły ze skoku, ponieważ potrzebuje tylko przydzielić tablicę wyjściową.

Poniżej znajdziesz kod, którego użyłem do pomiaru czasu:

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
 145
Author: Jonas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-18 13:25:17

W moim przypadku używam bsxfun, ponieważ unika mi to myślenia o problemach z kolumną lub wierszem.

W celu napisania przykładu:

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

Muszę rozwiązać kilka problemów:

1) size(A,1) lub size(A,2)

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

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

4) mean(A) lub mean(A,2)

Kiedy używam bsxfun, muszę rozwiązać ostatnią:

A) mean(A) lub mean(A,2)

Możesz pomyśleć, że jest leniwy czy coś, ale kiedy używam bsxfun, mam mniej błędów a ja programuję szybciej .

Ponadto jest krótszy, co poprawia szybkość pisania i czytelność.

 39
Author: Oli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-18 20:48:50

Bardzo ciekawe pytanie! Ostatnio natknąłem się na dokładnie taką sytuację, odpowiadając na to pytanie. Rozważmy następujący kod, który oblicza indeksy okna przesuwnego o rozmiarze 3 przez wektor 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

W tym przypadku bsxfun jest prawie dwa razy szybszy! Jest to przydatne i szybkie, ponieważ unika jednoznacznego przydzielania pamięci dla macierzy idx0 i idx1, zapisując je w pamięci, a następnie odczytując je ponownie, aby je dodać. Od pamięci przepustowość jest cennym zasobem i często wąskim gardłem na dzisiejszych architekturach, chcesz używać jej mądrze i zmniejszyć zapotrzebowanie na pamięć kodu w celu poprawy wydajności.

bsxfun pozwala na to: tworzenie macierzy opartej na zastosowaniu dowolnego operatora do wszystkich par elementów dwóch wektorów, zamiast operować jawnie na dwóch macierzach uzyskanych przez replikację wektorów. To jest ekspansja Singletona . Można również myśleć o tym jako o produkt zewnętrzny z BLAS:

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

Można pomnożyć dwa wektory, aby uzyskać macierz. Tylko, że iloczyn zewnętrzny wykonuje tylko mnożenie i {[3] } może stosować dowolne operatory. Na marginesie, bardzo interesujące jest to, że bsxfun jest tak szybki jak produkt zewnętrzny BLAS. I BLAS jest zwykle uważane za dostarczenie wydajność ..

Edit Dzięki komentarzowi dana, oto świetny artykuł Loren omawiający dokładnie to.

 16
Author: angainor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:30:55

[[6]}od R2016b, Matlab obsługuje Implicit Expansion dla wielu różnych operatorów, więc w większości przypadków nie jest już konieczne stosowanie bsxfun:

Poprzednio funkcjonalność ta była dostępna za pomocą funkcji bsxfun. Teraz zaleca się zastąpienie większości zastosowań bsxfun bezpośrednim wywołania funkcji i operatorów, które obsługują implicit expansion . W porównaniu do używania bsxfun, implicit expansion offers faster speed , lepsze wykorzystanie pamięci i Poprawiono czytelność kodu .

Jestszczegółowa dyskusja Implicit Expansion i jej wydajność na blogu Loren. Do cytat Steve Eddins z MathWorks:

W R2016b, implicit expansion działa tak szybko lub szybciej niż bsxfun w większości przypadków. Najlepsze zyski wydajności dla implicit expansion są przy małych rozmiarach macierzy i tablic. Dla dużych wielkości macierzy, Expansion implicit ma tendencję do mniej więcej takiej samej prędkości jak bsxfun.

 12
Author: nirvana-msu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-30 16:39:15

Rzeczy nie zawsze są zgodne z 3 wspólnymi metodami: repmat, expension by one indexing, and bsxfun. Staje się to bardziej interesujące, gdy zwiększasz rozmiar wektora jeszcze bardziej. Patrz wykres:

porównanie

bsxfun w pewnym momencie staje się nieco wolniejszy niż dwa pozostałe, ale zaskoczyło mnie to, że jeśli zwiększysz rozmiar wektora jeszcze bardziej (>elementy wyjściowe 13e6), bsxfun nagle znowu staje się szybszy o około 3x. nie zawsze konsekwentny. Domyślam się, że może to być również zależne od rozmiaru procesora / pamięci, ale generalnie myślę, że zostałbym przy bsxfun, gdy tylko to możliwe.

 8
Author: Justin Wong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-05 08:43:51