Moje pytanie: Zauważyłem, że wiele dobrych odpowiedzi na pytania Matlab dotyczące SO często korzysta z tej funkcji bsxfun
. Czemu?
Motywacja: w dokumentacji Matlab dla bsxfun
podano następujący przykład:
A = magic(5);
A = bsxfun(@minus, A, mean(A))
Oczywiście moglibyśmy wykonać tę samą operację używając:
A = A - (ones(size(A, 1), 1) * mean(A));
W rzeczywistości prosty test szybkości pokazuje, że druga metoda jest o około 20% szybsza. Dlaczego więc używać pierwszej metody? Domyślam się, że istnieją okoliczności, w których używanie bsxfun
będzie znacznie szybsze niż podejście „ręczne”. Bardzo chciałbym zobaczyć przykład takiej sytuacji i wyjaśnienie, dlaczego jest szybszy.
Również ostatni element tego pytania, ponownie z dokumentacji Matlab dla bsxfun
: "C = bsxfun (fun, A, B) stosuje binarną operację element po elemencie określoną przez funkcję handle fun do tablic A i B, z singletonem rozszerzenie włączone. ”. Co oznacza wyrażenie „z włączonym rozwijaniem singletona”?
tic...toc
wokół linii, szybkość kodu będzie zależeć od konieczności wczytywania funkcji do pamięci.timeit
funkcji w linku, który podajesz / angainor / Dan.Odpowiedzi:
Są trzy powody, dla których używam
bsxfun
( dokumentacja , link do bloga )bsxfun
jest szybszy niżrepmat
(patrz poniżej)bsxfun
wymaga mniej pisaniabsxfun
, podobnie jak używanieaccumarray
, sprawia, że czuję się dobrze ze zrozumieniem Matlab.bsxfun
powielą tablice wejściowe wzdłuż ich „pojedynczych wymiarów”, tj. wymiarów, wzdłuż których rozmiar tablicy wynosi 1, tak aby pasowały do rozmiaru odpowiadającego wymiaru drugiej tablicy. Nazywa się to „pojedynczą ekspansją”. Na marginesie, pojedyncze wymiary to te, które zostaną odrzucone, jeśli zadzwoniszsqueeze
.Możliwe, że w przypadku bardzo małych problemów
repmat
podejście jest szybsze - ale przy tym rozmiarze macierzy obie operacje są tak szybkie, że prawdopodobnie nie będzie miało żadnego wpływu na ogólną wydajność. Są dwa ważne powodybsxfun
jest szybsze: (1) obliczenia się w skompilowanym kodzie, co oznacza, że rzeczywista replikacja tablicy nigdy się nie dzieje, oraz (2)bsxfun
jest jedną z wielowątkowych funkcji Matlaba.Przeprowadziłem porównanie prędkości między
repmat
izbsxfun
R2012b na moim przyzwoicie szybkim laptopie.U mnie
bsxfun
to około 3 razy szybciej niżrepmat
. Różnica staje się bardziej wyraźna, gdy tablice stają się większeSkok w czasie wykonywania
repmat
miejsce wokół rozmiaru tablicy 1 MB, co może mieć coś wspólnego z rozmiarem pamięci podręcznej procesora -bsxfun
nie jest tak zły jak skok, ponieważ wystarczy przydzielić tablicę wyjściową.Poniżej znajduje się kod, którego użyłem do pomiaru czasu:
źródło
W moim przypadku używam
bsxfun
ponieważ pozwala mi to uniknąć myślenia o problemach z kolumnami lub wierszami.Aby napisać swój przykład:
Muszę rozwiązać kilka problemów:
1)
size(A,1)
lubsize(A,2)
2)
ones(sizes(A,1),1)
lubones(1,sizes(A,1))
3)
ones(size(A, 1), 1) * mean(A)
lubmean(A)*ones(size(A, 1), 1)
4)
mean(A)
lubmean(A,2)
Kiedy używam
bsxfun
, po prostu muszę rozwiązać ten ostatni:a)
mean(A)
lubmean(A,2)
Możesz pomyśleć, że jest leniwy czy coś, ale kiedy używam
bsxfun
, mam mniej błędów i szybciej programuję .Ponadto jest krótsza, co poprawia szybkość pisania i czytelność .
źródło
Bardzo ciekawe pytanie! Właśnie taką sytuację natknąłem się ostatnio, odpowiadając na to pytanie. Rozważmy następujący kod, który oblicza indeksy przesuwanego okna o rozmiarze 3 poprzez wektor
a
:W tym przypadku
bsxfun
jest prawie dwa razy szybszy! Jest użyteczny i szybki, ponieważ pozwala uniknąć jawnego przydzielania pamięci dla macierzyidx0
iidx1
zapisywania ich w pamięci, a następnie ponownego ich czytania, aby je dodać. Ponieważ przepustowość pamięci jest cennym atutem i często wąskim gardłem w dzisiejszych architekturach, chcesz z niej mądrze korzystać i zmniejszyć wymagania dotyczące pamięci kodu, aby poprawić wydajność.bsxfun
pozwala tylko na to: stworzyć macierz opartą 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 pojedyncza ekspansja . Możesz również pomyśleć o nim jako o produkcie zewnętrznym firmy BLAS:Mnożymy dwa wektory, aby otrzymać macierz. Tylko tyle, że iloczyn zewnętrzny wykonuje tylko mnożenie i
bsxfun
może stosować dowolne operatory. Na marginesie, bardzo interesującebsxfun
jest to, że jest tak szybki, jak produkt zewnętrzny BLAS. Zwykle uważa się, że BLAS zapewnia wydajność.Edytuj Dzięki komentarzowi Dana, oto świetny artykuł Lorena omawiający dokładnie to.
źródło
bsxfun
z dobrym przykładem.Od R2016b Matlab obsługuje niejawną ekspansję dla wielu różnych operatorów, więc w większości przypadków nie jest już konieczne używanie
bsxfun
:Jest to szczegółowe omówienie z niejawnego Rozbudowa i jego wydajność na blogu Loren. Aby zacytować Steve Eddins od MathWorks:
źródło
Rzeczy nie zawsze są zgodne z trzema typowymi metodami:
repmat
rozszerzanie o indeksowanie ibsxfun
. Robi się to bardziej interesująco, gdy jeszcze bardziej zwiększysz rozmiar wektora. Zobacz działkę:bsxfun
w rzeczywistości staje się nieco wolniejszy niż pozostałe dwa w pewnym momencie, ale co mnie zaskoczyło, to jeśli zwiększysz rozmiar wektora jeszcze bardziej (> 13E6 elementów wyjściowych), bsxfun nagle znów stanie się szybszy o około 3x. Wydaje się, że ich prędkości skaczą stopniowo, a kolejność nie zawsze jest stała. Domyślam się, że może to być również zależne od rozmiaru procesora / pamięci, ale ogólnie myślę, że trzymałbym się,bsxfun
gdy tylko jest to możliwe.źródło