2013-05-23 10 views
5

Konwolucji w Matlab wydaje się być dwa razy szybciej niż splot w Numpy.Czy splot jest wolniejszy w Numpy niż w Matlab?

kod Pythona (trwa 19 sekund w moim urządzenia):

import numpy as np 
from scipy import ndimage 
import time 

img = np.ones((512,512,512)) 
kernel = np.ones((5,5,5))/125 

start_time = time.time() 
ndimage.convolve(img,kernel,mode='constant') 
print "Numpy execution took ", (time.time() - start_time), "seconds" 

kod Matlab (trwa 8,7 sekundy w moim urządzenia):

img = ones(512,512,512); 
kernel = ones(5,5,5)/125; 
tic 
convn(img, kernel, 'same'); 
toc 

Oba dają identyczne wyniki.

Czy istnieje sposób na poprawę Numpy, aby dopasować lub pokonać wydajność Matlaba tutaj?

Co ciekawe, ten współczynnik lub ~ 2 różnica w czasie wykonywania jest stała przy wielu wejściach.

+0

To nie jest tak naprawdę wydajność Pythona, o której tu chodzi, ale NumPy/SciPy. Czy możesz poprawić wydajność tych modułów? Oczywiście, ale nie poprzez pisanie kodu Pythona. – kindall

+0

Edytowane (s/Python/Numpy /). – naroom

+2

Możesz sprawdzić, jakie biblioteki buduje numpy w porównaniu z vs matlab. Z własnego doświadczenia wiem, że gdy numpy zostanie zbudowana na bazie biblioteki MKL Intela, uzyskuję znacznie lepszą wydajność w przypadku niektórych operacji niż przy domyślnych ustawieniach. – JoshAdel

Odpowiedz

3

Nie anwer; tylko komentarz:

Przed porównać wydajność, trzeba upewnić się, że te dwie funkcje są wraca ten sam wynik:

Jeśli convn MATLAB wraca ten sam rezultat jak convn oktawy, a następnie convn jest inna niż ndimage.convolve:

octave> convn(ones(3,3), ones(2,2)) 
ans = 

    1 2 2 1 
    2 4 4 2 
    2 4 4 2 
    1 2 2 1 

In [99]: ndimage.convolve(np.ones((3,3)), np.ones((2,2))) 
Out[99]: 
array([[ 4., 4., 4.], 
     [ 4., 4., 4.], 
     [ 4., 4., 4.]]) 

ndimage.convolve ma innych trybach 'reflect','constant','nearest','mirror', 'wrap', ale żaden ("full") zachowania te mecze convn „s domyślny.


Na tablicach 2D scipy.signal.convolve2d jest szybszy niż scipy.signal.convolve.

Dla tablic 3D scipy.signal.convolve wydaje się mieć takie samo zachowanie jak convn(A,B):

octave> x = convn(ones(3,3,3), ones(2,2,2)) 
x = 

ans(:,:,1) = 

    1 2 2 1 
    2 4 4 2 
    2 4 4 2 
    1 2 2 1 

ans(:,:,2) = 

    2 4 4 2 
    4 8 8 4 
    4 8 8 4 
    2 4 4 2 

ans(:,:,3) = 

    2 4 4 2 
    4 8 8 4 
    4 8 8 4 
    2 4 4 2 

ans(:,:,4) = 

    1 2 2 1 
    2 4 4 2 
    2 4 4 2 
    1 2 2 1 

In [109]: signal.convolve(np.ones((3,3,3), dtype='uint8'), np.ones((2,2,2), dtype='uint8')) 
Out[109]: 
array([[[1, 2, 2, 1], 
     [2, 4, 4, 2], 
     [2, 4, 4, 2], 
     [1, 2, 2, 1]], 

     [[2, 4, 4, 2], 
     [4, 8, 8, 4], 
     [4, 8, 8, 4], 
     [2, 4, 4, 2]], 

     [[2, 4, 4, 2], 
     [4, 8, 8, 4], 
     [4, 8, 8, 4], 
     [2, 4, 4, 2]], 

     [[1, 2, 2, 1], 
     [2, 4, 4, 2], 
     [2, 4, 4, 2], 
     [1, 2, 2, 1]]], dtype=uint8) 

Zauważ, że np.ones((n,m,p)) tworzy pływaka tablicę domyślnie. Matlab ones(n,m,p) wydaje się tworzyć tablicę intów. Aby dokonać dobrego porównania, powinieneś spróbować dopasować typ dtype z tablic numpy do typu macierzy Matlaba.

+1

Na marginesie, 'scipy.signal.convolve2d' domyślnie działa tak samo jak" konwój "matlab/oktawy. W 'scipy.signal',' tryb' kwarg steruje rozmiarem wyniku (podobnie jak w 'conv'a matlaba), natomiast w' ndimage', 'mode' kwarg (głównie) kontroluje warunki brzegowe. Jest to konwencja nazewnictwa, która prowadzi do wielu nieporozumień przy porównywaniu rzeczy ... –

+0

Te z Matlab() tworzą matrycę podwójną, więc typy faktycznie pasują. – naroom

+1

@naroom - Jeśli jednak nie potrzebujesz pływaków, użycie ints da w tym przypadku przyspieszenie ~ 20x. –

8

Jaką dokładnie operację wykonujesz? Istnieje wiele optymalizacji, które zapewnia ndimage, jeśli nie potrzebujesz ogólnego splotu N-d.

Na przykład, aktualna praca:

img = np.ones((512,512,512)) 
kernel = np.ones((5,5,5))/125 
result = ndimage.convolve(img, kernel) 

odpowiada:

img = np.ones((512,512,512)) 
result = ndimage.uniform_filter(img, 5) 

Istnieje jednak duża różnica w szybkości wykonania:

In [22]: %timeit ndimage.convolve(img, kernel) 
1 loops, best of 3: 25.9 s per loop 

In [23]: %timeit ndimage.uniform_filter(img, 5) 
1 loops, best of 3: 8.69 s per loop 

Różnica jest spowodowana przez uniform_filter preforming 1-d splotu wzdłuż każdej osi, zamiast ogólnej 3 D splot.

W przypadkach, w których jądro jest symetryczne, można wprowadzić te uproszczenia i uzyskać znaczące przyspieszenie.

Nie mam pewności co do convn, ale często funkcje Matlaba powodują, że tego rodzaju optymalizacje odbywają się za kulisami, jeśli dane wejściowe pasują do określonych kryteriów. Scipy częściej korzysta z jednego algorytmu na funkcję i oczekuje, że użytkownik dowie się, który z nich wybrać w danym przypadku.


Wspomniałeś filtr "Laplacian of Gaussian". Zawsze mam tutaj pojęcie mylące z terminologią.

myślę, co chcesz pod względem ndimage funkcji jest albo scipy.ndimage.gaussian_laplace lub scipy.ndimage.gaussian_filter z order=2 (który filtruje przez drugą pochodną Gaussa).

W każdym razie oba uproszczają operację do 1-d splotu na każdą oś, co powinno dać znaczące (2-3x) przyspieszenie.

+2

Dobra myśl! Pracuję nad problemem segmentacji 3D, więc filtrem, który naprawdę muszę uruchomić, jest 3D Laplacian z Gaussian (AKA Mexican Hat). Zastępowanie jądra Matlaba za pomocą 'kernel = rand (5,5,5);' nie zmieniło jednak czasu jego wykonania, więc nie sądzę, że Matlab oszukuje tutaj :) – naroom

+0

Ach, tak, myślę, że matlab nie jest "oszustwo", a następnie! :) –

+0

Myślę, że chcesz 'scipy.ndimage.gaussian_laplace', ale nie jestem w 100% pewny ... Zawsze mylę się trochę z różnicami pomiędzy różnymi filtrami krawędzi. Mam nadzieję, że sugestia pomaga trochę, w każdym razie! –

Powiązane problemy