আমি এমন একটি প্রোগ্রাম লিখতে চাই যা বিএএলএএস এবং ল্যাপ্যাক লিনিয়ার বীজগণিতের কার্যকারিতা ব্যাপকভাবে ব্যবহার করে। পারফরম্যান্স যেহেতু একটি সমস্যা তাই আমি কিছু বেঞ্চমার্কিং করেছি এবং জানতে চাই, যদি আমি গ্রহণ করা পদ্ধতিটি বৈধ হয় তবে।
আমার কাছে তিনটি প্রতিযোগীর কথা বলতে হবে এবং একটি সাধারণ ম্যাট্রিক্স-ম্যাট্রিক্স গুণনের সাথে তাদের পারফরম্যান্স পরীক্ষা করতে চাই। প্রতিযোগীরা হলেন:
- নম্পি, এর কার্যকারিতা কেবলমাত্র ব্যবহার করে
dot
। - পাইথন, একটি ভাগ করা অবজেক্টের মাধ্যমে বিএলএএস কার্যকারিতা কল করে।
- সি ++, একটি ভাগ করা অবজেক্টের মাধ্যমে BLAS কার্যকারিতা কল করে calling
দৃশ্যপট
আমি বিভিন্ন মাত্রার জন্য একটি ম্যাট্রিক্স-ম্যাট্রিক্স গুণকে প্রয়োগ করেছি i
। i
5 এবং ম্যাট্রিকগুলির বর্ধনের সাথে 5 থেকে 500 পর্যন্ত চলে 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)))
২. পাইথন, ভাগ করা অবজেক্টের মাধ্যমে বিএলএএস-কে কল করে
ফাংশন সহ
_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. সি ++, একটি ভাগ করা অবজেক্টের মাধ্যমে 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;
}
ফলাফল
ফলাফলটি নীচের প্লটে দেখানো হয়েছে:
প্রশ্নাবলি
- আপনি কি মনে করেন যে আমার দৃষ্টিভঙ্গিটি ন্যায্য, বা এমন কিছু অপ্রয়োজনীয় ওভারহেডগুলি এড়ানো যায়?
- আপনি কি আশা করতে পারেন যে ফলাফলটি সি ++ এবং পাইথন পদ্ধতির মধ্যে এত বিশাল তাত্পর্য দেখায়? উভয়ই তাদের গণনার জন্য ভাগ করা অবজেক্ট ব্যবহার করছে।
- যেহেতু আমি বরং আমার প্রোগ্রামের জন্য অজগর ব্যবহার করব, তাই বিএলএএস বা ল্যাপ্যাক রুটিনগুলিতে কল করার সময় আমি কার্যকারিতা বাড়ানোর জন্য কী করতে পারি?
ডাউনলোড
সম্পূর্ণ বেঞ্চমার্কটি এখানে ডাউনলোড করা যায় । (জেএফ সেবাস্তিয়ান সেই লিঙ্কটি সম্ভব করেছেন ^^)
r
ম্যাট্রিক্সের জন্য মেমরির বরাদ্দ অন্যায্য। আমি এখনই "সমস্যা" সমাধান করছি এবং নতুন ফলাফল পোস্ট করছি।
np.ascontiguousarray()
(সি বনাম ফোর্টরান ক্রম বিবেচনা করুন)। ২. np.dot()
এটি একই ব্যবহার করে তা নিশ্চিত করুন libblas.so
।
m1
এবং m2
আছে ascontiguousarray
হিসেবে ফ্ল্যাগ True
। এবং নম্পি সি'র মতো ভাগ করা বস্তুটি ব্যবহার করে। অ্যারের ক্রম হিসাবে: বর্তমানে আমি গণনার ফলাফলের জন্য আগ্রহী নই সুতরাং আদেশটি অপ্রাসঙ্গিক।