मैं सबसे तेज़ तरीका आव्यूह गुणन करने के लिए पता लगाने की कोशिश और 3 अलग अलग तरीकों की कोशिश की गई थी:पाइथन में ctypes के साथ मैटिक्स गुणा तेजी से numpy के साथ क्यों है?
- शुद्ध अजगर कार्यान्वयन: यहाँ कोई आश्चर्य।
- Numpy कार्यान्वयन
numpy.dot(a, b)
- अजगर में
ctypes
मॉड्यूल का उपयोग कर सेल्सियस के साथ Interfacing का उपयोग कर।#include <stdio.h> #include <stdlib.h> void matmult(float* a, float* b, float* c, int n) { int i = 0; int j = 0; int k = 0; /*float* c = malloc(nay * sizeof(float));*/ for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { int sub = 0; for (k = 0; k < n; k++) { sub = sub + a[i * n + k] * b[k * n + j]; } c[i * n + j] = sub; } } return ; }
और अजगर कोड है कि यह कॉल:
इस सी कोड है कि एक शेयर की गई लाइब्रेरी में तब्दील हो जाता है
def C_mat_mult(a, b):
libmatmult = ctypes.CDLL("./matmult.so")
dima = len(a) * len(a)
dimb = len(b) * len(b)
array_a = ctypes.c_float * dima
array_b = ctypes.c_float * dimb
array_c = ctypes.c_float * dima
suma = array_a()
sumb = array_b()
sumc = array_c()
inda = 0
for i in range(0, len(a)):
for j in range(0, len(a[i])):
suma[inda] = a[i][j]
inda = inda + 1
indb = 0
for i in range(0, len(b)):
for j in range(0, len(b[i])):
sumb[indb] = b[i][j]
indb = indb + 1
libmatmult.matmult(ctypes.byref(suma), ctypes.byref(sumb), ctypes.byref(sumc), 2);
res = numpy.zeros([len(a), len(a)])
indc = 0
for i in range(0, len(sumc)):
res[indc][i % len(a)] = sumc[i]
if i % len(a) == len(a) - 1:
indc = indc + 1
return res
मैं शर्त है कि सी का उपयोग कर संस्करण के लिए होता है तेजी से होता ... और मैं हार गया होता! नीचे मेरी बेंचमार्क जो कि मैं या तो इसे गलत तरीके से किया था दिखाने के लिए लगता है, या कि numpy
मूर्खता से तेज है:
मुझे समझ में क्यों numpy
संस्करण ctypes
संस्करण की तुलना में तेजी से होता है करना चाहते हैं, मैं मैं शुद्ध पायथन कार्यान्वयन के बारे में भी बात नहीं कर रहा हूं क्योंकि यह स्पष्ट है।
अच्छा सवाल - यह पता चला है कि np.dot() सी – user2398029
में एक निष्क्रिय जीपीयू कार्यान्वयन से भी तेज है। अपने बेवकूफ सी matmul धीमी बनाने वाली सबसे बड़ी चीजों में से एक मेमोरी एक्सेस पैटर्न है। 'बी [के * एन + जे]; 'आंतरिक लूप (' के' से अधिक) के अंदर 'एन' का एक अंतर है, इसलिए यह प्रत्येक पहुंच पर एक अलग कैश लाइन को छूता है। और आपका लूप एसएसई/एवीएक्स के साथ ऑटो-वेक्टरिज़ नहीं कर सकता है। ** 'बी' अप-फ्रंट ट्रांसपोज़ करके इसे हल करें, जो ओ (एन^2) समय खर्च करता है और कम कैश मिस में खुद के लिए भुगतान करता है जबकि आप ओ (एन^3) 'बी' से लोड करते हैं। ** यह अभी भी होगा हालांकि, कैश-अवरुद्ध (उर्फ लूप टाइलिंग) के बिना एक निष्क्रिय कार्यान्वयन हो। –
चूंकि आप 'int sum' (किसी कारण से ...) का उपयोग करते हैं, तो आपका लूप वास्तव में' -फैस्ट-गणित 'के बिना सदिश हो सकता है यदि आंतरिक लूप दो अनुक्रमिक सरणी तक पहुंच रहा था। एफपी गणित सहयोगी नहीं है, इसलिए कंपेलर '-फैस्ट-गणित' के बिना संचालन को पुन: क्रमबद्ध नहीं कर सकते हैं, लेकिन पूर्णांक गणित सहयोगी है (और इसमें एफपी अतिरिक्त की तुलना में कम विलंबता है, जो मदद करता है यदि आप अपने लूप को अनुकूलित करने के लिए नहीं जा रहे हैं एकाधिक accumulators या अन्य विलंब छुपा सामान)। 'फ्लोट' -> 'int' रूपांतरण एक एफपी 'एड' (वास्तव में इंटेल CPUs पर एफपी जोड़ एएलयू का उपयोग करके) के बारे में है, इसलिए यह अनुकूलित कोड में इसके लायक नहीं है। –