Chciałbym napisać program, który w szerokim zakresie wykorzystuje funkcje algebry liniowej BLAS i LAPACK. Ponieważ wydajność jest problemem, przeprowadziłem testy porównawcze i chciałbym wiedzieć, czy zastosowane przeze mnie podejście jest uzasadnione.
Mam, że tak powiem, trzech zawodników i chcę sprawdzić ich wyniki za pomocą prostego mnożenia macierzy. Zawodnicy to:
- Numpy, wykorzystując tylko funkcjonalność
dot
. - Python, wywołujący funkcje BLAS-a poprzez wspólny obiekt.
- C ++, wywołując funkcje BLAS-a poprzez wspólny obiekt.
Scenariusz
Zaimplementowałem mnożenie macierzy dla różnych wymiarów i
. i
biegnie od 5 do 500 z przyrostem 5 i matricies m1
i m2
są ustawione w następujący sposób:
m1 = numpy.random.rand(i,i).astype(numpy.float32)
m2 = numpy.random.rand(i,i).astype(numpy.float32)
1. Odrętwiały
Użyty kod wygląda następująco:
tNumpy = timeit.Timer("numpy.dot(m1, m2)", "import numpy; from __main__ import m1, m2")
rNumpy.append((i, tNumpy.repeat(20, 1)))
2. Python, wywołujący BLAS przez wspólny obiekt
Dzięki funkcji
_blaslib = ctypes.cdll.LoadLibrary("libblas.so")
def Mul(m1, m2, i, r):
no_trans = c_char("n")
n = c_int(i)
one = c_float(1.0)
zero = c_float(0.0)
_blaslib.sgemm_(byref(no_trans), byref(no_trans), byref(n), byref(n), byref(n),
byref(one), m1.ctypes.data_as(ctypes.c_void_p), byref(n),
m2.ctypes.data_as(ctypes.c_void_p), byref(n), byref(zero),
r.ctypes.data_as(ctypes.c_void_p), byref(n))
kod testu wygląda następująco:
r = numpy.zeros((i,i), numpy.float32)
tBlas = timeit.Timer("Mul(m1, m2, i, r)", "import numpy; from __main__ import i, m1, m2, r, Mul")
rBlas.append((i, tBlas.repeat(20, 1)))
3. c ++, wywołując BLAS za pośrednictwem udostępnionego obiektu
Teraz kod c ++ jest oczywiście trochę dłuższy, więc ograniczam informacje do minimum.
Ładuję funkcję z
void* handle = dlopen("libblas.so", RTLD_LAZY);
void* Func = dlsym(handle, "sgemm_");
Czas mierzę w gettimeofday
ten sposób:
gettimeofday(&start, NULL);
f(&no_trans, &no_trans, &dim, &dim, &dim, &one, A, &dim, B, &dim, &zero, Return, &dim);
gettimeofday(&end, NULL);
dTimes[j] = CalcTime(start, end);
gdzie j
jest pętla działająca 20 razy. Obliczam upływający czas
double CalcTime(timeval start, timeval end)
{
double factor = 1000000;
return (((double)end.tv_sec) * factor + ((double)end.tv_usec) - (((double)start.tv_sec) * factor + ((double)start.tv_usec))) / factor;
}
Wyniki
Wynik przedstawiono na poniższym wykresie:
pytania
- Czy uważasz, że moje podejście jest sprawiedliwe, czy też są jakieś niepotrzebne koszty ogólne, których mogę uniknąć?
- Czy spodziewałbyś się, że wynik pokaże tak dużą rozbieżność między podejściem C ++ i Python? Obaj używają obiektów współdzielonych do swoich obliczeń.
- Ponieważ wolałbym używać języka Python w moim programie, co mogę zrobić, aby zwiększyć wydajność podczas wywoływania procedur BLAS lub LAPACK?
Pobieranie
Pełny test porównawczy można pobrać tutaj . (JF Sebastian umożliwił ten link ^^)
r
macierzy jest niesprawiedliwa. Właśnie rozwiązuję ten „problem” i publikuję nowe wyniki.np.ascontiguousarray()
(rozważ kolejność C vs. Fortran). 2. upewnij się, żenp.dot()
używa tego samegolibblas.so
.m1
im2
mająascontiguousarray
flagę jakoTrue
. Numpy używa tego samego wspólnego obiektu co C. Co do kolejności tablicy: Obecnie nie interesuje mnie wynik obliczeń stąd kolejność nie ma znaczenia.Odpowiedzi:
Sprawdziłem twój punkt odniesienia . Na moim komputerze nie ma różnicy między C ++ a numpy:
Wydaje się to sprawiedliwe, ponieważ nie ma różnicy w wynikach.
Nie.
Upewnij się, że numpy używa zoptymalizowanej wersji bibliotek BLAS / LAPACK w twoim systemie.
źródło
AKTUALIZACJA (30.07.2014):
Ponownie przeprowadziłem test porównawczy na naszym nowym HPC. Zarówno sprzęt, jak i stos oprogramowania zmieniły się w porównaniu z konfiguracją w oryginalnej odpowiedzi.
Wyniki umieściłem w arkuszu kalkulacyjnym Google (zawiera również wyniki z oryginalnej odpowiedzi).
Sprzęt komputerowy
Nasz HPC ma dwa różne węzły, jeden z procesorami Intel Sandy Bridge, a drugi z nowszymi procesorami Ivy Bridge:
Sandy (MKL, OpenBLAS, ATLAS):
Bluszcz (MKL, OpenBLAS, ATLAS):
Oprogramowanie
Stos oprogramowania jest dla obu węzłów sam. Zamiast GotoBLAS2 , OpenBLAS jest używany i jest również wielowątkowy ATLAS BLAS, która jest ustawiona do 8 nici (stałe).
Benchmark produktów dot
Kod porównawczy jest taki sam jak poniżej. Jednak dla nowych maszyn przeprowadziłem również benchmark dla rozmiarów matryc 5000 i 8000 .
Poniższa tabela zawiera wyniki testu porównawczego z oryginalnej odpowiedzi (nazwa zmieniona: MKL -> Nehalem MKL, Netlib Blas -> Nehalem Netlib BLAS itp.)
Wydajność jednowątkowa:
Wydajność wielowątkowa (8 wątków):
Wątki a rozmiar matrycy (Ivy Bridge MKL) :
Pakiet Benchmark
Wydajność jednowątkowa:
Wydajność wielowątkowa (8 wątków):
Wniosek
Nowe wyniki testu porównawczego są podobne do tych w oryginalnej odpowiedzi. OpenBLAS i MKL działają na tym samym poziomie, z wyjątkiem testu wartości własnej . Test wartości własnej działa dość dobrze na OpenBLAS w trybie jednowątkowym . W trybie wielowątkowym wydajność jest gorsza.
„Rozmiar matrycy vs nici wykres” wskazują także, że chociaż MKL jak OpenBLAS ogólnie skalę oraz z liczbą rdzeni / wątków, zależy od rozmiaru macierzy. W przypadku małych matryc dodanie większej liczby rdzeni nie poprawi zbytnio wydajności.
Występuje również około 30% wzrost wydajności z Sandy Bridge do Ivy Bridge, co może być spowodowane wyższą częstotliwością zegara (+ 0,8 Ghz) i / lub lepszą architekturą.
Oryginalna odpowiedź (04.10.2011):
Jakiś czas temu musiałem zoptymalizować niektóre obliczenia / algorytmy algebry liniowej, które zostały napisane w Pythonie przy użyciu numpy i BLAS, więc przetestowałem / przetestowałem różne konfiguracje numpy / BLAS.
Konkretnie przetestowałem:
Przeprowadziłem dwa różne testy porównawcze:
Oto moje wyniki:
Maszyny
Linux (MKL, ATLAS, No-MKL, GotoBlas2):
Mac Book Pro (Accelerate Framework):
Mac Server (Accelerate Framework):
Benchmark produktowy
Kod :
Wyniki :
Pakiet Benchmark
Kod :
Aby uzyskać dodatkowe informacje na temat zestawu testów, zobacz tutaj .
Wyniki :
Instalacja
Instalacja MKL obejmowała instalację kompletnego pakietu Intel Compiler Suite, co jest dość proste. Jednak z powodu pewnych błędów / problemów konfiguracja i kompilacja numpy z obsługą MKL była trochę kłopotliwa.
GotoBlas2 to mały pakiet, który można łatwo skompilować jako bibliotekę współdzieloną. Jednak z powodu błędu musisz ponownie utworzyć współdzieloną bibliotekę po jej zbudowaniu, aby móc jej używać z numpy.
Oprócz tego budowania go dla wielu platform docelowych nie działał z jakiegoś powodu. Musiałem więc utworzyć plik .so dla każdej platformy, dla której chcę mieć zoptymalizowany plik libgoto2.so .
Jeśli zainstalujesz numpy z repozytorium Ubuntu, automatycznie zainstaluje i skonfiguruje numpy do korzystania z ATLAS . Instalacja ATLAS ze źródła może zająć trochę czasu i wymaga dodatkowych czynności (fortran itp.).
Jeśli zainstalujesz numpy na komputerze z systemem Mac OS X z portami Fink lub Mac , skonfiguruje on numpy do korzystania z ATLAS lub Accelerate Framework firmy Apple . Możesz to sprawdzić, uruchamiając ldd na pliku numpy.core._dotblas lub wywołując numpy.show_config () .
Wnioski
MKL działa najlepiej, tuż za nim znajduje się GotoBlas2 .
W teście wartości własnej GotoBlas2 działa zaskakująco gorzej niż oczekiwano. Nie wiem, dlaczego tak jest.
Accelerate Framework firmy Apple działa naprawdę dobrze, szczególnie w trybie jednowątkowym (w porównaniu z innymi implementacjami BLAS).
Zarówno GotoBlas2, jak i MKL bardzo dobrze skalują się z liczbą wątków. Więc jeśli masz do czynienia z dużymi matrycami, uruchamianie go na wielu wątkach bardzo pomoże.
W każdym razie nie używaj domyślnej implementacji blas Netlib, ponieważ jest ona zbyt wolna, aby wykonać jakąkolwiek poważną pracę obliczeniową.
Na naszym klastrze zainstalowałem również ACML AMD, a wydajność była podobna do MKL i GotoBlas2 . Nie mam żadnych trudnych liczb.
Osobiście poleciłbym użycie GotoBlas2, ponieważ jest łatwiejszy w instalacji i jest darmowy.
Jeśli chcesz kodować w C ++ / C, sprawdź również Eigen3, który w niektórych przypadkach ma przewyższać MKL / GotoBlas2 i jest również dość łatwy w użyciu.
źródło
Oto kolejny test porównawczy (w systemie Linux wystarczy wpisać
make
): http://dl.dropbox.com/u/5453551/blas_call_benchmark.ziphttp://dl.dropbox.com/u/5453551/blas_call_benchmark.png
Nie widzę zasadniczo żadnej różnicy między różnymi metodami dla dużych macierzy, między Numpy, Ctypes i Fortran. (Fortran zamiast C ++ --- i jeśli to ma znaczenie, Twój test porównawczy jest prawdopodobnie uszkodzony).
TwojaByć może twój test porównawczy ma również inne błędy, np. Porównywanie różnych bibliotek BLAS lub różnych ustawień BLAS, takich jak liczba wątków lub między czasem rzeczywistym a czasem procesora?CalcTime
funkcja w C ++ wydaje się mieć błąd znaku.... + ((double)start.tv_usec))
powinno być zamiast tego... - ((double)start.tv_usec))
.EDYCJA : nie udało się policzyć nawiasów klamrowych w
CalcTime
funkcji - jest OK.Wskazówka: jeśli wykonujesz test porównawczy, zawsze umieszczaj gdzieś cały kod. Komentowanie benchmarków, zwłaszcza gdy są zaskakujące, bez pełnego kodu zwykle nie jest produktywne.
Aby dowiedzieć się, z którym BLAS Numpy jest połączony, wykonaj:
AKTUALIZACJA : Jeśli nie możesz zaimportować numpy.core._dotblas, Twój Numpy używa wewnętrznej kopii zapasowej BLAS, która jest wolniejsza i nie jest przeznaczona do obliczeń wydajnościowych! Odpowiedź od @Woltan poniżej wskazuje, że jest to wyjaśnienie różnicy, którą widzi w Numpy vs. Ctypes + BLAS.
Aby naprawić sytuację, potrzebujesz ATLAS lub MKL --- sprawdź te instrukcje: http://scipy.org/Installing_SciPy/Linux Większość dystrybucji Linuksa jest dostarczana z ATLAS, więc najlepszą opcją jest zainstalowanie ich
libatlas-dev
pakietu (nazwa może się różnić) .źródło
import numpy.core._dotblas
. Jaki może być tutaj problem? Spróbuję wyczyścić mój benchmark i napisać plik makefile, aby inni mogli go przetestować.otool -L
zamiastldd
LinuksaBiorąc pod uwagę rygor, jaki wykazałeś w swojej analizie, jestem zaskoczony dotychczasowymi wynikami. Postawiłem to jako „odpowiedź”, ale tylko dlatego, że jest zbyt długa na komentarz i daje taką możliwość (choć spodziewam się, że to rozważyłeś).
Pomyślałbym, że podejście numpy / python nie zwiększyłoby dużo narzutu dla macierzy o rozsądnej złożoności, ponieważ wraz ze wzrostem złożoności proporcja, w której uczestniczy python, powinna być niewielka. Bardziej interesują mnie wyniki po prawej stronie wykresu, ale pokazane tam rozbieżności rzędu wielkości byłyby niepokojące.
Zastanawiam się, czy używasz najlepszych algorytmów, z których może skorzystać Numpy. Z przewodnika po kompilacji dla systemu Linux:
„Build FFTW (3.1.2): SciPy Versions> = 0.7 and Numpy> = 1.2: Ze względu na problemy z licencją, konfiguracją i konserwacją usunięto obsługę FFTW w wersjach SciPy> = 0.7 i NumPy> = 1.2. Zamiast tego używa wbudowana wersja fftpack. Istnieje kilka sposobów, aby skorzystać z szybkości FFTW, jeśli jest to konieczne do przeprowadzenia analizy. Przejdź na wersję Numpy / Scipy, która obejmuje obsługę. Zainstaluj lub utwórz własne opakowanie FFTW. Zobacz http: //developer.berlios.de/projects/pyfftw/ jako niezatwierdzony przykład ”.
Czy skompilowałeś numpy z mkl? ( http://software.intel.com/en-us/articles/intel-mkl/ ). Jeśli używasz Linuksa, instrukcje kompilacji numpy z mkl są tutaj: http://www.scipy.org/Installing_SciPy/Linux#head-7ce43956a69ec51c6f2cedd894a4715d5bfff974 (pomimo adresu URL). Kluczową częścią jest:
Jeśli korzystasz z systemu Windows, możesz pobrać skompilowany plik binarny za pomocą mkl (a także uzyskać pyfftw i wiele innych powiązanych algorytmów) pod adresem : http://www.lfd.uci.edu/~gohlke/pythonlibs/ , z dług wdzięczności wobec Christopha Gohlkego z Laboratorium Dynamiki Fluorescencji, UC Irvine.
Uwaga, w obu przypadkach istnieje wiele problemów związanych z licencjami i tak dalej, o których należy pamiętać, ale strona z informacjami wyjaśnia je. Ponownie, wyobrażam sobie, że rozważałeś to, ale jeśli spełniasz wymagania licencyjne (co w Linuksie jest bardzo łatwe do zrobienia), przyspieszyłoby to znacznie część numpy w porównaniu z użyciem prostej automatycznej kompilacji, nawet bez FFTW. Będę zainteresowany śledzeniem tego wątku i zobaczeniem, co myślą inni. Niezależnie od tego, doskonały rygor i doskonałe pytanie. Dzięki za wysłanie.
źródło