Lesson_5_Performance

  |   Source

مقاييس الاداء وتقنيات الامثلة:

  • الهدف:

بمعالجة الصورة وبما ان الكود خاصتك يتعامل مع عدد كبير من العمليات بالثانية , من الضروري ان لا يؤمن فقط الحل الصحيح وانما بالشكل الاسرع, ولذلك في هذا الفصل سنتعلم

  1. قياس اداء البرنامج

  2. بعض النصح لتحسين الاداء

  3. وسنرى هذه التوابع

cv2.getTickCount , cv2.getTickFrequency

بدون توابع opencv يقدم بايثون توابع time المفيدة بقياس زمن التنفيذ , و هناك موديول اخر (profile)يساعدك للحصول على تقرير كامل عن الكود, مثل كم استغرق كل تابع بالتنفيذ , اما اذا كنت تستخدم IPython كما في حالتنا , فهناك تسهيلات اكثر ,حيث سنتعرف على اهمها , للمزيد راجع التوثيق الخاص بكل منها

قياس الاداء مع OpenCV:

التابع:

cv2.getTickCount يعطي عدد دورات الساعة التي مرت من حدث مرجعي للحظة المناداة

ولذلك اذا استعديته قبل وبعد تنفيذ تابع فسيعطي عدد دورات الساعة خلال عمله.

أما: cv2.getTickFrequency

يعطي تردد دورات الساعة, او عدد الدورات بالثانية , ولذلك لايجاد زمن التنفيذ بالثواني عليك فعل التالي:

In [16]:
import cv2
import numpy as np
e1 = cv2.getTickCount()
# your code execution
d = 5/8.0
e2 = cv2.getTickCount()
time = (e2 - e1)/ cv2.getTickFrequency()
In [17]:
img1 = cv2.imread('Rene_Decart.jpg')
e1 = cv2.getTickCount()
for i in xrange(5,49,2):
    img1 = cv2.medianBlur(img1,i)
e2 = cv2.getTickCount()
t = (e2 - e1)/cv2.getTickFrequency()
print t
# Result I got is 0.521107655 seconds
0.294762540901

ملاحظة:

يمكنك القيام بنفس الامر باستخدام الموديول time بدلا من السابق ,حيث يتم اخذ الفرق ايضاً لمناداتين للتابع

الامثلة الافتراضية في OpenCV:

العديد من التوابع مؤمثلة في OpenCV

ولكنها تتضمن ايضاً أكواد غير مؤمثلة ,ولذلك اذا كان نظامنا داعماً لهكذا طرق فيجب علينا استغلالهم (تقريبا معظم المعالجات الحديثة داعمة لها)وهي تكون مفعلة بالاصل عند التنفيذ (افتراضياً)بالمناسبة ولذلك يتم تنفيذ الكود المؤمثل Optimized في حال انه ممكن , والا الاخر ونستخدم cv2.useOptimized لمعرفة هل الامثلة ممكنة , ام لا , ونستخدم cv2.setUseOptimized للتمكين او الغاء التمكين , والتالي كمثال:

In [4]:
cv2.useOptimized()
Out[4]:
True
In [5]:
%timeit res = cv2.medianBlur(img1,49)
100 loops, best of 3: 6.44 ms per loop
In [6]:
cv2.setUseOptimized(False)
In [7]:
cv2.useOptimized()
Out[7]:
False
In [8]:
%timeit res = cv2.medianBlur(img1,49)
100 loops, best of 3: 14.7 ms per loop

وكما نرى , فان الترشيح الاوسطي المؤمثل ,اسرع بحوالي الضعف من الغير مؤمثل , ولو نظرت لبرنامجه لوجدت ان امثلته من نوع SIMD ولذلك يجب تمكين الامثلة ببرنامجك (تذكر الامثلة افتراضية)مبدئياً

قياس الاداء في IPython:

احياناً تحتاج قياس الاداء لعمليتين متشابهتين ,ونلحظ ضمن IPython انه يزودنا بامر سحري لذلك , وهو timeit%

فهو يشغل البرنامج عدة مرات لمعرفة الزمن اللازم له بدقة , وايضاً تتناسب هذه الطريقة مع التعليمات المفردة , مثلا هل تعرف اي من عمليات الجمع التالية افضل , هذا سنعرفه من خلال هذا الامر وبواجهة البايثون

In [9]:
x = 5
In [10]:
%timeit y=x**2
The slowest run took 22.86 times longer than the fastest. This could mean that an intermediate result is being cached.
10000000 loops, best of 3: 56 ns per loop
In [11]:
%timeit y=x*x
The slowest run took 20.19 times longer than the fastest. This could mean that an intermediate result is being cached.
10000000 loops, best of 3: 63.4 ns per loop
In [12]:
z = np.uint8([5])
In [13]:
%timeit y=z*z
The slowest run took 23.67 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 505 ns per loop
In [14]:
%timeit y=np.square(z)
The slowest run took 24.20 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 529 ns per loop

ومنه يمكنك الاستنتاج , مع تجاهل اخطاء الهاردوير , ان عملية الضرب

$$y = x*x$$

هي اسرع بحوالي 10 مرة من انشاء المصفوفات في Numpy واذا اخذت بعين الحسبان ,تربيع المصفوفات فقد يصل لحوالي 11 مرة اسرع , سيئ هه؟

هذه ثغرة يتم العمل عليها في Numpy

ملاحظة:

عمليات الارقام القياسية في بايثون, اسرع من العمليات في Numpy للارقام المفردة , ولذلك لتلك العمليات المتضمنة عددا او اثنين استخدم بايثون ,حيث فائدة Numpy تكمن عندما يزداد حجم المصفوفة قليلا

الآن سنجرب مثالا اضافيا اخر , هذه المرة ,سنقارن اداء التابعين التاليين لنفس الصورة

cv2.countNonZeo , np.count_nonzero

In [21]:
img1_g = cv2.cvtColor(img1,cv2.cv.CV_BGR2GRAY)
%timeit z = cv2.countNonZero( img1_g )
10000 loops, best of 3: 51.6 µs per loop
In [22]:
%timeit z = np.count_nonzero(img1_g)
10000 loops, best of 3: 170 µs per loop

نلاحظ ان سرعة توابع cv2 أعلى من سرعة توابع np

ملاحظة :

عادة توابع opencv اسرع من توابع Numpy ولذلك لاجل نفس العملية استعمل الاول , ولكن هناك استثناءات , مثلاً عند تعامل الثانية مع العرض بدلاً من النسخ.

تقنيات امثلة الاداء:

الشيء الرئيسي هنا انه عليك اولاً ايجاد تطبيق الخوارزمية بشكل بسيط ثم توضيح ادائها بعد عملها الصحيح , ثم ايجاد العراقيل فيه , وامثلته

  • تجنب استخدام الحلقات ببايثون , وخصوصاً الحلقات الثنائية والثلاثية نظراً لبطئها.

  • اجعل الخوارزمية باوسع شكل للاشعة لأن العمليات في كلا المكتبتين مؤمثلة للاشعة .

  • استفد من المتغيرات المعرفة مسبقاً ,بدون تعريف أخرى

  • لا تنسخ المصفوفات , مالم تحتاج ذلك ,حاول استخدام العرض بدلاً من ذلك ,لان نسخها عملية مكلفة

  • وحتى بعد كل ذلك , اذا بقي برنامجك بطيئاً او لا يحتمل التعديل , يمكنك التسريع باستخدام مكتبات ك cython لجعله اسرع

Comments powered by Disqus