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

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

1 - توابع فعالساز :

حدود 6 تابع فعالساز خیلی معروف برای لایه ها داریم که در تصویر زیر هم مشخص شدن که در اینجا 3 لایه رو به صورت مختصر بررسی می کنیم!

1 - تابع فعالساز Sigmoid :

نمودار تابع فعالساز Sigmoid
نمودار تابع فعالساز Sigmoid

همانطور که در شکل بالا مشاهده میشود، این تابع غیرخطی، یکنواخت، پیوسته و مشتق پذیر است. این تابع خروجی آنالوگ تولید میکند و شیب نرمی دارد، از همین رو این تابع برای استفاده در مسائل طبقه بندی کاربرد دارد. این تابع به مقادیر بسیار کم یا بسیار زیادی ورودی واکنش درخوری نشان نمیدهد و شیب را از بین میبرد که به این مساله vanishing gradientنیز گفته می شود. به همین دلیل این تابع همگرایی کندی دارد.

2 - تابع فعالساز Tanh :

نمودار تابع فعالساز Tanh
نمودار تابع فعالساز Tanh

این تابع نیز مانند تایع sigmoid با مسئله ی vanishing gradientمواجه است اما این مسئله در tanh وضعیت بهتری دارد به دلیل شیب های تندتر مشتقات آن و همچنین خروجی های این تابع مرکزیت 0 دارند که باعث می شود برای مدل هایی که ورودیها مقادیر مثبت یا منفی شدیدی دارند، مناسب تر باشد.این تابع و مشتقاتش هردو یکنواخت هستند. تصمیم برای انتخاب بین sigmoid و tanh به میزان قوی بودن شیب در تابع بسته به مسئله ی پیش روی ما بستگی دارد. این تابع هم مانند sigmoidدر طبقه بندی و لایه ی آخر کاربرد دارد.

3 - تابع فعالساز ReLU :

نمودار تابع فعالساز ReLU
نمودار تابع فعالساز ReLU

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

چند ویژگی مثبت نسبت به توابع قبلی :

این تابع با مسئله ی vanishing gradientبه خوبی مواجه میشود و آن را حل کرده است. همچنین Reluهزینه ی محاسبات کمتری دارد زیرا از روابط ریاضی ساده تری نسبت به sigmoidو tanh پیروی می کند.


2 - نرخ یادگیری :

برای Learning Rate یا همان نرخ یادگیری مقدار به مسئله وابسته است ولی اگه مقدار آن را کم کنیم سرعت کاهش خطا کند می شود و همینطور امکان تصادفی بودن کمتر می شود و ممکن است در نقاط بهینه محلی گیر کنیم ولی با انتخاب مقادیر بالا نتایج نوسانی میشه و ممکنه از کنار جواب مناسب به خاطر گام های بلند بپریم! به طور کلی این مقدار نرخ یادگیری بسته به مسئله انتخاب می شود و می تواند تاثیرات متفاوتی بذارد

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

مقایسه نرخ های یادگیری
مقایسه نرخ های یادگیری


3 - تابع هزینه :

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

یکی از رایج ترین تابع های هزینه Cross Entropy هست که اینجا توضیح میدم :

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

4 - بهینه سازها :

خوب در ادامه آخرین آرگومانی که در تابع compile در قسمت اول استفاده کردیم و تاکنون توضیح داده نشده رو توضیح میدم : بهینه سازها !

وقتی از توابع هزینه استفاده می کنیم و بعد میخوایم وزن های شبکه رو به روز کنیم این بهینه سازها نقش خودشون رو ایفا میکنن! حالا چرا بهینه سازها فرق میکنن؟ چرا چند تا بهینه ساز داریم؟ مگه همه با استفاده از تابع هزینه و یک Backpropagation به روز رسانی نمیشن؟

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

اولین بهینه سازی که معرفی میکنم بهینه ساز SGD یا همان Stochastic Gradient Descent هست که داخل قطعه کد قسمت اول هم در پیاده سازی مدل استفاده کردم ، این روش به این شکل کار می کند که در جهت شیب تندتر با گرادیان منفی حرکت میکند. این روش یکی از پرکاربردترین روشه ای بهینه سازی در یادگیری ماشین است. این روش از نظر هزینه محاسباتی جزو روشهای کم هزینه نسبت به سایر روشهای بهینه سازی است . بهترین استفاده این الگوریتم در مواردی است که پارامترها نمی توانند به صورت تحلیلی محاسبه شوند (به عنوان مثال با استفاده از جبر خطی) و باید توسط یک الگوریتم بهینه سازی جستجو شود ، خوب ولی 3 مشکل عمده داره :

الف ) Learning Rate :

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

ب ) Saddle points :

نقاط زین اسبی یا Saddle points مشکل دیگر این روش هستند چون این روش جاهایی که گرادیان صفر می شود را مورد توجه قرار می دهند ، در این نقاط زین اسبی تابع هزینه در یک بعد کمترین مقدار شده ولی در یک بعد دیگر Maximum محلی شده است ، در این نقاط اگر تابع در جهتی که کمترین مقدار شده کمی صاف تر شود ، روش گرادیان کاهشی برای همیشه دچار نوسان می شود و نتیجه اشتباه بدست می آید !

ج ) Local Minimum :

به طور کلی شبکه های عصبی شامل توابع با پیچیدگی های مختلف هستند که شامل تعداد زیادی تبدیلات غیر خطی هستند. پس نباید انتظار عملکرد فوق العاده ای از تابع loss داشته باشد و به این صورت باشد که فقط یک نقطه Minimum وجود داشته باشد که به آن نزدیک بشیم. تابع loss یک نوع منحی محدب است کهاین امکان را دارد که شامل چندین نقطه Min باشد. با این شرایط با توجه به وجود چندین نقطه Min که شیب آن ها صفر است ، اگر با استفاده از روش Gradient Decent به یکی از این Minimum ها رسیده باشیم امکان دارد در این نقطه به دام Local Minimum بیافتیم . روش گرادیان کاهشی با استفاده از صفر کردن گرادیان کار میکند و این مساله در مورد تمام نقاط Minimum برقرار است.

SGD
SGD

در ادامه برای بهبود SGD از تکنیکی به اسم Momentum استفاده شد! این تکنیک به منظور کم کردن خطای روش gradient descent مطرح شده است. در این روش به جای اینکه تنها از مقدار گرادیان در مرحله ی فعلی به منظور هدایت جستجو استفاده شود، momentum گرادیان مراحل گذشته را نیز محاسبه می کند و از آن برای تعیین جهت گرادیان استفاده می کند.

Momentum
Momentum

در ادامه بهینه سازهایی مثل RMSProp یا AdaGrad ارائه شد و در نهایت Adam ارائه شد که الان تقریبا در بیشتر مسائل نتایج مطلوب تری رو نسبت به سایر بهینه سازها برای ما به ارمغان میاره! قانون به روز رسانی برای Adam بر اساس برآورد لحظه اول (میانگین) و دومین لحظه خام از شیب های پیشین (در پنجره زمانی اخیر از طریق میانگین حرکت نمایی) تعیین می شود. همانطور که در شبکه کد زیر مشخص است تقریبا تمامی موارد بهینه سازهای دیگر در دل بهینه ساز Adam جای گرفتن!

Adam
Adam

5 - اندازه دسته ها :

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

6 - انواع داده ها :

به طور کلی داده ها را به دسته آموزش ، ارزیابی و تست تقسیم می کنند ، داده های آموزش را برای آموزش دادن مدل شبکه عصبی استفاده می کنند ، از داده های ارزیابی برای بررسی میزان دقت و قدرت تعمیم پذیری در هر Epoch استفاده می کنند و از داده های تست برای بدست آوردن دقت نهایی بعد از پایان آموزش شبکه استفاده می کنند ، هیچکدام از داده های ارزیابی و تست را برای یادگیری از قبل به شبکه نمی دهند!

تقسیم داده ها
تقسیم داده ها


از Validation Setکه یکی از سه دسته داده ما است برای ارزیابی مدل در هر لحظه استفاده می کنیم و تفاوت آن با Testدر این است که Testرا در آخر چک می کنیم ولی در اینجا مقدار Validationرا در هر Epochارزیابی می کنیم و می توانیم آن را در حد شرط توقف نیز دخالت دهیم. با توجه به اینکه Validationداده هایی هستند که در قسمت Trainبه شبکه داده نشده اند ، در اینجا این مقادیر به نوعی قدرت تعمیم شبکه را نیز ارزیابی می کنند. در شکل زیر نمونه ای از شرط توقف به وسیله ارزیابی مقدار Lossداده های Validationمشاهده می نمائید.

توقف زودهنگام به علت فرابرازش
توقف زودهنگام به علت فرابرازش