چطوری حافظه و زمان اجرا را در پایتون و ژوپیتر نوت بوک حساب کنیم؟
قرار هستش در این اموزش با روش های ساده تا پیشرفته محاسبه زمان اجرا و وضعیت مصرف حافظه در پایتون رو با هم بررسی کنم پس ما من همراه باشید.
خیلی خلاصه بگم که توی ژوپیتر نوت بوک ابزار مورد علاقه من کلی ابزار هست که میتونیم از اونها استفاده کنیم و زمان اجرا رو محاسبه کنیم در کنارش توی پایتون خالص هم روش / روش هایی برای اینکار هست که در این مقاله با توجه به رویه یک دانشمند داده و مهندسی یادگیری ماشین بیشتر درباره ژوپیتر نوت بوک صحبت میکنم.
اگر که میخواهید میتونید راهنمای جامع ژوپیتر نوت بوک به صورت پست بلاگ رو مشاهده کنید و همچنین پلی لیست یوتوب ژوپیتر نوت بوک رو بررسی کنید.
پیش نیاز:
دانش اولیه پایتونی
دانش اولیه کار با ژوپیتر نوت بوک
جدول محتوایی
روش های محاسب زمان اجرا در پایتون (خالص)
روش های محاسبه زمان اجرا در ژوپیتر نوت بوک
محاسبه مصرف Ram در ژوپیتر نوت بوک
روش های محاسبه زمان اجرا در پایتون
برای محاسبه در قالب یک سری کد پایتونی ساده ترین روش استفاده از کتابخونه time و محاسبه قبل و بعد از اجرای یک یا چند خط کد میباشد.
قبل از اینکه کد اصلی رو بزنم باید یک کدی داشته باشیم که اجرا بشه برای شروه فاکتوریل ۱۰۰۰ که مودش رو بر ۲ بگیریم :
حالا کد اصلی که با استفاده از time.clock() هست و میایم قبل و بعد از کد قرار میدیم:
این روش دو عیب داره برامون اینکه ما نمیدونیم هر سطر چقدر منابع مصرف میکنه و اینکه به صورت متوسط چقدر منابع مصرف میشه که بریم به بخش بعدی تا برای هر کدوم از این عیب ها بهتون بگم که jupyter notebook چه خوابی برامون دیده ( البته که Ipython باید گفت)
دو مشکل داریم:
۱. زمان اجرای متوسط رو نداریم
۲. زمان اجرای هر بخش رو نداریم
روش های محاسبه زمان اجرا در ژوپیتر نوت بوک
فعلا هنوز کد قبلیمون رو داریم و به نظرم به اندازه کافی خوب هستش برای اینجا بریم و بررسی کنیم
%time به خاطر اینکه ما دفعات زیادی کد رو اجرا میکنیم و دستور print خروجی رو شلوع میکنه و io رو درگیر من کد مرجع رو تغییر دادم به:
از بخش توابع جادویی با یک تابع جادویی به اسم time اشنا شدیم که برامون دقیقا مثل قسمت قبل مقدارش رو برمیگردونه برای مثال ببینید:
البته یک قاعده ای رو داریم اگر دوتا % بذاریم پشت time برای کل اون سلول زمان رو حساب میکنه که زمانی که چند خط داریم از این رویه استفاده میکنیم ( یا خوانایی بهتر)
این تا حدی خوبه که با جزییات ما میدونیم هر بخش چقدر زمان صرفش شده ولی بهمون هر دفعه یک رقم جدید میده و مشکل اول زمان اجرای متوسط رو نداریم رو اینجا قرار هست با دستور timeit حل کنیم!
این دستور برای ما میاد و کدی / کدهایی که گفتیم رو چندین بار اجرا میکنه و بهمون یک خلاصه ای از عملکردش رو میده
بیایم اول مثل قبلی ها اجراش کنیم تا ببینیم چه چیزی بهمون میده و بعد مفصل تر دربارش صحبت کنیم:
البته باز هم نسخه چند خطی اون با %% در دسترس هست
قبل از اینکه جلو تر بریم بیاییم ببینیم چه چیز هایی رو بهمون میگه:
143 ns ± 3.93 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
به طور متوسط ۱۴۳ نانو ثانیه زمان اجرا دستورات ماست و std ما ( انحراف معیار) ما حدود ۴ نانو ثانیه هست در کنارش دو چیز رو مطرح میکنه که این بر اساس یک تعداد run و یک تعداد loop هست
loop میشه گفت اجرای از اول کد هستش
run اجرای اون کد هستش
البته که میتونیم با دادن پارامتر هایی این رو تعیین کنیم
%timeit -n10 -r5 my_code()
که n تعداد اجراست و r تعداد حلقه هایی باید اجرا بشه
برای گرفتن خروجی این تابع مجیک میتوینم با فلگ o خروجیش رو در یک متغییر ذخیره کنیم
output_of_test = %timeit -n10 -r5 -o my_code()
که این خروجیش میتونیم ازش مورادی مثل بهترین ها و بدترین زمان های اجرا رو بگیریم
تا اینجا یکی از مشکلاتی که گفتم یعنی متوسط زمان اجرا رو حل کردیم ولی هنوز بهمون میزانی که هر خط کد طول میکشه اجرا بشه رو نمیگه بریم به بخش استفاده از ماژول های line_profiler و memory_profiler در ژوپیتر برای تشخیص میزان مصرف منابع و حافظه خط به خط کد پایتون:
نصب و استفاده از ماژول line_profiler برای تشخیص زمان اجرای خط به خط کد
با استفاده از ماژول line_profiler در ژوپیتر و Ipython میتونیم زمان اجرای خط به خط پایتون رو در بیاریم و بعدا بتونیم با این اطلاعات بهبود بدیم اون رو
ابتدا اون رو نصب کنیم با کمک دستور pip
بعد از نصب میتونید با کمک load_ext اون رو توی ژوپیتر لود کنید
و قبل از اینکه بریم و یک کدی بنویسیم که چندین قسمت داره تا درک بهتری داشته باشیم به کار.
چیزی که میدونیم اینکه فاکتوریل اعداد بزرگتر بیشتر طول میکشه و میخواهیم بررسی کنیم 250 چقدر بیشتر از بقیه طول میکشه. برای اینجا بعد از لود باید از lprun استفاده کنیم به این شکل که با فلگ f اسم تابع و خود تابع رو بفرستیم.
که بهمون این خروجی رو میده:
که الان میدونیم هر خط چقدر منابع مصرف میکنه حالا بیایم با یک کد دیگه هم بررسیش کنیم
برای اینکه نشون بدم میشه از توابعی که حتی خودمون نساختیم هم استفاده کنیم اینجا یک مدل خیلی ساده با استفاده از LinearRegression و دیتاست ایریس ساختم و اجراش کردم ببینم چطوری اجرا میشه که نتیجه به این شکل شد:
نصب و استفاده از ماژول memory_profiler برای تشخیص میزان رم هر خط
ماژول بعدی که میخوام دربارش صحبت کنم memory_profiler هست که با استفاده از اون میتونیم خط به خط میزان استفاده رو توی پایتون مشخص کنیم.
برای شروع با دستور زیر اون رو نصب میکنیم
بعد از نصب میتونید با کمک load_ext اون رو توی ژوپیتر لود کنید
دقیقا مثل دستور قبلی و اینجا از mprun استفاده میکنیم برای نمونه برای تابعی که فاکتوریل های مختلفی اجرا میکرد:
همانطور که میبینید در خط اول مکان دقیق اون تابع رو برای ما مشخص کردم و از طرفی طبق پیامی که من گرفتم اجازه اجرا
NOTE: %mprun can only be used on functions defined in physical files, and not in the IPython environment.
رو به ما میده که متاسفانه نمیتونم از فانکشن هایی که توی ژوپیتر تعریف میکنیم این تابع رو استفاده کنیم.
خب اینجا هم خروجی رو بینید که برای اون تابع fit هست: