ML Learning Hub
التعلم التعزيزيمتقدم

التعلم المعزز

وكيل يتعلم بالفعل — تعظيم المكافأة التراكمية من خلال التفاعل بالتجربة والخطأ

صياغة MDP ومعادلات Bellman وQ-learning والشبكات DQN وتدرجات السياسة وPPO — مع تصور تفاعلي يُظهر تقارب قيم Q عبر 200 حلقة.

55 min
12 مخططات
8 المفاهيم المغطاة

المتطلبات الأساسية

Probability & Statistics
Neural Networks
Calculus & Optimization

المفاهيم المغطاة

MDPBellman EquationQ-LearningDQNPolicy GradientPPORLHFExploration vs Exploitation

الصيغ الرئيسية

معادلة بيلمان

قيمة Q المثلى: المكافأة الفورية + أفضل قيمة مستقبلية مخصومة. الهدف العودي الذي يتقارب إليه Q-learning

تحديث Q-Learning

تحريك التقدير الحالي نحو هدف بيلمان بخطوة α (التعلم بالفرق الزمني)

تدرج السياسة (REINFORCE)

زيادة احتمال الأفعال التي أدت إلى عوائد عالية، وتقليله للأفعال ذات العوائد المنخفضة

هدف PPO مع القطع

تحسين السياسة القريبة: يقطع نسبة تحديث السياسة لتبقى في [1-ε, 1+ε] — تدريب مستقر بالدُّفعات الكبيرة

محاكاة تفاعلية

Loading visualization…
🎯

التعلم بالممارسة — نموذج التعلم التعزيزي

motivation

يحتاج التعلم الخاضع للإشراف إلى أمثلة مُعلَّمة. يحتاج التعلم التعزيزي فقط إلى إشارة مكافأة — ردود فعل على ما إذا كان الفعل جيداً أم سيئاً. هكذا يتعلم البشر المشي واللعب والقيادة: من خلال الممارسة والتغذية الراجعة والتحسين التدريجي للاستراتيجية. نجاحات RL: هزم AlphaGo بطل العالم في Go (2016) — دُرِّب بـRL بعد تدريب مسبق خاضع للإشراف. يستخدم ChatGPT / GPT-4 RLHF لمحاذاة مخرجات النموذج مع التفضيلات البشرية. تُدرّب أنظمة التلاعب الروبوتي سياساتها في المحاكاة ثم تنقلها إلى الأجهزة الحقيقية.

تعلّم AlphaZero من DeepMind الشطرنج والغو والشوغي على المستوى فوق البشري في 24 ساعة من اللعب الذاتي — دون سجلات ألعاب بشرية، تعلم تعزيزي خالص من اللعب العشوائي ومكافأة الفوز.

💡

إطار عمل RL: الوكيل، البيئة، MDP

intuition

**عملية قرار ماركوف (MDP):** (S, A, T, R, γ) — حالات S، أفعال A، دالة انتقال T(s'|s,a)، مكافأة R(s,a,s')، خصم γ∈[0,1]. **الوكيل:** في كل خطوة زمنية t، يلاحظ الحالة sₜ، يتخذ الفعل aₜ وفق السياسة π(aₜ|sₜ)، يتلقى المكافأة rₜ. **الهدف:** إيجاد السياسة π* التي تُعظّم العائد المخصوم المتوقع Gₜ = Σᵢ γⁱrₜ₊ᵢ. **دالة Q(s,a):** العائد المتوقع بدءاً من الحالة s مع اتخاذ الفعل a ثم اتباع السياسة المثلى. **تمييز رئيسي:** RL بدون نموذج (Q-learning, PPO) يتعلم مباشرةً من التفاعل دون معرفة T. RL بنموذج (Dyna, MuZero) يتعلم نموذج عالم T̂ ويخطط في الخيال.

يتحكم معامل الخصم γ في قصر النظر: γ=0.99 يجعل الوكيل يهتم بالمكافآت 100 خطوة في المستقبل؛ γ=0 جشع بحت. معظم المسائل تحتاج γ∈[0.95, 0.999].

⚙️

التعلم بـQ: الجدولي والعميق (DQN)

algorithm
1

ابدأ جدول Q: Q(s,a)=0 لجميع أزواج الحالة-الفعل (جدولي) أو شبكة Q ذات معاملات θ (DQN).

2

لكل حلقة: أعِد تهيئة البيئة، لاحظ الحالة الأولية s.

3

اختيار الفعل ε-جشع: باحتمال ε اختر فعلاً عشوائياً (استكشاف)، وإلا اختر argmax_a Q(s,a) (استغلال). قلّص ε من 1.0 → 0.05 خلال التدريب.

4

نفّذ الفعل a، لاحظ المكافأة r والحالة التالية s'. خزّن (s,a,r,s') في ذاكرة التشغيل (DQN).

5

تحديث TD: Q(s,a) ← Q(s,a) + α[r + γ·max_a' Q(s',a') - Q(s,a)].

6

إضافات DQN: (1) إعادة تشغيل التجربة — دُفعات عشوائية لكسر الارتباطات. (2) الشبكة المستهدفة — نسخة مجمّدة Q_هدف(θ⁻)، تُزامن كل N خطوة. (3) DQN المزدوج — فصل اختيار الفعل عن تقدير القيمة لتقليل المبالغة.

7

التقارب: يتقارب Q-learning الجدولي إلى Q* للـMDPs المحدودة مع استكشاف كافٍ. شبكات Q العصبية غير مضمونة لكنها تعمل جيداً عملياً.

</>

تعلم Q وDQN من الصفر

code
python113 lines
import numpy as np
import gymnasium as gym
from collections import deque
import torch, torch.nn as nn, torch.optim as optim

class="tok-comment"># ── class="tok-num">1. Tabular Q-Learning (FrozenLake) ───────────────────────────────────────
env = gym.make(class="tok-str">"FrozenLake-v1", is_slippery=False)
n_states, n_actions = env.observation_space.n, env.action_space.n

Q = np.zeros((n_states, n_actions))
alpha = class="tok-num">0.8          class="tok-comment"># learning rate
gamma = class="tok-num">0.95         class="tok-comment"># discount
epsilon = class="tok-num">1.0        class="tok-comment"># exploration rate

for episode in range(class="tok-num">2000):
    s, _ = env.reset()
    done = False
    while not done:
        class="tok-comment"># ε-greedy
        if np.random.random() < epsilon:
            a = env.action_space.sample()
        else:
            a = np.argmax(Q[s])

        s_next, r, terminated, truncated, _ = env.step(a)
        done = terminated or truncated

        class="tok-comment"># Q-learning update (Bellman target)
        td_target = r + gamma * np.max(Q[s_next]) * (class="tok-num">1 - terminated)
        Q[s, a] += alpha * (td_target - Q[s, a])
        s = s_next

    epsilon = max(class="tok-num">0.01, epsilon * class="tok-num">0.999)   class="tok-comment"># decay exploration

class="tok-comment"># Evaluate greedy policy
n_wins = class="tok-num">0
for _ in range(class="tok-num">100):
    s, _ = env.reset()
    done = False
    while not done:
        a = np.argmax(Q[s])
        s, r, terminated, truncated, _ = env.step(a)
        done = terminated or truncated
    if r == class="tok-num">1.0:      class="tok-comment"># reached the goal
        n_wins += class="tok-num">1
print(fclass="tok-str">"Win rate: {n_wins/class="tok-num">100:.class="tok-num">0%}")

class="tok-comment"># ── class="tok-num">2. Deep Q-Network (CartPole) ─────────────────────────────────────────────
class DQN(nn.Module):
    def __init__(self, obs_dim, n_actions):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(obs_dim, class="tok-num">128), nn.ReLU(),
            nn.Linear(class="tok-num">128, class="tok-num">128),    nn.ReLU(),
            nn.Linear(class="tok-num">128, n_actions)
        )
    def forward(self, x): return self.net(x)

env = gym.make(class="tok-str">"CartPole-v1")
obs_dim = env.observation_space.shape[class="tok-num">0]
n_actions = env.action_space.n

q_net    = DQN(obs_dim, n_actions)
q_target = DQN(obs_dim, n_actions)    class="tok-comment"># frozen target network
q_target.load_state_dict(q_net.state_dict())

optimizer  = optim.Adam(q_net.parameters(), lr=class="tok-num">1e-3)
replay     = deque(maxlen=10_000)     class="tok-comment"># experience replay buffer
gamma      = class="tok-num">0.99
epsilon    = class="tok-num">1.0
batch_size = class="tok-num">64
target_update_freq = class="tok-num">100
steps = class="tok-num">0

for episode in range(class="tok-num">500):
    s, _ = env.reset()
    total_reward = class="tok-num">0
    done = False
    while not done:
        class="tok-comment"># ε-greedy action
        if np.random.random() < epsilon:
            a = env.action_space.sample()
        else:
            with torch.no_grad():
                a = q_net(torch.FloatTensor(s)).argmax().item()

        s_next, r, terminated, truncated, _ = env.step(a)
        done = terminated or truncated
        replay.append((s, a, r, s_next, terminated))
        s = s_next; total_reward += r; steps += class="tok-num">1

        class="tok-comment"># Train when buffer has enough samples
        if len(replay) >= batch_size:
            batch = [replay[i] for i in np.random.choice(len(replay), batch_size, replace=False)]
            S, A, R, S_next, D = map(np.array, zip(*batch))
            S_t = torch.FloatTensor(S); A_t = torch.LongTensor(A)
            R_t = torch.FloatTensor(R); S_next_t = torch.FloatTensor(S_next)
            D_t = torch.FloatTensor(D)

            with torch.no_grad():
                max_next_q = q_target(S_next_t).max(class="tok-num">1)[class="tok-num">0]
                target = R_t + gamma * max_next_q * (class="tok-num">1 - D_t)

            current_q = q_net(S_t).gather(class="tok-num">1, A_t.unsqueeze(class="tok-num">1)).squeeze()
            loss = nn.functional.mse_loss(current_q, target)
            optimizer.zero_grad(); loss.backward(); optimizer.step()

        if steps % target_update_freq == class="tok-num">0:
            q_target.load_state_dict(q_net.state_dict())

    epsilon = max(class="tok-num">0.05, epsilon * class="tok-num">0.995)
    if episode % class="tok-num">50 == class="tok-num">0:
        print(fclass="tok-str">"Episode {episode:4d} | reward={total_reward:class="tok-num">5.0f} | ε={epsilon:.3f}")

تدرج السياسة والفاعل-الناقد (A2C/PPO)

math

تُحسّن أساليب تدرج السياسة مباشرةً السياسةَ π_θ بدلاً من دالة قيمة. تستخدم بنية الفاعل-الناقد شبكتين: الفاعل π_θ يختار الأفعال، والناقد V_φ يُقدّر قيم الحالة كخط أساسي لتقليل تباين التدرج. تُضيف PPO (تحسين السياسة القريبة) آلية قطع لمنع تحديثات السياسة المدمرة الكبيرة — نسبة r_t(θ) = π_θ(a|s)/π_θ_القديمة(a|s) مقطوعة إلى [1-ε, 1+ε]. يجعل هذا PPO كافياً في كفاءة العينات للاستخدام العملي وهو الخوارزمية القياسية في RLHF لـLLMs.

الميزة، خسارة A2C مع مكافأة الإنتروبيا، PPO مع القطع
⚠️

الثالوث المميت وأوضاع فشل RL الشائعة

pitfall

الثالوث المميت (Sutton & Barto): الجمع بين (1) تقريب الدوال (الشبكات العصبية)، (2) الإقلاع (تحديثات TD)، و(3) التعلم خارج السياسة قد يُسبّب التباعد. يتجنب DQN هذا بذاكرة التشغيل والشبكات المستهدفة لكن التدريب قد يظل غير مستقر. مخاطر RL العملية: (1) تشكيل المكافآت قد يُدخل اختصارات غير مقصودة — وكيل سباق القوارب الذي تعلّم الدوران في دوائر لجمع المكافآت. (2) المكافآت النادرة تجعل الاستكشاف شبه مستحيل — استخدم الدافعية الداخلية بحذر. (3) الفجوة بين المحاكاة والواقع — السياسات المدرّبة في المحاكاة تفشل على الروبوتات الحقيقية بسبب الفيزياء غير المُنمذجة. (4) التقييم بنقاط ابتداء ثابتة مضلِّل — أبلغ عن المتوسط ± الانحراف المعياري عبر 10+ نقاط ابتداء.

تعلّم وكيل سباق القوارب من OpenAI المدرَّب بمكافآت مُشكَّلة القيادةَ في دوائر لجمع العناصر بدلاً من إنهاء السباق — حالة فشل شهيرة لاختراق المكافأة.

?اختبار المعرفة

يتم حفظ التقدم في متصفحك — لا حاجة لحساب.

تحتاج مهندس ذكاء اصطناعي أو عالم بيانات؟

أبني نماذج تعلم آلي مخصصة، ووكلاء ذكاء اصطناعي، ورؤية حاسوب، وأتمتة — من الفكرة إلى الإنتاج.