Mahyar Riazati
Mahyar Riazati
خواندن ۶ دقیقه·۳ سال پیش

بازی بازی با D2QN! یادگیری تقویتی و شبکه‌های عصبی


سلااام! این مقاله خیلی خودمونیه با این حال هدف اینه با هم معماری معروف DQN ای که در مقاله "Playing Atari with Deep Reinforcement" شد رو یک بررسی بکنیم و ببینیم و نسخه بهبود یافتش یعنی Double DQN که بعضا بهش D2QN هم میگن (یا حداقل من میگم:دی ) چیه و در نهایت پیاده سازیش توی PyTorch رو ببینم. که خب انتظار میره اندکی پایتون و شبکه عصبی بلد باشید و البته سعی میکنیم درگیر فرمولها زیاد نشیم. قبل از شروع این داستان زیبا بیاید مطمئن شیم یسری چیزای پایه ای رو میدونیم:

  • در یادگیری تقویتی Agent ما در یک محیطی (Environment) زندگی میکنه و به ازای موقعیتی که درش قرار داره (St) یک حرکتی (At) رو انجام میده و در نهایت به موقعیت بعدی (St+1) با یک پاداش/مجازاتی (R) منتقل میشه. هدف؟ بیشینه کردن میزان پاداش.


  • عادت یا ماجراجویی؟ برای کسب تجربه بعضی مواقع نیازه که همیشه دست به راه حل بهینه نزنیده و اندکی خل بازی در بیارید که به این قضیه میگیم Explore Exploit dilemma.
  • محیطای ما به دو نوع پیوسته و مرحله‌ای میتونن تقسیم بشن. اگر محیط از جنس مرحله ای باشه به ازای هر حرکتی که میزنید خود محیط بهتون یه سیگنالی میده که بیانگر اینه که آیا این مرحله تموم شده یا خیر ما به این سیگنال میگیم done در صورتی که تموم نشده باشه مقدار منطقی False و در صورتی که تموم شده باشه مقدار منطقی True رو دراه.
  • موقعیتی که ما توش قرار داریم میتونه به صورت یک آرایه باشه که بیانگر یکسری از خصوصیات محیط هستند یا میتونن در قالب یک تصویر باشن.
  • یک تابعی داریم ما تحت عنوان q(s, a) که به زبان ساده و غیر ریاضیش صرفا بیانگر اینه که اگر در موقعیت s باشیم و حرکت a رو بزنیم این چقدر خوبه و در دراز مدت آیا تاثیر منفی داره یا مثبت.
  • ما میتونیم این دسته از مسائل رو با یه جدول خیلی خیلی بزرگ یعنی به سایز s * a حل کنیم. ولی ممکنه s, a خیلی بزرگ باشن یا کارایی که میتونیم انجام بدیم به صورت گسسته (مثلا رفتن به چپ یا راست) نباشه یعنی پیوسته باشه(مثلا وارد کردن نیرو در یک جهت خاص) که باید گسسته سازی صورت بگیره. و در نهایت با یک حلقه و اعمال فرمول زیر مقادیر این جدول رو به بهینه ترین حالت نزدیک کنیم:
چیز ترسناکی نیست کلا یه خط پایتون میشه :دی
چیز ترسناکی نیست کلا یه خط پایتون میشه :دی
  • اینم در خاطر داشته باشید که ما از مقدار q حالت بعدی برای بهبود حالت فعلی استفاده می‌کنیم اگر گیج شدید فرمول رو یه بار بخونید :دی و خب بهش میگیم q-learning
  • در صورتی که این جدول رو بتونیم تولید کنیم و در موقعیت s قرار داشته باشیم میتونیم حرکتی رو انتخاب کنیم که بهترین نتیجه رو داشته باشه، به بیان پایتونیش:
action = np.argmax(q[state]) # q[state] = [1.2 50 23 -0] action == 1

اما احتمالا توی پاراگراف آخر متوجه شدید که برای یسری مسائل ممکنه این جدول اینقد بزرگ بشه که هرچی RAM توی دنیا هست رو هم جمع کنیم نتونیم ذخیرش کنیم. اما خب راهکار چیه؟ یه تقریب با دقت خوب راه حل بهتری نیست؟ هممم! وقتی اسم تقریب توی قرن 21 به گوشمون میخوره ناخواسته ذهنمون میره سمت یادگیری عمیق و شبکه های عصبی. از قضا حضرات هم همین تفکر رو پیش گرفتن و مقاله فوق رو دادن. به طور خلاصه شما یک شبکه عصبی دارید که با گرفتن یک موقعیت مقدارهای مختلف q رو به ازای هر action خروجی میده عکسی شبیه زیر:


اما به هرحال باید این شبکه عصبی تربیت بشه مگه نه؟ و صد البته supervised هم هست پس نیاز به یه یسری داده داریم و خروجی متناسبشون. در بالا ما 5 پارامتر اساسی رو معرفی کردیم. در مقاله ذکر شده اگر مقادیر فوق درون یک بافر ذخیره بشن میتونیم بعد ازشون برای تربیبت شبکه عصبمیون استفاده کنیم. لکن برای این مسئله نیاز است که که یک کلاسی طراحی بشه.

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

و خب جالبه بدونید روند یادگیری در یادگیری عمیق به شدت کندتر از مسائل supervised مرسوم هست چون شما یه بار کل دادتون رو fit نمی کنید بلکه مثلا مجبورید هزاربار مدلتون رو fit کنید به همین جهت شما نمی تونید از کل داده ای که ذخیره کردید استفاده کنید بلکه باید از یک تعداد مشخصش استفاده کنید مگر اینکه این قدرت سخت افزاریش رو داشته باشد. یعنی شما مدل رو روی یک batch رندوم از تجربه های حاضر تربیت می کنید.


برای محاسبه مقادیر مطلوب ما یه کاری مشابه قبل رو میکنیم:

  1. مقدار state بعدی رو با استفاده از شبکه عصبی محاسبه میکنیم و مقدار بیشنینه رو در q_max ذخیره کنیم
  2. در صورتی که در اون موقعیت بازی به اتمام نرسیده بود در discount factor ضربش میکنیم و با پاداش جمعش میکنی
  3. در صورتی که اون موقعیت پایان یافته بود فقط پاداش

و خب داده ورودیمون یعنی x میشه state های فعلی و داده های خروجی رو هم بر حسب فرمول بالا محاسبه کنیم. اما صبر کنید بیاید وارد کد نشیم و همین اول کار همین رو بهبود بدیم. اگر از یک شبکه عصبی استفاده کنیم خیلی غیر stable میشه روند یادگیریمون! یعنی چی این؟

منبع: Deep Reinforcement Learning Grokking
منبع: Deep Reinforcement Learning Grokking

همونطور که مبینید اون نقطه optimal هر بار جاش تغییر پیدا میکنه و نمیشه بهش رسید. اما خب چیکار کنیم که هم شبکه عصبیمون یادبگیره هم این نقطه جاش ثابت بمونه؟ آها! یه شبکه عصبی دیگه بیاریم :دی

به شبکه عصبی اول که رفتار agent رو بهبود میده بهش میگیم online_model و شبکه عصبی که ازش برای محاسبه q(St+1) استفاده می کنیم میگیم target_model. این قضیه منجر به این میشه که اون نقطه optimal توی فضای بهینه سازیمون ثابت بمونه:

منبع: Deep Reinforcement Learning Grokking
منبع: Deep Reinforcement Learning Grokking

در زمانی که این دو شبکه عصبی رو تعریف میکنیم باید این نکته رو دقت داشته باشیم که وزناشون دقیقا یکسان باشن یعنی target_model وزنهای online_model رو داشته باشه. و همچنین بعد از هر episode یا fit شدن مجددا وزنهای online_model برابر target_model قرار داده میشن تا روند یادگیری بهتر بشه. معماری شبکه عصبمیمون چون روی محیط CartPole-v1 هست یک ANN سادس:

معماری مدل
معماری مدل
مقدار دهی اولیه nS ابعاد ورودی و nA ابعاد خروجی.
مقدار دهی اولیه nS ابعاد ورودی و nA ابعاد خروجی.


نکته: در صورتی که محیط پیچیده باشه یعنی مثلا state ها به صورت تصویر باشن باید از CNN استفاده بشه که در مقاله اصلی هم همینه.

اما اینجا برای محاسبه مقدار بهینه و استفاده از target_model یکم روندمون فرق میکنه که میتونیم خلاصش کنیم به مراحل زیر:

  1. مقدار موقعیت های بعدی یعنی St+1 رو با online_model محاسبه می‌کنیم و ببینیم کدوم action بیشترین مقدار رو داشته از این ها به عنوان اندیس در مرحله بعدی استفاده می‌کنیم
  2. مقدار موقعیت های بعدی یعنی St+1 رو با target_model محاسبه می‌کنیم و اندیس‌هایی که از بخش قبل محاسبه کردیم رو استفاده و مقادیر مربوطه رو استخراج می‌کنیم که این میشه همون q_max بخش قبلی
  3. در نهایت y مربوطه رو کاملا مشابه فرمول قبلی محاسبه میکنیم

مقادیر St فعلی رو با استفاده از online_model محاسبه و میزان خطاش رو با مقدار مطلوب محاسبه میکنیم و در نهایت backprop میکنیم توی شبکه عصبی:

در نهایت باید با Hyper Parameters ها و اندکی صبر و حوصله این مغر سیلیکونی یاد میگیره چطوری بازی کنه.

نتایج

نکته‌ای که خواستم همین اول کار بگم اینه که از episode های 400 به بعد Agent امون عملا دیگه explore ای انجام نمیده در نتیجه reward ای که میگیره کاملا کار خودشه

محیط CartPole-v1

محیط LunarLander-v2




امیدوارم مفید واقع شده باشه هر چند ضعف زیاد داره این مقاله چون خیلی مبحث مفصلیه من هم تازه کار :دی

ولی خودم سر پیاده سازیش خیلی بدبختی کشیدم گفتم شاید دفعه بعد گره‌ای از کسی باز کنه

با این حال کدها رو هم داخل گیتهاب قرار دادم و میتونید خودتون بررسی کنید و اگر جاییش سوالی بود خوشحال میشم کمکی کنم.

https://github.com/mhyrzt/D2QN



dqnrlیادگیری تقویتیtorchpython
Yare Yare Daze!
شاید از این پست‌ها خوشتان بیاید