2013-05-23 5 views
5

Matlab में कनवॉल्यूशन Numpy में दृढ़ता के रूप में दोगुनी तेजी से प्रतीत होता है।Matlab की तुलना में Numpy में संकल्प धीमा है?

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" 

मैटलैब कोड (मेरी मशीन पर 8.7 सेकंड लेता है):

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

दो समान परिणाम दे

अजगर कोड (मेरी मशीन पर 19 सेकंड लेता है)।

क्या मैटलैब के प्रदर्शन से मेल खाने या हरा करने के लिए नम्पी सुधारने का कोई तरीका है?

दिलचस्प बात यह है कि रनटाइम्स में यह कारक या ~ 2 अंतर कई इनपुट आकारों में सुसंगत है।

+0

यह वास्तव में पाइथन का प्रदर्शन नहीं है, आप यहां समय दे रहे हैं, लेकिन न्यूपी/साइपी। क्या आप उन मॉड्यूल के प्रदर्शन में सुधार कर सकते हैं? निश्चित रूप से, लेकिन पायथन कोड लिखकर नहीं। – kindall

+0

संपादित (एस/पायथन/न्यूम्पी /)। – naroom

+2

आप देख सकते हैं कि बनाम matlab के खिलाफ क्या पुस्तकालय numpy बनाया गया है। मुझे व्यक्तिगत अनुभव से पता है कि जब इंटेल की एमकेएल लाइब्रेरी के खिलाफ numpy बनाया गया है, तो मुझे डिफ़ॉल्ट के मुकाबले कुछ परिचालनों के लिए बेहतर प्रदर्शन मिलता है। – JoshAdel

उत्तर

3

कोई एवर नहीं; बस एक टिप्पणी:

इससे पहले कि आप प्रदर्शन की तुलना, आप सुनिश्चित दो कार्य एक ही परिणाम लौट रहे हैं बनाने की जरूरत है:

मैटलैब का convn, सप्टक के convn रूप में एक ही परिणाम देता है तो convnndimage.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 अन्य साधनों, 'reflect','constant','nearest','mirror', 'wrap', लेकिन इन मैच convn के डिफ़ॉल्ट ("पूर्ण") व्यवहार से कोई भी नहीं है।


2 डी सरणियों के लिए, scipy.signal.convolve2dscipy.signal.convolve से तेज है।

3 डी सरणियों के लिए, scipy.signal.convolveconvn(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) 

ध्यान दें कि np.ones((n,m,p)) डिफ़ॉल्ट रूप से एक नाव सरणी पैदा करता है। Matlab ones(n,m,p) इन्स की एक सरणी बनाने के लिए प्रतीत होता है। अच्छी तुलना करने के लिए, आपको मैटलैब मैट्रिस के प्रकार के लिए numpy arrays के dtype से मिलान करने का प्रयास करना चाहिए।

+1

बस एक तरफ नोट पर, 'scipy.signal.convolve2d' matlab/octave के 'conv' के समान व्यवहार के लिए डिफ़ॉल्ट है। 'Scipy.signal' में, 'मोड' kwarg परिणाम के आकार को नियंत्रित करता है (matlab के' conv' के समान), जबकि 'ndimage' में,' मोड' kwarg (ज्यादातर) सीमा की स्थिति को नियंत्रित करता है। यह एक नामकरण सम्मेलन है जो चीजों की तुलना करते समय बहुत भ्रम पैदा करता है ... –

+0

मैटलैब के() युगल का मैट्रिक्स बनाता है, इसलिए वास्तव में प्रकार मेल खाते हैं। – naroom

+1

@ नारूम - फिर भी, अगर आपको फ्लोट की आवश्यकता नहीं है, तो इन्सट्स का उपयोग करके इस मामले में ~ 20x स्पीडअप मिलेगा। –

8

आप क्या सटीक संचालन कर रहे हैं? ऐसे कई अनुकूलन हैं जो ndimage प्रदान करते हैं यदि आपको सामान्य एन-डी संकल्प की आवश्यकता नहीं है।

उदाहरण के लिए, अपने वर्तमान आपरेशन:

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

के बराबर है:

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 

अंतर के कारण होता है:

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

हालांकि, वहाँ निष्पादन की गति में एक बड़े अंतर है uniform_filter द्वारा प्रत्येक अक्ष के साथ 1-डी रूपांतरण को पूर्ववर्ती करने के बजाय, सामान्य 3 डी संकल्प।

ऐसे मामलों में जहां कर्नेल सममित है, आप इन सरलीकरण को बना सकते हैं और एक महत्वपूर्ण गति प्राप्त कर सकते हैं।

मुझे convn के बारे में निश्चित नहीं है, लेकिन अक्सर आपके इनपुट डेटा कुछ मानदंडों से मेल खाते हैं तो मैटलैब के फ़ंक्शन इस तरह के अनुकूलन को पीछे-दृश्य बनाते हैं। Scipy अधिक आम तौर पर एक-एल्गोरिदम-प्रति-फ़ंक्शन का उपयोग करता है, और उम्मीद करता है कि उपयोगकर्ता को यह पता चल जाएगा कि किस मामले में कौन सा चयन करना है।


आपने "गॉसियन के लैपलासीन" फ़िल्टर का उल्लेख किया है। मैं हमेशा शब्दावली के साथ उलझन में एक स्पर्श मिलता है।

मुझे लगता है कि तुम क्या ndimage कार्यों के मामले में चाहते हैं या तो scipy.ndimage.gaussian_laplace या order=2 साथ scipy.ndimage.gaussian_filter (जो गाऊसी का दूसरा व्युत्पन्न द्वारा फिल्टर) है।

किसी भी दर पर, ऑपरेशन को प्रत्येक अक्ष पर 1-डी रूपांतरण के लिए सरल बनाते हैं, जो एक महत्वपूर्ण (2-3x) गति प्रदान करना चाहिए।

+2

अच्छा विचार! मैं एक 3 डी सेगमेंटेशन समस्या पर काम कर रहा हूं, इसलिए मुझे जिस फ़िल्टर को वास्तव में चलाने की ज़रूरत है वह गॉसियन (एकेए मैक्सिकन हैट) का 3 डी लैपलासीन है। मैटलैब के कर्नेल को 'कर्नेल = रैंड (5,5,5) के साथ बदलना; 'इसके निष्पादन समय को नहीं बदला, हालांकि, मुझे नहीं लगता कि मैटलैब यहाँ धोखा दे रहा है :) – naroom

+0

आह, हाँ, मुझे लगता है कि matlab नहीं है "धोखाधड़ी", तो! :) –

+0

मुझे लगता है कि आप 'scipy.ndimage.gaussian_laplace' चाहते हैं, लेकिन मैं 100% निश्चित नहीं हूं ... मैं हमेशा विभिन्न एज फ़िल्टरों के बीच अंतर के साथ थोड़ा उलझन में पड़ता हूं। उम्मीद है कि सुझाव किसी भी दर पर थोड़ा सा मदद करता है! –

संबंधित मुद्दे