के लिए NumPy फ़ंक्शन की मेमोरी खपत मैं वर्तमान में काफी बड़े रास्टर डेटा सेट (> 4 जीबी) पर काम करने के लिए जीडीएएल की पायथन बाइंडिंग का उपयोग कर रहा हूं। चूंकि उन्हें एक बार में स्मृति में लोड करना मेरे लिए कोई व्यवहार्य समाधान नहीं है, इसलिए मैं उन्हें छोटे ब्लॉक में पढ़ता हूं और टुकड़े टुकड़े टुकड़े टुकड़े करता हूं। प्रत्येक ब्लॉक पढ़ने के लिए एक नए आवंटन से बचने के लिए मैं buf_obj
तर्क (here) का उपयोग कर रहा हूं ताकि मूल्यों को एक पूर्ववर्ती NumPy सरणी में पढ़ा जा सके। एक बिंदु पर मुझे पूरे रास्टर के औसत और मानक विचलन की गणना करना है। स्वाभाविक रूप से मैंने गणना के लिए np.std
का उपयोग किया है। हालांकि मेरे कार्यक्रम की स्मृति खपत को प्रोफाइल करके मुझे एहसास हुआ कि np.std
के प्रत्येक आमंत्रण के साथ अतिरिक्त स्मृति आवंटित और जारी की गई है।मानक विचलन
एक न्यूनतम काम कर उदाहरण जो इस व्यवहार को दर्शाता है:
In [1] import numpy as np
In [2] a = np.random.rand(20e6) # Approx. 150 MiB of memory
In [3] %memit np.mean(a)
peak memory: 187.30 MiB, increment: 0.48 MiB
In [4] %memit np.std(a)
peak memory: 340.24 MiB, increment: 152.91 MiB
NumPy GitHub पर के स्रोत वृक्ष के भीतर तलाशी में पता चला है कि np.std
समारोह आंतरिक _methods.py
(here) से _var
समारोह का आह्वान। एक बिंदु पर _var
माध्य से विचलन की गणना करता है और उन्हें बताता है। इसलिए इनपुट सरणी की एक अस्थायी प्रति बनाई गई है। इस प्रकार समारोह अनिवार्य रूप से मानक विचलन की गणना करता है:
mu = sum(arr)/len(arr)
tmp = arr - mu
tmp = tmp * tmp
sd = np.sum(tmp)/len(arr)
हालांकि यह दृष्टिकोण छोटे इनपुट सरणियों के लिए ठीक है यह निश्चित रूप से बड़े लोगों के लिए जाने के लिए कोई रास्ता नहीं है। चूंकि मैं इस अतिरिक्त प्रतिलिपि से पहले बताई गई स्मृति के छोटे ब्लॉक का उपयोग कर रहा हूं, मेरे प्रोग्राम में स्मृति बिंदु से गेम ब्रेकिंग समस्या नहीं है। हालांकि मुझे क्या बग है कि प्रत्येक ब्लॉक के लिए अगला ब्लॉक पढ़ने से पहले एक नया आवंटन किया जाता है और जारी किया जाता है।
क्या न्यूमपी या साइपीपी के भीतर कोई अन्य फ़ंक्शन है जो वेल्फोर्ड एल्गोरिदम (Wikipedia) जैसे निरंतर स्मृति खपत के साथ औसत और मानक विचलन की एक पास गणना के लिए अपर्याप्तता का उपयोग करता है?
जाने का एक और तरीका _var
फ़ंक्शन का एक कस्टम संस्करण लागू करने के लिए एक वैकल्पिक out
एक पूर्ववर्ती बफर (जैसे NumPy ufuncs) के लिए तर्क होगा। इस दृष्टिकोण के साथ अतिरिक्त प्रति को समाप्त नहीं किया जाएगा, लेकिन कम से कम स्मृति खपत स्थिर रहेगी और प्रत्येक ब्लॉक में आवंटन के लिए रनटाइम बचाया जाएगा।
संपादित करें: वेज़ोस द्वारा सुझाए गए वेलफोर्ड एल्गोरिदम के साइथन कार्यान्वयन का परीक्षण किया गया।
Cython कार्यान्वयन (kezzos से संशोधित):
cimport cython
cimport numpy as np
from libc.math cimport sqrt
@cython.boundscheck(False)
def iterative_approach(np.ndarray[np.float32_t, ndim=1] a):
cdef long n = 0
cdef float mean = 0
cdef float M2 = 0
cdef long i
cdef float delta
cdef float a_min = 10000000 # Must be set to Inf and -Inf for real cases
cdef float a_max = -10000000
for i in range(len(a)):
n += 1
delta = a[i] - mean
mean += delta/n
M2 += delta * (a[i] - mean)
if a[i] < a_min:
a_min = a[i]
if a[i] > a_max:
a_max = a[i]
return a_min, a_max, mean, sqrt(M2/(n - 1))
NumPy कार्यान्वयन (मतलब और एसटीडी संभवतः एक समारोह में गणना की जा सकती):
def vector_approach(a):
return np.min(a), np.max(a), np.mean(a), np.std(a, ddof=1)
टेस्ट एक यादृच्छिक डेटा सेट का उपयोग कर परिणाम (बार मिलीसेकंड में, 25 में से सर्वश्रेष्ठ):
----------------------------------
| Size | Iterative | Vector |
----------------------------------
| 1e2 | 0.00529 | 0.17149 |
| 1e3 | 0.02027 | 0.16856 |
| 1e4 | 0.17850 | 0.23069 |
| 1e5 | 1.93980 | 0.77727 |
| 1e6 | 18.78207 | 8.83245 |
| 1e7 | 180.04069 | 101.14722 |
| 1e8 | 1789.60228 | 1086.66737 |
----------------------------------
ऐसा लगता है कि यह पुनरावर्तक है 10000+ तत्वों के साथ बड़े डेटा सेट के लिए छोटे डेटा सेट और न्यूमपी वेक्टर (संभवतः सिम त्वरित) दृष्टिकोण के साथ साइथन का उपयोग करके पिप्रोच तेज है। सभी परीक्षण पायथन 2.7.9 और न्यूपी संस्करण 1.9.2 के साथ किए गए थे।
ध्यान दें कि वास्तविक मामले में ऊपरी कार्यों में रास्टर के एक ब्लॉक के आंकड़ों की गणना करने के लिए उपयोग किया जाएगा।सभी ब्लॉक के लिए मानक विचलन और साधन विकिपीडिया (here) में सुझाई गई पद्धति के साथ संयुक्त किए जाने हैं। इसका लाभ यह है कि रास्टर के सभी तत्वों को सारांशित करने की आवश्यकता नहीं है और इस तरह फ्लोट ओवरफ्लो समस्या से बचा जाता है (कम से कम किसी बिंदु पर)।
क्या आपने बफर ऑब्जेक्ट पर वेल्फोर्ड एल्गोरिदम (शुद्ध पायथन में) का उपयोग करने का प्रयास किया है? – kezzos
@kezzos मैंने शुद्ध पायथन कार्यान्वयन के लिए परीक्षण परिणामों के साथ प्रश्न अद्यतन किया है। पाइथन कार्यान्वयन NumPy संस्करण की तुलना में काफी धीमी है। – Stefan