मैं एक प्रोग्राम लिखना चाहता हूं जो BLAS और LAPACK रैखिक बीजगणित कार्यात्मकताओं का व्यापक उपयोग करता है। चूंकि प्रदर्शन एक मुद्दा है इसलिए मैंने कुछ बेंचमार्किंग की और जानना चाहूंगा कि क्या मैंने जो तरीका अपनाया वह वैध है। गुणन। प्रतियोगी हैं:
- Numpy, केवल
dot
की कार्यक्षमता का उपयोग कर रहा है। - पायथन, एक साझा वस्तु के माध्यम से BLAS कार्यात्मकताओं को बुला रहा है।
- C++, एक साझा ऑब्जेक्ट के माध्यम से BLAS कार्यात्मकताओं को कॉल करना।
परिदृश्य
मैंने विभिन्न आयामों के लिए एक मैट्रिक्स-मैट्रिक्स गुणन लागू किया मैं ।
i
5 की वृद्धि के साथ 5 से 500 तक चलता है और मैट्रिक्स m1
और m2
इस तरह सेट किए जाते हैं:
m1 = numpy.random.rand(i,i).astype(numpy.float32) m2 = numpy.random.rand(i,i).astype(numpy.float32)
<एच2>1. Numpy इस्तेमाल किया गया कोड इस तरह दिखता है:
tNumpy = timeit.Timer("numpy.dot(m1, m2)", "import numpy; from __main__ import m1 , m2") rNumpy.append((i, tNumpy.repeat(20, 1)))
2. पायथन, एक साझा वस्तु के माध्यम से BLAS को कॉल करना
फ़ंक्शन के साथ
_blaslib = ctypes.cdll.LoadLibrary("libblas.so") def Mul(m1, m2, i , आर): no_trans = c_char("n") n = c_int(i) one = c_float(1.0) शून्य = c_float(0.0) _blaslib.sgemm_(byref(no_trans), byref(no_trans), byref(n), byref (n), byref(n), byref(one), m1.ctypes.data_as(ctypes.c_void_p), byref(n), m2.ctypes.data_as(ctypes.c_void_p), byref(n), byref(zero) , r.ctypes.data_as(ctypes.c_void_p), byref(n))
परीक्षण कोड इस तरह दिखता है:
r = numpy.zeros ((i,i), numpy.float32) tBlas = timeit.Timer("Mul(m1, m2, i, r)", "import numpy; from __main__ import i, m1, m2, r, Mul") rBlas। एपेंड ((i, tBlas.repeat(20, 1)))
3. c++, साझा किए गए ऑब्जेक्ट के माध्यम से BLAS को कॉल करना
अब c++ कोड स्वाभाविक रूप से थोड़ा लंबा है इसलिए मैं जानकारी को कम से कम कर देता हूं।
मैं फ़ंक्शन को
शून्य * हैंडल = dlopen ("libblas.so", RTLD_LAZY); शून्य * Func = dlsym (हैंडल, "sgemm_");
मैं समय को gettimeofday
से इस तरह मापता हूं:
gettimeofday(&start, NULL); f(&no_trans, &no_trans, &मंद, &मंद, &मंद, &एक, A, &मंद, B, &मंद, &शून्य, वापसी, &मंद; gettimeofday(&end, NULL); डीटाइम्स [जे] = कैल्कटाइम (प्रारंभ, अंत);
जहाँ j
एक लूप है जो 20 बार चल रहा है। मैं
डबल कैल्कटाइम (टाइमवल स्टार्ट, टाइमवल एंड) {डबल फैक्टर = 1000000; वापसी (((डबल)end.tv_sec) * फ़ैक्टर + ((डबल)end.tv_usec) - (((डबल) start.tv_sec) * फ़ैक्टर + ((डबल) start.tv_usec))) / फ़ैक्टर; }
परिणाम
परिणाम नीचे दिए गए प्लॉट में दिखाया गया है:
प्रश्न
- क्या आपको लगता है कि मेरा दृष्टिकोण उचित है, या कुछ अनावश्यक खर्च हैं जो मैं कर सकता हूं से बचें?
- क्या आप उम्मीद करेंगे कि परिणाम c++ और पायथन दृष्टिकोण के बीच इतनी बड़ी विसंगति दिखाएगा? दोनों अपनी गणना के लिए साझा वस्तुओं का उपयोग कर रहे हैं।
- चूंकि मैं अपने कार्यक्रम के लिए अजगर का उपयोग करना चाहूंगा, मैं बीएलएएस या लैपैक रूटीन को कॉल करते समय प्रदर्शन को बढ़ाने के लिए क्या कर सकता हूं?
डाउनलोड करें
संपूर्ण बेंचमार्क यहां डाउनलोड किया जा सकता है। (जेएफ सेबेस्टियन ने उस लिंक को संभव बनाया^^)