मान लीजिए कि हम np.dot
दो 'float32'
2D सरणियाँ लेते हैं:
res = np.dot(a, b) # see CASE 1
print(list(res[0])) # list shows more digits
[-0.90448684, -1.1708503, 0.907136, 3.5594249, 1.1374011, -1.3826287]
नंबर। सिवाय, वे बदल सकते हैं:
मामला 1 : टुकड़ाa
np.random.seed(1)
a = np.random.randn(9, 6).astype('float32')
b = np.random.randn(6, 6).astype('float32')
for i in range(1, len(a)):
print(list(np.dot(a[:i], b)[0])) # full shape: (i, 6)
[-0.9044868, -1.1708502, 0.90713596, 3.5594249, 1.1374012, -1.3826287]
[-0.90448684, -1.1708503, 0.9071359, 3.5594249, 1.1374011, -1.3826288]
[-0.90448684, -1.1708503, 0.9071359, 3.5594249, 1.1374011, -1.3826288]
[-0.90448684, -1.1708503, 0.907136, 3.5594249, 1.1374011, -1.3826287]
[-0.90448684, -1.1708503, 0.907136, 3.5594249, 1.1374011, -1.3826287]
[-0.90448684, -1.1708503, 0.907136, 3.5594249, 1.1374011, -1.3826287]
[-0.90448684, -1.1708503, 0.907136, 3.5594249, 1.1374011, -1.3826287]
[-0.90448684, -1.1708503, 0.907136, 3.5594249, 1.1374011, -1.3826287]
परिणाम भिन्न होते हैं, भले ही मुद्रित स्लाइस ठीक उसी संख्या से गुणा किया जाता है।
मामला 2 : समतल करें
a
, 1D संस्करण लें b
, फिर स्लाइस करें a
:
np.random.seed(1)
a = np.random.randn(9, 6).astype('float32')
b = np.random.randn(1, 6).astype('float32')
for i in range(1, len(a)):
a_flat = np.expand_dims(a[:i].flatten(), -1) # keep 2D
print(list(np.dot(a_flat, b)[0])) # full shape: (i*6, 6)
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
[-0.3393164, 0.9528787, 1.3627989, 1.5124314, 0.46389243, 1.437775]
मामले 3 : मजबूत नियंत्रण; सभी गैर-शामिल एंट्री को शून्य पर सेट करें : a[1:] = 0
CAS 1 कोड में जोड़ें । परिणाम: विसंगतियां बनी रहती हैं।
मामले 4 : के अलावा अन्य सूचकांकों की जाँच करें [0]
; जैसे [0]
, परिणाम सृजन के बिंदु से एक निश्चित # सरणी वृद्धि को स्थिर करना शुरू करते हैं। उत्पादन
np.random.seed(1)
a = np.random.randn(9, 6).astype('float32')
b = np.random.randn(6, 6).astype('float32')
for j in range(len(a) - 2):
for i in range(1, len(a)):
res = np.dot(a[:i], b)
try: print(list(res[j]))
except: pass
print()
इसलिए, 2D * 2D मामले के लिए, परिणाम भिन्न होते हैं - लेकिन 1D * 1D के लिए संगत होते हैं। मेरे कुछ रीडिंग से, यह 1D-1D से साधारण जोड़ का उपयोग करके स्टेम करने के लिए प्रकट होता है, जबकि 2D-2D में 'फैनसीयर' का उपयोग किया जाता है, प्रदर्शन-बढ़ाने वाला जोड़ कम सटीक हो सकता है (जैसे कि जोड़-तोड़ इसके विपरीत होता है)। फिर भी, मैं यह समझने में असमर्थ हूं कि एक बार a
'थ्रेशोल्ड' के पिछले टुकड़े किए जाने के मामले में विसंगतियां 1 में गायब क्यों हो जाती हैं ; बड़ा a
और b
, बाद में यह सीमा झूठ लगती है, लेकिन यह हमेशा मौजूद रहती है।
सभी ने कहा: np.dot
एनडी-एनडी सरणियों के लिए इंप्रूव (और असंगत) क्यों है ? प्रासंगिक गिट
अतिरिक्त जानकारी :
- पर्यावरण : विन -10 ओएस, पायथन 3.7.4, स्पाइडर 3.3.6 आईडीई, एनाकोंडा 3.0 2019/10
- CPU : i7-7700HQ 2.8 GHz
- Numpy v1.16.5
संभावित अपराधी पुस्तकालय : नॉम्पी एमकेएल - ब्लास लाइब्रेरी भी; ध्यान देने के लिए बी रीको का धन्यवाद
तनाव-परीक्षण कोड : जैसा कि कहा गया है, विसंगतियां आवृत्ति w / बड़े सरणियों में बढ़ जाती हैं; यदि ऊपर प्रजनन योग्य नहीं है, तो नीचे होना चाहिए (यदि नहीं, तो बड़े आकार का प्रयास करें)। मेरा आउटपुट
np.random.seed(1)
a = (0.01*np.random.randn(9, 9999)).astype('float32') # first multiply then type-cast
b = (0.01*np.random.randn(9999, 6)).astype('float32') # *0.01 to bound mults to < 1
for i in range(1, len(a)):
print(list(np.dot(a[:i], b)[0]))
समस्या की गंभीरता : दिखाई गई विसंगतियां 'छोटी' हैं, लेकिन अब ऐसा नहीं है जब तंत्रिका नेटवर्क पर अरबों की संख्या के साथ कुछ सेकंड में गुणा किया जाता है, और पूरे रनटाइम पर खरबों; रिपोर्ट किए गए मॉडल की सटीकता प्रति धागे के अनुसार 10 प्रतिशत है ।
नीचे एक मॉडल को खिलाने से उत्पन्न सरणियों का एक gif है जो मूल रूप से a[0]
, w / len(a)==1
बनाम है len(a)==32
:
पॉल के परीक्षण के अनुसार और उसके साथ अन्य PLATFORMS परिणाम :
केस 1 पुनरुत्पादित (आंशिक रूप से) :
- Google Colab VM - Intel Xeon 2.3 G-Hz - जुपिटर - पायथन 3.6.8
- विन -10 प्रो डॉकर डेस्कटॉप - इंटेल i7-8700K - ज्यूपिटर / स्किपी-नोटबुक - पायोनॉन 3.3
- उबंटू 18.04.2 एलटीएस + डोकर - एएमडी एफएक्स -8150 - ज्यूपिटर / स्केपी-नोटबुक - पायनियर 3.3
नोट : इन उपज बहुत कम त्रुटि से ऊपर दिखाया गया है; पहली पंक्तियों पर दो प्रविष्टियाँ अन्य पंक्तियों में संबंधित प्रविष्टियों से कम से कम महत्वपूर्ण अंक में 1 से बंद हैं।
केस 1 पुन : प्रस्तुत नहीं :
- Ubuntu 18.04.3 LTS - Intel i7-8700K - IPython 5.5.0 - पायथन 2.7.15+ और 3.6.8 (2 परीक्षण)
- Ubuntu 18.04.3 LTS - Intel i5-3320M - IPython 5.5.0 - पायथन 2.7.15+
- Ubuntu 18.04.2 LTS - AMD FX-8150 - IPython 5.5.0 - पायथन 2.7.15rc1
नोट :
- जुड़ा हुआ Colab नोटबुक और jupyter वातावरण में कहीं कम भिन्नता नहीं है (और केवल पहले दो पंक्तियों के लिए) की तुलना में अपने सिस्टम पर मनाया जाता है। इसके अलावा, केस 2 कभी नहीं (अभी तक) ने अपव्यय दिखाया।
- इस बहुत ही सीमित नमूने के भीतर, वर्तमान (डॉकरीकृत) ज्यूपिटर पर्यावरण आईपीथॉन पर्यावरण की तुलना में अधिक अतिसंवेदनशील है।
np.show_config()
पोस्ट करने के लिए बहुत लंबा है, लेकिन सारांश में: IPython envs BLAS / LAPACK- आधारित हैं; कोलाब ओपनबीएलएएस-आधारित है। IPython Linux envs में, BLAS लाइब्रेरी सिस्टम-स्थापित हैं - जुपिटर और कोलाब में, वे / ऑप्ट / कोंडा / लिब से आते हैं
अद्यतन : स्वीकृत उत्तर सटीक, लेकिन व्यापक और अपूर्ण है। यह सवाल किसी के लिए भी खुला रहता है जो कोड स्तर पर व्यवहार की व्याख्या कर सकता है - अर्थात्, एक सटीक एल्गोरिथम जिसका उपयोग किया जाता है np.dot
, और यह कैसे उपरोक्त परिणामों में मनाया गया 'सुसंगत असंगतता' (यह भी टिप्पणियां देखें) बताता है। यहाँ मेरे डिक्रिपरिंग से परे कुछ प्रत्यक्ष कार्यान्वयन हैं: sdot.c - arraytypes.c.src
ndarrays
आमतौर पर संख्यात्मक सटीक नुकसान की उपेक्षा करते हैं। क्योंकि वे reduce-sum
प्रत्येक अक्ष के साथ सादगी के लिए , संचालन का क्रम इष्टतम नहीं हो सकता है ... ध्यान दें कि यदि आप सटीक त्रुटि का मन बनाते हैं तो आप उपयोग कर सकते हैंfloat64