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