رفتن به مطلب

متد Batch learning رو چطور پیاده سازی کنم ؟ (وزنها بچه صورت آپدیت میشن؟)


ارسال های توصیه شده

سلام .

وقت همگی بخیر .

یکسره میرم سر اصل مطلب . تو شبکه های عصبی چندتا شیوه برای train کردن وجود داره . دو روش کلی اون :

یکی )incremental learning یا online learning هست

و دومی) هم Batch learning

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

ولی تو دومی مشکل دارم .

تو کتابها من خوندم میگن تو بچ لرنینگ ما آپدیتها رو به ازای هر epoch انجام میدیم (برخلاف حالت اول که برای هر نمونه این اپدیت رو رو شبکه اعمال میکنیم ) .

و برای این کار ما تغییرات وزن و بایاس ها رو با هم جمع میکنیم و بعد هرچی شد قبل از رفتن به epoch بعدی (دور بعدی تمرین) اپدیت میکنیم .

 

این یه الگوریتم

 

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

 

کدوم یکی از این دو الگوریتم درست هستن ؟

نمونه پیاده سازی شده ای ازش دارید (ترجیحا سی++ جاوا یا سی شارپ؟ )

من الگوریتم اول رو پیاده کردم اما اصلا converge نمیکنه . چه epoch رو 5 بزارم چه 800هزار (هر دوتا رو تست کردم ) و اصلا کانورج نمیکنه .

 

ورژن دوم رو تست کردم جواب میده (کانورج میکنه ) اما نمیدونم واقعا بچ بحساب میاد یا نه . اگر میاد چرا از روش اول استفاده میشه . روش دوم که خیلی بهینه تر هست و فضای کمتری میگیره .

 

این یه نمونه کد به سی++ هست که نحوه کار منو نشون میده . (بخشی از کتابخونه ای هست که نوشتم برای شبیه سازی شبکه های عصبی )

 

برای مشاهده این محتوا لطفاً ثبت نام کنید یا وارد شوید.

  • Like 3
لینک به دیدگاه

خب الحمدالله بلطف خدا متوجه شدم داستان چیه .

اولا ما تغییرات وزن به اون معنایی که متبادر میشه به ذهن رو انجام نمیدیم .

ما گرادیانت ارور رو جمع میکنیم و بعد میانگین اون رو برای محاسبه تغییرات وزن لحاظ میکنیم . خب این یعنی چی ؟

خب از اول ساده میریم جلو

قدم اول این بود که ما خطا رو در لایه آخر بدست بیاریم و برای بدست آوردن خطا ما داشتیم

error = desired_output - network_output

یعنی جواب دلخواه منهای خروجی شبکه ما خطای شبکه رو بما میداد . (حالا اگه ما تو لایه آخر بیشتر از 1 نورون داشته باشیم بصورت زیر میشد معادله ما )

برای مشاهده این محتوا لطفاً ثبت نام کنید یا وارد شوید.

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

و چون لایه آخر با لایه های قبل یک تفاوتی تو محاسبه داره ما دونوع محاسبه داریم .

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

اما لایه های دیگه بصورت غیرمستقیم روی این خطا تاثیر میزارن و ما باید این تاثیر غیرمستقیم رو لحاظ کنیم .

خب برای محاسبه تغییرات وزن در لایه آخر ما از فرمول زیر استفاده میکنیم

برای مشاهده این محتوا لطفاً ثبت نام کنید یا وارد شوید.

خب به این میگن گرادیانت ارور یا حساسیت (sensivity ) یا گرادیانت محلی (local gradient) (دلتا هم بهش میگن ). اینا همش اسمهای این ضریب ما هست .

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

برای مشاهده این محتوا لطفاً ثبت نام کنید یا وارد شوید.

و وزن جدید هم میشه

برای مشاهده این محتوا لطفاً ثبت نام کنید یا وارد شوید.

(که آلفا همون نرخ یادگیری هست )

برای لایه های قبلی هم تقریبا به همین صورته با این تفاوت که error در فرمول زیر از یه رابطه غیرمستقیم بدست میاد :

برای مشاهده این محتوا لطفاً ثبت نام کنید یا وارد شوید.

error از رابطه زیر بدست میاد

Sum of All (gradientofError k * W_jk

یعنی چی ؟ یعنی اینکه برای بدست آوردن خطای یک نورن در لایه مخفی ما میایم اول نرونهایی که این نورون به اون ها وصل هست رو مشخص میکنیم (فرض کنید یه شبکه داریم دوتا لایه داره . لایه شماره 1 که لایه مخفی هست و لایه شماره 2 که لایه خروجی هست .

نورون i در لایه 1 هست که که به چندتا نورون تو لایه 2 وصل هست(مثلا 2 تا نورون تو لایه آخر هستن با اسم های j1 و j2 )

حالا برای اینکه خطای نورون i رو بدست بیاریم . میایم گرادیانت محلی (گرادیانت ارور ) هر نورون تو لایه 2 که به نورون i وصل هست رو ضرب در وزن یالی میکنیم که نورون i با اون به این نورونها وصله .

مثلا فرض کنید نورون i به دوتا نورون تو لایه 2 وصل هست . پس دوتا وزن داریم که از نورون i به این دوتا نورون میره ( هرکدوم یک وزن ) .

حالا ما اینا رو باهم جمع میکنیم یعنی

error_i = gradientError_i_j1 * w_i_j1 + gradientError_i_j2 * w_i_j2

و حالا میشه گرادیانت محلی نورون i رو بدست آورد که میشه

برای مشاهده این محتوا لطفاً ثبت نام کنید یا وارد شوید.

و برای بدست آوردن وزن هم دقیقا مثل قبل عمل میکنیم .

برای مشاهده این محتوا لطفاً ثبت نام کنید یا وارد شوید.

و نهایتا مثل قبل

برای مشاهده این محتوا لطفاً ثبت نام کنید یا وارد شوید.

خب پس این شد یک مختصر توضیح اولیه کار .

تو بچ لرنینگ ما این گرادیانتها رو با هم جمع میکنیم و بعد میانگین میگیریم و بعد اون رو تو اپدیت وزنها دخالت میدیم . حالا این باز یعنی چی ؟

فرض کنید ما 4 تا نمونه داریم و تعداد مراحل تمرینی ما هم 10 هست (epoch) . تو متد آنلاین یا افزایشی ما هر بار که یک نمونه رو به شبکه ارائه میکردیم . خروجی شبکه رو میگرفتیم بعد ارور رو حساب میکردیم بعد گرادیانت محلی و بعدم دلتا دبلیو رو حساب میکردیم بصورت قبل و بعد وزنها رو بروز میکردیم . و بعدش میرفتیم و نمونه بعدی رو میخونیدم و به همین ترتیب شبکه رو دوباره تنظیم میکردیم . پس عمل تنظیم شبکه به ازای هر نمونه انجام میشد .

اما در متد بچ لرنینگ (دسته ای ) ما به ازای هر مرحله تمرینی کامل عمل اپدیت وزنها و تنظیم شبکه رو انجام میدیم . هر مرحله تمرینی هم شامل ارائه همه نمونه ها به شبکه است . یعنی وقتی همه مثالها رو به شبکه دادیم یک دور تمرین تموم میشه . و برای دور بعد تمرین ما مثالها رو دوباره به شبکه ارائه میکنیم .

خب نکته بچ لرنینگ هم همینجاست .

ما تا وقتی که تمام مثالها (نمونه ها) تموم نشدن میایم و به ازای هر نمونه خروجی شبکه رو حساب میکنیم گرادیانت محلی رو حساب میکنیم و بعد deltaW رو حساب میکنیم . (یک نکته خیلی مهم اینجا هست که پایین میگم) .

حالا این دلتا دبلیو رو ذخیره میکنیم . میریم سراغ نمونه بعدی دوباره تا همین مرحله میایم و یک دلتا دبلیو جدید بدست میاد این رو هم با قبلیه جمع میکنیم .

بعد میریم سراغ نمونه بعدی و این کار رو تا وقتی که همه نمونه ها تموم بشن ادامه میدیم .

حالا قبل از اینکه بریم و دور بعدی تمرین رو شروع کنیم باید عمل اپدیت وزنها رو انجام بدیم .

اینجا باید این دلتا دبلیویی که بدست اوردیم رو تقسیم بر تعداد نمونه ها کنیم . یک میانگین بدست میاد . و این میانگین میشه دلتادبلیو نهایی ما و وزن جدید ما هم مثل قبل بصورت زیر بدست میاد :

برای مشاهده این محتوا لطفاً ثبت نام کنید یا وارد شوید.

 

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

مثلا در کتاب Neural Networks and Learning Machins ویرایش سوم (ویرایش های قبلی هم همینطوره ) دقیقا اینطور اومده :

 

03_15144389842235861.jpg

( که اینجا اِتا (همون که شبیه n هست ) همون لرنینگ ریت هست دلتا همون دلتا (گرادیانت خطا یا گرادیانت محلی یا حساسیت) هست و yi هم یعنی ورودی نورون j (که میشه خروجی نورون i که با y_i نشون داده ))

(اشکال کار من هم دقیقا همین بود . دقت کردید دیگه این کار (لحاظ کردن آلفا در دلتا دبلیو) تو ورژن افزایشی یا آنلاین مشکلی ایجاد نمیکه بخاطر ماهیتش اما تو ورژن دسته ای مشکل ایجاد میکنه . (این کتاب هم دقیقا فقط همین رو توضیح داده بود و برای دسته ای کلی گویی کرده بود )

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

الحمدالله بلطف خدا کتاب Martin T Hagan Neural Network Design 2nd edition که لینکشم تو تاپیک شبکه های عصبی گذاشتم این بخش رو توضیح داد و من متوجه اشتباهم شدم .

امیدوارم این مطالب بدرد افراد دیگه هم بخوره و مثل من انقدر به مشکل برنخورن

 

نهایتا کد ما برای این بخش بشکل زیر در اومد :

برای مشاهده این محتوا لطفاً ثبت نام کنید یا وارد شوید.

  • Like 3
لینک به دیدگاه
×
×
  • اضافه کردن...