ד.13 — DDQN — ההבדל מ־DQN

המצגת: DDQN – Space Invaders · אתר הקורס: DDQN – Space Invaders

בשני הפרקים הקודמים בנינו סוכן DQN שלם. הפרק הזה אינו מוסיף רכיב חדש, אלא שואל שאלה על פרט קטן ביעד האימון: האם נכון לקחת את המקסימום של הערכות שאינן מדויקות? כדי להבין למה זו בעיה, חשבו על מורה שמעריך את הציון של כמה תלמידים "בערך", ואז מכריז שהתלמיד הטוב ביותר בכיתה הוא זה שקיבל את ההערכה הגבוהה ביותר. גם אם כל ההערכות שקולות בממוצע, זו שיצאה הגבוהה ביותר היא כנראה גם זו שהוגזמה יותר מהאחרות. בחירת המקסימום מטה את התוצאה כלפי מעלה.

כשבוחרים את המקסימום מבין כמה הערכות לא מדויקות, עלולים לבחור דווקא בהערכה שגבוהה מדי במקרה. אם אותה הערכה משמשת גם כיעד האימון, האופטימיות עלולה לעבור לעדכונים הבאים. Double DQN — DDQN מצמצם את הבעיה באמצעות הפרדה בין בחירת פעולת ההמשך לבין הערכת הערך שלה.

הרעיון הכללי: אם רשת אחת בוחרת איזו פעולה נראית הטובה ביותר, ורשת אחרת, שטעויותיה שונות, נותנת את הערך של אותה פעולה, ההטיה כלפי מעלה קטנה. יש לנו כבר שתי רשתות מ־DQN, ולכן השינוי במימוש קטן מאוד: שורה אחת בחישוב היעד. הרעיון הוצג ב־2015 במאמר של Hado van Hasselt, ‏Arthur Guez ו־David Silver מ־DeepMind, Deep Reinforcement Learning with Double Q-learning, שהראה שהאופטימיות של DQN אכן מופיעה במשחקי Atari ושההפרדה בין בחירה להערכה משפרת את התוצאות.

העמוד הראשון של המאמר Deep Reinforcement Learning with Double Q-learning
העמוד הראשון של המאמר שהציג את DDQN בשנת 2015.

DQN ו־DDQN זה לצד זה

הדרך הפשוטה ביותר לראות את ההבדל היא להציב את שני האלגוריתמים זה לצד זה. משמאל האלגוריתם DQN כפי שלמדנו ב־ד.11, ומימין DDQN. כל שורה זהה, פרט לשורה אחת בחלק האימון, המסומנת באדום: מציאת הפעולה a′ למצב הבא s′. ב־DQN מוצאים אותה בעזרת רשת המטרה Q̂; ב־DDQN מוצאים אותה בעזרת הרשת הראשית Q. חישוב ה־loss עצמו לא השתנה: את הערך של a′ עדיין נותנת רשת המטרה.

DQN
Initialize main network Q(s, a; w) with random weights w
Initialize target network Q̂(s, a; w⁻) and copy: w⁻ ← w
Initialize replay buffer RB with capacity N
For each episode (game):
    Initialize s
    While s is not terminal:
        # --- Sample the environment ---
        Choose a using Q(s, a; w) and epsilon-greedy
        Interact with environment, get r, s', done
        Store (s, a, r, s', done) in RB
        s = s'
 
        # --- Train the model ---
        Sample minibatch (s, a, r, s', done) from RB
        Calculate Q(s, a; w) – forward
        Find a' for s' using Q̂(s', a'; w⁻)
        target = r + (1 − done) · γ · Q̂(s', a'; w⁻)
        loss = (target − Q(s, a; w))²
        loss.backward()
        optimizer.step()
    Every C episodes: w⁻ ← w
DDQN
Initialize main network Q(s, a; w) with random weights w
Initialize target network Q̂(s, a; w⁻) and copy: w⁻ ← w
Initialize replay buffer RB with capacity N
For each episode (game):
    Initialize s
    While s is not terminal:
        # --- Sample the environment ---
        Choose a using Q(s, a; w) and epsilon-greedy
        Interact with environment, get r, s', done
        Store (s, a, r, s', done) in RB
        s = s'
 
        # --- Train the model ---
        Sample minibatch (s, a, r, s', done) from RB
        Calculate Q(s, a; w) – forward
        Find a' for s' using Q(s', a'; w)
        target = r + (1 − done) · γ · Q̂(s', a'; w⁻)
        loss = (target − Q(s, a; w))²
        loss.backward()
        optimizer.step()
    Every C episodes: w⁻ ← w

במילים: האימון של DDQN דומה מאוד לאימון של DQN, עם שינוי אחד בלבד. הפעולה max ביעד של DQN עושה שני דברים בבת אחת: היא בוחרת את הפעולה בעלת הערך הגבוה ביותר במצב הבא, וגם מחזירה את הערך הזה, ושניהם מרשת המטרה. ב־DDQN מפצלים את שני התפקידים בין שתי הרשתות: הרשת הראשית בוחרת את a′, ורשת המטרה מעריכה את הפעולה שנבחרה. הבחירה של a′ היא חמדנית, ללא ε-greedy, ובוחנים בה רק פעולות חוקיות. במצב סופי (done=1) המכפלה (1 − done) מאפסת את ערך ההמשך, והיעד בשתי השיטות הוא התגמול r בלבד, כמו ב־DQN. שתי רשתות ומאגר דגימות כבר קיימים ב־DQN; הם אינם החידוש של DDQN. השם "Double" מתייחס להפרדת התפקידים, לא למספר הרשתות.

דוגמה מספרית

ההבדל בין השורות נראה קטן, ולכן כדאי לראות אותו על מספרים. נניח שבמצב הבא s′ יש שתי פעולות חוקיות, וכל רשת נותנת להן הערכה משלה:

פעולההרשת הראשית Qרשת המטרה Q̂
A0.80.4
B0.60.9

עבור r=0 ו־γ=0.9, ‏DQN מוצא את a′ בעזרת רשת המטרה: הערך הגבוה ביותר בעמודת המטרה הוא 0.9 (פעולה B), ולכן היעד הוא 0.9×0.9=0.81. ‏DDQN מוצא את a′ בעזרת הרשת הראשית: בעמודת הראשית 0.8 גדול מ־0.6, ולכן a′=A. את הערך של A לוקחים מרשת המטרה, 0.4, והיעד הוא 0.9×0.4=0.36. שימו לב ששתי הרשתות חלוקות ביניהן איזו פעולה עדיפה, וזה בדיוק המצב שבו ההפרדה משנה את היעד. המספרים הומצאו להמחשת ההבדל; אין כאן ידיעה מהו הערך האמיתי או הוכחה שהיעד הנמוך תמיד נכון יותר.

במימוש איקס עיגול מ־ד.12, השינוי נמצא בפונקציה לחישוב ערכי ההמשך של האצווה: במקום לקחת את המקסימום מרשת המטרה, הרשת הראשית בוחרת פעולה חוקית ורשת המטרה מעריכה אותה. יתר לולאת האימון נשארת כפי שהיא: אותו מאגר, אותו סנכרון של רשת המטרה, אותו צעד אימון.