2015-05-25 9 views
15

मैं सबसे स्मृति-कारगर तरीका एक जटिल numpy ndarrayअधिकांश स्मृति-कारगर तरीका

arr = np.empty((250000, 150), dtype='complex128') # common size 
का पूर्ण वर्ग मूल्य की गणना करने के लिए देख रहा हूँ

मुझे एक ufunc नहीं मिला है जो वास्तव में np.abs()**2 करेगा।

उस आकार और प्रकार की एक सरणी के रूप में लगभग आधा जीबी लगता है, मैं मुख्य रूप से स्मृति-कुशल तरीके की तलाश में हूं।

मैं इसे पोर्टेबल भी पसंद करूंगा, इसलिए आदर्श रूप से यूफुनक्स का कुछ संयोजन।

अब तक मेरी समझ है कि इस यह बेकार की गणना के बारे में सबसे अच्छा

result = np.abs(arr) 
result **= 2 

(**0.5)**2 होना चाहिए, लेकिन यथा-स्थान **2 गणना करना चाहिए। कुल मिलाकर शीर्ष स्मृति आवश्यकता केवल मूल सरणी आकार + परिणाम सरणी आकार है, जो 1.5 * मूल सरणी आकार होना चाहिए क्योंकि परिणाम वास्तविक है।

अगर मैं बेकार **2 कॉल से छुटकारा प्राप्त करना चाहता था कि मैं इस

result = arr.real**2 
result += arr.imag**2 

की तरह कुछ करने के लिए होगा लेकिन अगर मैं गलत नहीं हूँ, यह मैं के लिए स्मृति को आबंटित करने का मतलब होगा वास्तविक और काल्पनिक भाग गणना दोनों, इसलिए शीर्ष स्मृति उपयोग 2.0 * मूल सरणी आकार होगा। arr.real गुण भी एक गैर-संगत सरणी लौटाते हैं (लेकिन यह कम चिंता का विषय है)।

क्या मुझे कुछ भी याद आ रही है? क्या ऐसा करने के कोई बेहतर तरीके हैं?

संपादित करें 1: मैं यह स्पष्ट नहीं बनाने के लिए माफी चाहता हूँ, मैं आगमन के ऊपर लिख नहीं करना चाहते, तो मैं यह के रूप में बाहर का उपयोग नहीं कर सकते हैं।

उत्तर

4

धन्यवाद numba.vectorize करने के लिए numba के हाल के संस्करण, कार्य के लिए एक numpy सार्वभौमिक कार्य बनाने बहुत आसान है:

@numba.vectorize([numba.float64(numba.complex128),numba.float32(numba.complex64)]) 
def abs2(x): 
    return x.real**2 + x.imag**2 

मेरी मशीन पर, मैं एक तीन गुना speedup कि मध्यवर्ती सरणियों बनाता है एक शुद्ध-numpy संस्करण की तुलना में लगता है:

>>> x = np.random.randn(10000).view('c16') 
>>> y = abs2(x) 
>>> np.all(y == x.real**2 + x.imag**2) # exactly equal, being the same operation 
True 
>>> %timeit np.abs(x)**2 
10000 loops, best of 3: 81.4 µs per loop 
>>> %timeit x.real**2 + x.imag**2 
100000 loops, best of 3: 12.7 µs per loop 
>>> %timeit abs2(x) 
100000 loops, best of 3: 4.6 µs per loop 
+0

मैं इसे एक उत्तर के रूप में स्वीकार करना चाहता हूं, लेकिन मुझे यकीन नहीं है कि यह पोर्टेबल कितना है। अधिकांश मशीनों पर एनाकोंडा के साथ इन दिनों इंस्टॉल करने के लिए नुम्बा बहुत आसान है, लेकिन मुझे यकीन नहीं है कि आर्किटेक्चर में वास्तविक एलएलवीएम बाइंडिंग कितने पोर्टेबल हैं। शायद आप इस उत्तर की पोर्टेबिलिटी के बारे में कुछ जानकारी जोड़ सकते हैं। –

+0

ठीक है, मैं एलएलवीएम विशेषज्ञ हूं, लेकिन वर्तमान संस्करण (0.31.0) का दस्तावेज कहता है: समर्थित लिनक्स, विंडोज 7 और ओएस एक्स 10.9 और बाद में हैं। – burnpanck

1

arr.real और arr.imag केवल जटिल सरणी में दृश्य हैं। तो कोई अतिरिक्त मेमोरी आवंटित नहीं है।

+2

लेकिन यह आवंटित किया जाता है जब मैं 'गणना arr.real ** 2'। –

1

यदि आपका प्राथमिक लक्ष्य स्मृति को संरक्षित करना है, तो NumPy के ufuncs एक वैकल्पिक out पैरामीटर लेते हैं जो आपको आउटपुट को आपके चयन की सरणी में निर्देशित करने देता है। जब आप संचालन करना चाहते हैं तो यह उपयोगी हो सकता है।

आप अपनी पहली विधि को यह मामूली संशोधन करना है, तो आप आपरेशन arr पर पूरी तरह से जगह में प्रदर्शन कर सकते हैं:

np.abs(arr, out=arr) 
arr **= 2 

एक जटिल तरीका है कि केवल एक थोड़ा अतिरिक्त सकता है स्मृति का उपयोग करता है arr को जगह में संशोधित करने के लिए, वास्तविक मानों की नई सरणी की गणना करें और फिर arr को पुनर्स्थापित करें।

इसका मतलब है संकेतों के बारे में जानकारी संग्रहीत करना (जब तक कि आप नहीं जानते कि आपके जटिल संख्याओं में सकारात्मक वास्तविक और काल्पनिक भाग हैं)। प्रत्येक वास्तविक या काल्पनिक मूल्य के संकेत के लिए केवल एक बिट की आवश्यकता होती है, इसलिए यह 1/16 + 1/16 == 1/8arr की स्मृति (आपके द्वारा बनाए गए फ्लोट की नई सरणी के अतिरिक्त) का उपयोग करता है।

>>> signs_real = np.signbit(arr.real) # store information about the signs 
>>> signs_imag = np.signbit(arr.imag) 
>>> arr.real **= 2 # square the real and imaginary values 
>>> arr.imag **= 2 
>>> result = arr.real + arr.imag 
>>> arr.real **= 0.5 # positive square roots of real and imaginary values 
>>> arr.imag **= 0.5 
>>> arr.real[signs_real] *= -1 # restore the signs of the real and imagary values 
>>> arr.imag[signs_imag] *= -1 

भंडारण signbits की कीमत पर, arr अपरिवर्तित है और result मूल्यों हम चाहते हैं रखती है।

+0

धन्यवाद, हालांकि, मैं एआर ओवरराइट नहीं करना चाहता, क्षमा करने के लिए खेद है। –

+0

मैं देखता हूं ... मैं वही करने के लिए किसी भी तरह से नहीं सोच सकता जो आप चाहते हैं (ए) 'एआर' को संरक्षित करता है, और (बी) फ्लोट वैल्यू की केवल एक नई सरणी आवंटित करता है (उसी आकार के' arr 'के रूप में)। एक कस्टम ufunc की आवश्यकता हो सकती है (लेकिन यह पोर्टेबिलिटी को प्रभावित कर सकता है)। –

+0

आपके संक्षिप्त उदाहरण के लिए धन्यवाद। मुझे numexpr का उपयोग करना समाप्त हो सकता है। –

0

संपादित करें: इस समाधान में न्यूनतम स्मृति आवश्यकता दो गुना है, और यह मामूली तेज़ी से है। टिप्पणियों में चर्चा हालांकि संदर्भ के लिए अच्छा है।

यहाँ एक तेजी से समाधान है, परिणाम res में संग्रहीत के साथ:

import numpy as np 
res = arr.conjugate() 
np.multiply(arr,res,out=res) 

जहाँ हम यानी एक जटिल संख्या के पेट की संपत्ति, abs(z) = sqrt(z*z.conjugate) शोषण, ताकि abs(z)**2 = z*z.conjugate

+0

मैं इसके बारे में भी सोच रहा था, लेकिन इसमें समस्या है कि परिणाम अभी भी जटिल है। इसके अतिरिक्त, शीर्ष स्मृति खपत 2.0 * मूल सरणी आकार है। मैं बस वास्तविक भाग ले सकता हूं (क्योंकि कल्पना भाग 0 के बहुत करीब होना चाहिए), लेकिन इससे या तो पीक मेमोरी खपत में वृद्धि होगी या मुझे एक गैर-संगत सरणी दी जाएगी। साथ ही, जटिल संख्याओं के गुणा से कई अनावश्यक गुणाएं और परिवर्धन निष्पादित किए जाएंगे जिन्हें हम पहले से जानते हैं कि इसका कोई उपयोग नहीं है (क्योंकि वे 0 तक रद्द होते हैं)। –

+0

1) परिणाम वास्तविक मूल्यवान है, एक जटिल 'dtype' के साथ, जो अलग है; 2) स्मृति खपत दो बार नहीं है, हम केवल 'res' के लिए आवंटित करते हैं, जो अपरिहार्य है, और फिर 'गुणा() 'के लिए' आउट' का उपयोग करें; 3) ध्यान दें कि 'सभी (res.imag == 0) -> True', ताकि कोई काल्पनिक हिस्सा न हो; 4) आप जटिल वास्तविक जटिलता के बारे में 4 असली वास्तविक गुणों के रूप में नहीं सोच सकते हैं और निष्कर्ष निकाल सकते हैं कि समय लेने वाली गणनाएं हैं। कोड 'abs()' का उपयोग करके तेज़ है और यह पूछा जाता है। यदि आपको आश्चर्य है कि ऐसा क्यों है, तो यह संभवतः CPU संख्या जटिल संख्या गुणा को लागू करने के लिए उबलता है – gg349

+0

भले ही यह वास्तविक मूल्यवान (सिद्धांत रूप में) है, फिर भी यह सभी शून्य काल्पनिक भागों के लिए स्मृति लेता है। मैं इस बारे में बात कर रहा था कि अंतिम (असली) परिणाम प्राप्त करने के लिए मुझे कितनी मेमोरी चाहिए, मुझे लगता है कि मैं नहीं हूं एआर ओवरराइट करना चाहते हैं। न्यूनतम 1.5 * एआर आकार है। आपका सुझाव 2.0 है, क्योंकि यह शून्य काल्पनिक भागों के लिए भी स्मृति लेता है। सीपीयू ऑप्टिमाइज़ेशन पर निर्भर करना बहुत पोर्टेबल नहीं है (हालांकि पीसी को ढूंढना मुश्किल होगा जिसमें इन दिनों थीम नहीं होगी)। –

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