2016-04-01 11 views
9

Mam wąskie gardło wydajności. Obliczam kolumnową średnią dużych tablic (250 wierszy & 1,3 miliona kolumn), a robię to ponad milion razy w mojej aplikacji.Wysoka wydajność macierzy średniej

Mój przypadek testowy w Pythonie:

import numpy as np 
big_array = np.random.random((250, 1300000)) 
%timeit mean = big_array.mean(axis = 0) # ~400 milliseconds 

Numpy zajmuje około 400 milisekund na moim komputerze, działa na jednym rdzeniu. Wypróbowałem kilka innych bibliotek macierzy w różnych językach (Cython, R, Julia, Torch), ale znalazłem tylko Julię, która pokonała Numpy, biorąc około 250 milisekund.

Czy ktokolwiek może udowodnić znaczącą poprawę wydajności w tym zadaniu? Być może jest to zadanie odpowiednie dla GPU?

Edycja: Moja aplikacja jest najwyraźniej ograniczona do pamięci, a jej wydajność znacznie się poprawia, uzyskując dostęp do elementów dużej tablicy tylko raz, a nie wielokrotnie. (Patrz komentarz poniżej).

+1

To obliczenie prawdopodobnie bardziej dotyczy dostępu do pamięci niż pracy procesora. Nie spodziewałbym się, że jakikolwiek system znacząco poprawi się w tym miejscu. Moją intuicją jest to, że używanie wielu rdzeni lub procesorów graficznych nie byłoby zbyt użyteczne. Pomocne może być jednak ograniczenie do float32. – MRocklin

+0

Przypadek testowy mógł być zbyt prosty. Mój typ tablicy będzie faktycznie boolean, więc każdy element jest przechowywany jako bajt z Numpy. Paradoksalnie, uzyskanie wartości średniej lub sumy dla tablicy boolowskiej zajmuje więcej czasu niż w przypadku elementów pływających, jak w przykładzie. Każdy pomysł, jak wykonać operację na macierzy bitpakowanej, co zmniejszy ruch pamięci o ~ 90%? –

+0

W mojej konkretnej aplikacji biorę średnią tablic, które są podzbiorami 250 wierszy z tablicy o liczbie 22000 wierszy. Pamięć uzyskuje dostęp tylko do 24 godzin na całe obliczenia. Jeśli jednak operuję na większej macierzy i dotykam każdego elementu tylko raz, pamięć uzyskuje dostęp do mniej niż 10 sekund. Muszę to wypróbować! Dzięki @MRocklin za wskazanie wąskiego gardła. –

Odpowiedz

9

Julia, jeśli się nie mylę, używa forteli w pamięci, a nie numpy, która domyślnie używa układu pamięci C. Więc jeśli zmienić rzeczy do przestrzegania tego samego układu tak, że średnia dzieje się wzdłuż pamięci ciągłej, można uzyskać lepszą wydajność:

In [1]: import numpy as np 

In [2]: big_array = np.random.random((250, 1300000)) 

In [4]: big_array_f = np.asfortranarray(big_array) 

In [5]: %timeit mean = big_array.mean(axis = 0) 
1 loop, best of 3: 319 ms per loop 

In [6]: %timeit mean = big_array_f.mean(axis = 0) 
1 loop, best of 3: 205 ms per loop 

Albo można po prostu zmienić Cię wymiary i wziąć średnią na drugiej osi:

In [10]: big_array = np.random.random((1300000, 250)) 

In [11]: %timeit mean = big_array.mean(axis = 1) 
1 loop, best of 3: 205 ms per loop 
+0

Na moim komputerze synchronizacja jest odwrotna: W [56]:% timeit big_array.mean (0) -> 705 ms na pętlę; In [57]:% timeit big_arrayf.mean (0) -> 1201 ms na pętlę; Masz jakiś pomysł? –

Powiązane problemy