پیاده سازی اولین شبکه عصبی برای طبقه بندی تصاویر (قسمت اول)


تو این نوشتار هدف ما طراحی و پیاده سازی یک شبکه عصبی پرسپترونی با دو لایه مخفی برای طبقه بندی تصاویره! در نظر داشته باشید تو این تمرین برای اینکه کارمون راحت باشه از لایه های دیگه که داخل شبکه های عصبی استفاده میشه مانند کانولوشن ها صرف نظر کردیم و صرفا در قالب الگوریتم شبکه عصبی پرسپترونی عمل می کنیم و با لایه های Dense سر و کار داریم ، طبیعتا استفاده از سایر متدها و لایه ها میتونه نتیجه ای که ما در این نوشتار بدست میاریم رو بهبود بده ولی در اینجا هدف صرفا آموزش هر چه ساده تر پیاده سازی اولین شبکه عصبی برای فردی هست که قصد داره کار با شبکه های عصبی رو شروع کنه!

شبکه عصبی
شبکه عصبی

خوب ابتدا توضیح میدم که قراره چه تصاویری رو دسته بندی کنیم ، مجموعه تصاویر مورد استفاده در اینجا مجموعه داده MNIST هست که این مجموعه داده یک مجموعه داده بسیار معروف جهت شناسایی و نمایش ارقام از 0 تا 9 است . در این مجموعه داده هر تصویر نشان دهنده یک عدد تک رقمی است که در کل در 10 دسته ( از صفر تا 9 ) طبقه بندی شده اند ، این مجموعه داده مجموعا از هفتاد هزار تصویر تشکیل شده است که 60 هزار تصویر آن در مجموعه آموزشی و 10 هزار تصویر تصویر در مجموعه تست قرار گرفته اند.

نمونه ای از تصاویر موجود در دیتاست MNIST رو مشاهده می کنید :

نمونه تصاویری از مجموعه داده mnist
نمونه تصاویری از مجموعه داده mnist

اگه می خواید اطلاعات بیشتری راجع به این مجموعه داده تصویری پیدا کنید می تونید به لینک زیر سر بزنید!

http://yann.lecun.com/exdb/mnist/

خوب حالا باید این مجموعه تصویر رو دانلود کنیم تا داخل کدمون ازش استفاده کنیم ، یه راه حل مراجعه به همین لینک بالا و دانلود این مجموعه هست ، اما خوب راه ساده تری هم وجود داره و می تونیم به راحتی از کتابخانه ها برای دانلود Mnist استفاده کنیم ، با استفاده از قطعه کد زیر تصاویر در دو قسمت آموزشی و تست دانلود میشن :

https://gist.github.com/alikarimi120/b88ce6443fa0349402ac06921cce9b2c

حالا بعد از دانلود تصاویر و قبل از پیاده سازی مدل شبکه عصبی لازم است ، داده های ما نرمال یا استاندارد بشوند، اما چرا لازمه این کار رو انجام بدیم؟

وقتی داده های ما بدون پیش پردازش به عنوان ورودی به شبکه عصبی داده بشه ، الگوریتم شبکه عصبی با توجه به پراکندگی داده ها و تفاوت مقیاس داده ها دچار حساسیت میشه و باعث بالا رفتن مقادیر وزن های شبکه عصبی میشه که در نهایت باعث تولید نتیجه نامناسب میشه

برای نرمالسازی می تونیم مقدار ماکزیمم و مینیمم هر ستون از داده ها رو محاسبه کنیم و با استفاده از روش MinMax و فرمول زیر داده ها رو نرمالسازی کنیم! دقت کنید داده ها باید در یک محدوده مشخص نرمال بشن (اینجا بین صفر و یک)!

نرمالسازی MinMax
نرمالسازی MinMax

خوب در روش نرمالسازی پراکندگی داده ها تغییر نمیکنه ولی در روش استانداردسازی مقادیر میانگین و انحراف معیار تغییر خواهند کرد ، مقدار میانگین صفرو انحراف معیار 1 خواهد شد. با تمام این تفاسیر با استفاده از فرمول زیر و محاسبه میانگین و انحراف معیار داده ها می تونیم داده ها رو استانداردسازی کنیم!

استاندارد سازی
استاندارد سازی

یه راه ساده تر و سریع تر از دو روش بالا هم وجود داره که به نوعی نرمالسازی صورت می گیره با توجه به اینکه پیکسل داده های این شبکه عصبی از نوع Graylevel هستند و در بازه 0 تا 255 قرار دارند ، کافی است آنها را فقط تقسیم بر 255 بکنیم. سپس آنها را Reshape می کنیم تا بتوانیم از این داده ها در ورودی مدل شبکه عصبی استفاده کنیم.

برای پیاده سازی نرمالسازی و استاندارد سازی می تونیم از کتابخانه Scikit استفاده کنیم.

نمونه کد برای نرمالسازی داده ها :

https://gist.github.com/alikarimi120/d2a00b0c7a8eff0bab9a40934a4f86c1

نمونه کد برای استاندارد سازی داده ها :

https://gist.github.com/alikarimi120/ff715d2b553da4bbe658e6b9fc36af22

خوب حالا بعد نرمالسازی یا استانداردسازی داده هامون باید اونها رو به ابعادی در بیاریم که بتونیم داخل شبکه عصبی استفاده کنیم ، تصاویر مجموعه Mnist در ابعاد 28 در 28 هستن و فقط کافیه اونها رو به یک بردار 784 بعدی تبدیل کنیم! این کار رو هم برای داده های آموزشی و هم داده های تست انجام میدیم.

قطعه کد برای تغییر ابعاد :

https://gist.github.com/alikarimi120/f25ca5d949c00dd27d7ec5e7a650119c

حالا برای داده های هدف ، یعنی دسته های کلاسمون هم باید تغییر ابعاد انجام بدیم! به این صورت که شماره کلاس ها رو به روش One-hot کد گذاری کنیم یعنی مثلا به جای اینکه داده هدفمون وقتی عددمون تو دسته سوم هست 3 باشه ، بیایم از یک آرایه با ده خانه استفاده کنیم و تمام خونه های اون رو برابر صفر قرار بدیم و تنها خونه سوم رو برابر با یک قرار بدیم تا نشون بده این تصویر به دسته سوم تعلق داره!!
این کار رو برای تمام داده های هدف انجام میدیم ، برای این کار میشه به راحتی از قطعه کد زیر داخل کتابخانه استفاده کرد :

https://gist.github.com/alikarimi120/310169aff72395356321f0c998cc898d


داده ها رو هم برای اینکه آموزش شبکه به درستی انجام بشه و تصاویر از دسته های مختلف برای آموزش انتخاب بشن با استفاده از قطعه کد زیر ، آنها را بُر می زنیم!

https://gist.github.com/alikarimi120/79654013147194c5b14a4b0e1aa163d5

حالا لازم هست معماری شبکمون رو طراحی کنیم! همونطور که قبلا گفته شد قصد داریم یک شبکه با دو لایه مخفی طراحی کنیم ، حالا معماری کلی شبکمون رو می دونیم ولی باید تعداد نورون های مورد استفاده داخل این معماری رو بدست بیاریم!

ابتدا در مورد نورون های ورودی باید دقت کنیم تعداد نورون های لایه ورودی ما برابر با ابعاد تصویر ورودی هست! و از اونجایی که در این مسئله تمام تصاویر ما 784 بعدی هستن! پس تعداد نورون های لایه ورودی هم 784 تا میشه!

خوب حالا که تعداد نورون ورودی مشخص شد ، باید تعداد نورون های لایه خروجی رو مشخص کنیم! تعداد نورون های لایه خروجی در یک مسئله طبقه بندی برابر با تعداد طبقه های ما هست ، ما تو این مسئله ده طبقه (کلاس) داده داریم پس 10 نورون خروجی خواهیم داشت!

حالا که تکلیف نورون های ورودی و خورجی مشخص شد ، میریم سراغ نورون های لایه مخفی ! خوب نمیشه قبل از آموزش شبکه و بارها تست گرفتن تعداد نسبتا دقیقی نورون براش قرار داد! کشف تعداد نورون لازم برای لایه های میانی یا همان لایه های مخفی در این مسئله نیازمند تعداد زیادی آزمایش هست تا با بررسی دقتشون به نتیجه مشخصی برسیم !

اما میتوان یک تخمین نسبی برای تعداد نورون های لایه مخفی زد ، تعداد نورون ها نباید نسبت به ابعاد تصویر اولیه خیلی کمتر یا خیلی بیشتر باشند تا شبکه دچار Overfitting یا Underfitting نشه! فعلا تو این مسئله تعداد نورون های هر دو لایه مخفی رو برابر با 512 در نظر می گیریم و خودتون می تونید تغییر بدید!

در نهایت ما چنین معماری ای برای شبکه عصبی طبقه بندمون خواهیم داشت:

معماری شبکه عصبی مورد استفاده در این کد
معماری شبکه عصبی مورد استفاده در این کد


خوب حالا نوبت به پیاده سازی شبکه عصبی رسیده ! برای پیاده سازی شبکه عصبی همونطور که داخل قطعه کد زیر مشخص هست از تعدادی لایه Dense موجود در کتابخانه Keras استفاده می کنیم ، همونطور که مشخص هست اندازه تصویر ورودی 784 ، و تعداد نورون های دو لایه Dense اول برابر 512 و لایه آخر نیز برابر 10 در نظر گرفته شده است. کلیت ساختار پیاده سازی یک مدل شبکه عصبی به همین صورت هست ، حالا علاوه بر پارامتری مانند تعداد نورون ، پارامترها و توابع دیگه ای مثل تابع فعالساز ، نرخ یادگیری ، بهینه ساز و تابع هزینه هم در قطعه کد زیر مشخص هست که در قسمت دوم آموزش در مورد تاثیر و کاربرد هر کدومشون صحبت می کنیم

خوب حالا نوبت به آموزش شبکه میرسه ، از قطعه کد زیر برای این کار استفاده می کنیم:

https://gist.github.com/alikarimi120/988c19352d0751f3d53fb205187442e7

دو آرگومان اول شامل تصاویر و داده های هدف هستن ، یک آرگومان برای تعداد Epoch داریم که تعداد دوره هایی رو مشخص میکنه که میخواهیم شبکه مورد آموزش قرار بگیره و آرگومان Validation_split نیز نمایش دهنده درصد داده هایی هست که از داده های ورودی به عنوان داده های ارزیابی ( نه برای اموزش) قرار است در هر Epoch استفاده شود. همچنین مقدار آرگومان batch size اندازه دسته ها را مشخص می کند که در قسمت دوم آموزش در مورد تاثیر آن توضیح داده می شود.


در نهایت از داده های تست نیز برای ارزیابی دقت شبکه استفاده می کنیم ، مطابق با قطعه کد زیر 10 هزار تصویر تست را به شبکه می دهیم و نتایج بدست آمده را با نتایج واقعی مقایسه می کنیم و مقدار دقت و خطا را بدست میاریم:

https://gist.github.com/alikarimi120/dda7eba466b053307b5a5334a21cf593

نتیجه بدست آمده از داده های تست :

Test - Loss: 0.06670001149177551

Test - Accuracy 0.9790999889373779

کد رسم نمودار دقت و خطا :

https://gist.github.com/alikarimi120/bf0a4ccb711fb38469446d0e59f73175

نمودار میزان دقت داده های آموزش و ارزیابی شبکه در 50 دوره

نمودار میزان دقت داده های آموزشی و ارزیابی
نمودار میزان دقت داده های آموزشی و ارزیابی


نمودار میزان خطا داده های آموزش و ارزیابی شبکه در 50 دوره

نمودار میزان خطا داده های آموزشی و ارزیابی
نمودار میزان خطا داده های آموزشی و ارزیابی


تا اینجا توانستیم یک شبکه برای طبقه بندی تصاویر ایجاد کنیم ، توضیحات مربوط به توابع و پارامترهای مختلف در قسمت دوم آموزش داده شده است.