فاز 9 · درس 6

آموزش گرادیان سیاست و پیاده‌سازی الگوریتم REINFORCE از صفر

نوع
ساختنی
زمان
حدود 75 دقیقه
زبان‌ها
Python
پیش‌نیاز
فاز 3 · درس 03 (انتشار رو به عقب یا Backpropagation)، فاز 9 · درس 03 (روش‌های مونت‌کارلو)، فاز 9 · درس 04 (یادگیری تفاوت زمانی یا TD Learning)
یک صفحه مشبک چهار در چهار که مسیرهای نوری روی آن رسم شده و فلش‌های برداری در جهت صعود یک تپه تغییر جهت می‌دهند
فهرست مطالب
  1. صورت مسئله
  2. مفاهیم پایه
  3. پیاده‌سازی
  4. گام 1: شبکه‌ی سیاست سافت‌مکس
  5. گام 2: نمونه‌برداری و محاسبه‌ی لگاریتم احتمال
  6. گام 3: اجرای Rollout همراه با ثبت لگاریتم احتمالات
  7. گام 4: به‌روزرسانی با REINFORCE
  8. گام 5: خطوط مبنا
  9. چالش‌ها و دام‌ها
  10. کاربردهای واقعی
  11. ارائه‌ی خروجی
  12. تمرین‌ها
  13. اصطلاحات کلیدی
  14. برای مطالعه‌ی بیشتر

در روش‌های مرسوم یادگیری تقویتی مثل Q-learning، تمرکز روی تخمین تابع ارزش است و تصمیم‌ها با انتخاب بیشینه‌ی ارزش اتخاذ می‌شوند. اما وقتی با فضاهای پیوسته روبه‌رو هستید یا نیاز به سیاستی تصادفی دارید، این فرمول‌بندی به بن‌بست می‌خورد. گرادیان سیاست (Policy Gradient) این محدودیت را با پارامتری‌سازی مستقیم خودِ سیاست و بهینه‌سازی آن با صعود گرادیانی حل می‌کند.

الگوریتم REINFORCE نقطه‌ی آغاز این مسیر است؛ زیربنای ریاضیاتی تمام روش‌های مدرن ترازسازی مدل‌های زبانی مانند PPO، GRPO و DPO بر همین قضیه استوار است. درک شهودی و پیاده‌سازی این الگوریتم از صفر به شما کمک می‌کند سازوکار واقعی حلقه‌های یادگیری تقویتی در LLMها را از پشت صحنه کدهای آماده عمیقاً بشناسید.

برای اجرای کدهای این درس و آزمایش آن روی محیط‌های پایه‌ای نیازی به سرورهای ابری گران‌قیمت یا پردازنده‌های گرافیکی خارجی نیست؛ تمام پیاده‌سازی‌ها و شبیه‌سازی‌ها به‌راحتی روی CPU سیستم شخصی شما اجرا می‌شوند.

تخمین ارزش را کنار بگذارید. سیاست (policy) را مستقیماً پارامتری کنید، گرادیان بازده مورد انتظار را به دست آورید و در جهت صعود گام بردارید. ویلیامز (1992) این ایده را در قالب یک قضیه فرمول‌بندی کرد؛ همان بنیانی که PPO، GRPO و تمام حلقه‌های یادگیری تقویتی در مدل‌های زبانی بزرگ (LLM) بر پایه‌ی آن وجود دارند.

صورت مسئله

روش‌های Q-learning و DQN تابع ارزش (value) را پارامتری می‌کنند و اکشن‌ها با argmax Q انتخاب می‌شوند. این رویکرد برای اکشن‌ها و حالت‌های گسسته خوب جواب می‌دهد؛ اما وقتی اکشن‌ها پیوسته باشند (چطور روی گشتاور در یک فضای 10 بعدی argmax بگیریم؟) یا وقتی سیاستی تصادفی (stochastic) بخواهید (argmax بر حسب ساختار همواره قطعی است)، کارایی خود را از دست می‌دهد.

در مقابل، گرادیان‌های سیاست مستقیماً خودِ سیاست را پارامتری می‌کنند. πθ(a∣s)\pi_\theta(a \mid s) یک شبکه‌ی عصبی است که توزیعی روی اکشن‌ها تولید می‌کند. برای عمل کردن، از همین توزیع نمونه برمی‌دارید؛ سپس گرادیان بازده مورد انتظار را نسبت به θ\theta حساب کرده و در جهت صعود گام برمی‌دارید. دیگر نه خبری از argmax است و نه رابطه‌ی بازگشتی بلمن (Bellman recursion)؛ فقط صعود گرادیانی روی J(θ)=Eπθ[G]J(\theta) = \mathbb E_{\pi_\theta}[G].

قضیه‌ی REINFORCE (ویلیامز 1992) نشان می‌دهد که این گرادیان قابل محاسبه است: ∇J(θ)=Eπ[G⋅∇θlog⁡πθ(a∣s)]\nabla J(\theta) = \mathbb E_\pi[ G \cdot \nabla_\theta \log \pi_\theta(a \mid s) ]. یک اپیزود اجرا کنید، بازده را به دست آورید، آن را در هر گام در ∇log⁡πθ(a∣s)\nabla \log \pi_\theta(a \mid s) ضرب کنید، میانگین بگیرید و با صعود گرادیانی پیش بروید؛ کار تمام است.

تمام الگوریتم‌های RL برای LLMها در سال 2026 — مثل PPO، DPO و GRPO — نسخه‌های بهبودیافته‌ی REINFORCE هستند. تسلط کامل و عملی بر این مفهوم، پیش‌نیاز ادامه‌ی این فاز و همچنین درس 07 فاز 10 (پیاده‌سازی RLHF) و درس 08 فاز 10 (DPO) است.

مفاهیم پایه

Policy gradient: softmax policy, log-π gradient, return-weighted update

قضیه‌ی گرادیان سیاست. به ازای هر سیاست πθ\pi_\theta که با θ\theta پارامتری شده باشد:

∇J(θ)=Eτ∼πθ[∑t=0TGt⋅∇θlog⁡πθ(at∣st)]\nabla J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta}[ \sum_{t=0}^{T} G_t \cdot \nabla_\theta \log \pi_\theta(a_t \mid s_t) ]

که در آن Gt=∑k=tTγk−trk+1G_t = \sum_{k=t}^{T} \gamma^{k-t} r_{k+1} بازده تنزیل‌شده از گام tt است. امید ریاضی روی مسیرهای کامل (trajectories) یعنی τ\tau گرفته می‌شود که از πθ\pi_\theta نمونه‌برداری شده‌اند.

اثبات آن کوتاه است. از J(θ)=∑τP(τ;θ)G(τ)J(\theta) = \sum_\tau P(\tau; \theta) G(\tau) زیر نماد امید ریاضی مشتق بگیرید. از ترفند مشتق لگاریتم (log-derivative trick) یعنی ∇P(τ;θ)=P(τ;θ)∇log⁡P(τ;θ)\nabla P(\tau; \theta) = P(\tau; \theta) \nabla \log P(\tau; \theta) استفاده کنید. log⁡P(τ;θ)=∑log⁡πθ(at∣st)+environment terms that do not depend on θ\log P(\tau; \theta) = \sum \log \pi_\theta(a_t \mid s_t) + \text{environment terms that do not depend on } \theta را فاکتور بگیرید. جملات مربوط به محیط حذف می‌شوند. با دو خط محاسبات جبری ساده به قضیه می‌رسید.

ترفندهای کاهش واریانس. الگوریتم پایه‌ی REINFORCE واریانس بسیار بالایی دارد؛ بازده‌ها نویزی هستند، ∇log⁡π\nabla \log \pi نویزی است و حاصل‌ضرب آن‌ها به شدت نویز دارد. دو راهکار استاندارد برای این مشکل وجود دارد:

  1. تفریق خط مبنا (Baseline). جایگزین کردن GtG_t با Gt−b(st)G_t - b(s_t) به ازای هر خط مبنای b(st)b(s_t) که به ata_t وابسته نباشد. این تغییر نااریب است، چون E[b(st)⋅∇log⁡π(at∣st)]=0\mathbb{E}[b(s_t) \cdot \nabla \log \pi(a_t \mid s_t)] = 0. انتخاب معمول: b(st)=V^(st)b(s_t) = \hat{V}(s_t) که توسط منتقد (critic) یاد گرفته می‌شود ← روش‌های بازیگر-منتقد (Actor-Critic) در درس 07.
  2. پاداش باقی‌مانده (Reward-to-go). جایگزین کردن ∑tGt⋅∇log⁡πθ(at∣st)\sum_t G_t \cdot \nabla \log \pi_\theta(a_t \mid s_t) با ∑tGtfrom t⋅∇log⁡πθ(at∣st)\sum_t G_t^{\text{from } t} \cdot \nabla \log \pi_\theta(a_t \mid s_t). برای یک اکشن مشخص، فقط بازده‌های آینده اهمیت دارند؛ پاداش‌های گذشته نویزی با میانگین صفر وارد محاسبات می‌کنند.

با ترکیب این دو مورد، به این رابطه می‌رسید:

∇J≈(1/N)∑i=1N∑t=0Ti[Gt(i)−V^(st(i))]⋅∇θlog⁡πθ(at(i)∣st(i))\nabla J \approx (1/N) \sum_{i=1}^{N} \sum_{t=0}^{T_i} [ G_t^{(i)} - \hat{V}(s_t^{(i)}) ] \cdot \nabla_\theta \log \pi_\theta(a_t^{(i)} \mid s_t^{(i)})

این همان الگوریتم REINFORCE با خط مبنا است؛ جد مستقیم A2C (درس 07) و PPO (درس 08).

پارامتری‌سازی سیاست با سافت‌مکس. برای اکشن‌های گسسته، انتخاب استاندارد به این صورت است:

πθ(a∣s)=exp⁡(fθ(s,a))/∑a′exp⁡(fθ(s,a′))\pi_\theta(a \mid s) = \exp(f_\theta(s, a)) / \sum_{a'} \exp(f_\theta(s, a'))

که در آن fθf_\theta هر شبکه‌ی عصبی دلخواهی است که به ازای هر اکشن یک امتیاز خروجی می‌دهد. گرادیان فرم بسیار تمیزی دارد:

∇θlog⁡πθ(a∣s)=∇θfθ(s,a)−∑a′πθ(a′∣s)∇θfθ(s,a′)\nabla_\theta \log \pi_\theta(a \mid s) = \nabla_\theta f_\theta(s, a) - \sum_{a'} \pi_\theta(a' \mid s) \nabla_\theta f_\theta(s, a')

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

سیاست گاوسی برای اکشن‌های پیوسته. πθ(a∣s)=N(μθ(s),σθ(s))\pi_\theta(a \mid s) = N(\mu_\theta(s), \sigma_\theta(s)). عبارت ∇log⁡N(a;μ,σ)\nabla \log N(a; \mu, \sigma) فرم بسته (closed-form) دارد؛ و این دقیقاً تمام چیزی است که SAC در درس 07 فاز 9 به آن نیاز دارد.

گرادیان خط‌مشینرخ یادگیری را تغییر دهید
POLICY GRADIENTPolicy gradient methods adjust the policy parameter theta in the direction that raises expected reward. Here the grey curve is the reward landscape and the dots are ascent steps climbing toward the peak. A small rate creeps up slowly; too large a rate overshoots; a local bump on the left can trap the climb if it starts there.
روش‌های گرادیان خط‌مشی، پارامتر خط‌مشی (theta) را در جهتی تنظیم می‌کنند که پاداش مورد انتظار افزایش یابد. در اینجا منحنی خاکستری نمایانگر چشم‌انداز پاداش و نقاط نشان‌دهنده گام‌های صعود به سمت قله هستند. نرخ یادگیری کوچک بسیار کند پیش می‌رود؛ نرخ بیش از حد بزرگ باعث پرش از روی قله می‌شود؛ و برجستگی محلی سمت چپ در صورت شروع از آن نقطه می‌تواند صعود را به دام بیندازد.

پیاده‌سازی

گام 1: شبکه‌ی سیاست سافت‌مکس

def policy_logits(theta, state_features):
    return [dot(theta[a], state_features) for a in range(N_ACTIONS)]

def softmax(logits):
    m = max(logits)
    exps = [exp(l - m) for l in logits]
    Z = sum(exps)
    return [e / Z for e in exps]

برای یک محیط جدولی (tabular) از یک سیاست خطی (یک بردار وزن به ازای هر اکشن) استفاده کنید. برای بازی‌های Atari، به جای آن یک CNN بگذارید و سرِ (head) سافت‌مکس را دست‌نخورده نگه دارید.

گام 2: نمونه‌برداری و محاسبه‌ی لگاریتم احتمال

def sample_action(probs, rng):
    x = rng.random()
    cum = 0
    for a, p in enumerate(probs):
        cum += p
        if x <= cum:
            return a
    return len(probs) - 1

def log_prob(probs, a):
    return log(probs[a] + 1e-12)

گام 3: اجرای Rollout همراه با ثبت لگاریتم احتمالات

def rollout(theta, env, rng, gamma):
    trajectory = []
    s = env.reset()
    while not done:
        logits = policy_logits(theta, s)
        probs = softmax(logits)
        a = sample_action(probs, rng)
        s_next, r, done = env.step(s, a)
        trajectory.append((s, a, r, probs))
        s = s_next
    return trajectory

گام 4: به‌روزرسانی با REINFORCE

def reinforce_step(theta, trajectory, gamma, lr, baseline=0.0):
    returns = compute_returns(trajectory, gamma)
    for (s, a, _, probs), G in zip(trajectory, returns):
        advantage = G - baseline
        grad_log_pi_a = [-p for p in probs]
        grad_log_pi_a[a] += 1.0
        for i in range(N_ACTIONS):
            for j in range(len(s)):
                theta[i][j] += lr * advantage * grad_log_pi_a[i] * s[j]

گرادیان ∇log⁡π(a∣s)=ea−π(⋅∣s)\nabla \log \pi(a \mid s) = e_a - \pi(\cdot \mid s) (بردار one-hot اکشن aa منهای احتمالات) هسته‌ی اصلی گرادیان‌های سیاست سافت‌مکس است. این فرمول را در حافظه‌ی عضلانی خود حک کنید.

گام 5: خطوط مبنا

میانگین متحرک GG روی اپیزودهای اخیر، کاهش واریانس کافی را برای حل یک محیط GridWorld ابعاد 4×4 فراهم می‌کند؛ این محیط پس از حدود 500 اپیزود همگرا می‌شود. اگر خط مبنا را به یک مدل یادگیرنده‌ی V^(s)\hat{V}(s) ارتقا دهید، الگوریتم بازیگر-منتقد حاصل می‌شود.

چالش‌ها و دام‌ها

  • انفجار گرادیان (Exploding gradients). بازده‌ها ممکن است بسیار بزرگ شوند. همیشه پیش از ضرب در ∇log⁡π\nabla \log \pi، مقدار GG را در سطح کل بچ (batch) به فرم ~N(0, 1) نرمال‌سازی کنید.
  • فروپاشی آنتروپی (Entropy collapse). سیاست خیلی زود به سمت اکشنی نزدیک به قطعی همگرا می‌شود، اکتشاف متوقف خواهد شد و مدل در جا می‌زند. راه‌حل: افزودن جریمه‌ی آنتروپی (entropy bonus) یعنی β⋅H(π(⋅∣s))\beta \cdot H(\pi(\cdot \mid s)) به تابع هدف.
  • واریانس بالا. الگوریتم پایه‌ی REINFORCE به هزاران اپیزود نیاز دارد. خط مبنای منتقد (درس 07) یا ناحیه‌ی اعتماد در TRPO/PPO (درس 08) راهکارهای استاندارد این مشکل هستند.
  • ناکارآمدی در مصرف نمونه (Sample inefficiency). هم‌سیاست بودن (On-policy) یعنی پس از یک بار به‌روزرسانی، باید تمام ترنزیشن‌های جمع‌آوری‌شده را دور بریزید. اصلاحات ناهم‌سیاست (Off-policy) با نمونه‌برداری اهمیتی (importance sampling)، امکان استفاده‌ی مجدد از داده‌ها را به قیمت افزایش واریانس فراهم می‌کنند (نسبت استفاده‌شده در PPO در واقع وزن نمونه‌برداری اهمیتیِ برش‌خورده یا clipped است).
  • گرادیان‌های غیرایستا (Non-stationary gradients). گرادیانی که 100 اپیزود قبل محاسبه شده از π\pi قدیمی استفاده می‌کند. به همین دلیل روش‌های هم‌سیاست، مدل را هر چند rollout یک بار به‌روزرسانی می‌کنند.
  • تخصیص اعتبار (Credit assignment). بدون استفاده از پاداش باقی‌مانده، پاداش‌های گذشته فقط نویز به همراه دارند. همیشه از پاداش باقی‌مانده استفاده کنید.

کاربردهای واقعی

در سال 2026، الگوریتم REINFORCE به‌ندرت مستقیماً اجرا می‌شود، اما فرمول گرادیان آن همه‌جا حضور دارد:

کاربرد روش مشتق‌شده
کنترل پیوسته PPO / SAC با سیاست گاوسی
آموزش RLHF برای LLM PPO با جریمه‌ی KL، روی سیاست در سطح توکن
استدلال در LLMها (DeepSeek) GRPO — الگوریتم REINFORCE با خط مبنای نسبی گروهی، بدون منتقد
سیستم‌های چندایجنت REINFORCE با منتقد متمرکز (MADDPG، COMA)
رباتیک با اکشن‌های گسسته A2C، A3C، PPO
سناریوهای صرفاً مبتنی بر ترجیحات DPO — بازنویسی REINFORCE به‌صورت تابع زیان (loss) درست‌نمایی ترجیحات، بدون نیاز به نمونه‌برداری

وقتی در اسکریپت‌های آموزشی سال 2026 خط کدی مثل loss = -advantage * log_prob می‌بینید، در واقع همان REINFORCE با خط مبنا است. مقالات کاملی (مانند DPO، GRPO، RLOO) صرفاً ترفندهایی برای کاهش واریانس روی همین یک خط کد هستند.

ارائه‌ی خروجی

کد را در مسیر outputs/skill-policy-gradient-trainer.md ذخیره کنید:

---
name: policy-gradient-trainer
description: Produce a REINFORCE / actor-critic / PPO training config for a given task and diagnose variance issues.
version: 1.0.0
phase: 9
lesson: 6
tags: [rl, policy-gradient, reinforce]
---

Given an environment (discrete / continuous actions, horizon, reward stats), output:

1. Policy head. Softmax (discrete) or Gaussian (continuous) with parameter counts.
2. Baseline. None (vanilla), running mean, learned `V̂(s)`, or A2C critic.
3. Variance controls. Reward-to-go on by default, return normalization, gradient clip value.
4. Entropy bonus. Coefficient β and decay schedule.
5. Batch size. Episodes per update; on-policy data freshness contract.

Refuse REINFORCE-no-baseline on horizons > 500 steps. Refuse continuous-action control with a softmax head. Flag any run with `β = 0` and observed policy entropy < 0.1 as entropy-collapsed.

تمرین‌ها

  1. ساده. الگوریتم REINFORCE را روی محیط 4×4 GridWorld با یک سیاست خطی سافت‌مکس پیاده‌سازی کنید. مدل را برای 1,000 اپیزود بدون خط مبنا آموزش دهید. منحنی یادگیری (learning curve) را رسم کنید و واریانس (انحراف معیار بازده‌ها) را بسنجید.
  2. متوسط. یک خط مبنای میانگین متحرک اضافه کنید و دوباره آموزش را اجرا کنید. بهره‌وری نمونه‌ها و واریانس را با حالت پایه مقایسه کنید. خط مبنا تعداد گام‌های لازم برای همگرایی را چقدر کاهش می‌دهد؟
  3. سخت. جریمه‌ی آنتروپی β⋅H(π)\beta \cdot H(\pi) را اضافه کنید. پارامتر β∈{0,0.01,0.1,1.0}\beta \in \lbrace 0, 0.01, 0.1, 1.0 \rbrace را جستجو (sweep) کنید. بازده نهایی و آنتروپی سیاست را رسم کرده و نقطه‌ی تعادل بهینه‌ی این مسئله را پیدا کنید.

اصطلاحات کلیدی

اصطلاح در گفتار عامیانه معنای دقیق فنی
گرادیان سیاست (Policy gradient) «آموزش مستقیم سیاست» ∇J(θ)=E[G⋅∇log⁡πθ(a∣s)]\nabla J(\theta) = \mathbb{E}[G \cdot \nabla \log \pi_\theta(a \mid s)]؛ به‌دست‌آمده از ترفند مشتق لگاریتم.
REINFORCE «الگوریتم اولیه‌ی PG» اثر ویلیامز (1992)؛ بازده‌های مونت‌کارلو ضرب‌در گرادیان لگاریتمِ سیاست.
ترفند مشتق لگاریتم (Log-derivative trick) «برآوردگر تابع امتیاز» ∇P(τ;θ)=P(τ;θ)⋅∇log⁡P(τ;θ)\nabla P(\tau;\theta) = P(\tau;\theta) \cdot \nabla \log P(\tau;\theta)؛ گرادیان‌گیری از امید ریاضی را ممکن می‌کند.
خط مبنا (Baseline) «کاهش واریانس» هر b(s)b(s) که از GG کم شود؛ نااریب است چون E[b⋅∇log⁡π]=0\mathbb{E}[b \cdot \nabla \log \pi] = 0.
پاداش باقی‌مانده (Reward-to-go) «فقط بازده‌های آینده حساب می‌شوند» استفاده از Gtfrom tG_t^{\text{from } t} به جای کل G0G_0؛ فرمولی صحیح با واریانس کمتر.
جریمه‌ی آنتروپی (Entropy bonus) «تشویق به اکتشاف» عبارت +β⋅H(π(⋅∣s))+\beta \cdot H(\pi(\cdot \mid s)) که مانع از فروپاشی سیاست می‌شود.
هم‌سیاست (On-policy) «آموزش روی داده‌های هم‌اکنون» امید ریاضی گرادیان نسبت به سیاست فعلی است؛ نمی‌توان داده‌های قدیمی را مستقیماً بازاستفاده کرد.
مزیت (Advantage) «چقدر بهتر از حد میانگین» A(s,a)=G(s,a)−V(s)A(s, a) = G(s, a) - V(s)؛ کمیت علامت‌داری که در REINFORCE با خط مبنا ضرب می‌شود.

برای مطالعه‌ی بیشتر

سؤالات متداول

چرا به جای Q-learning از گرادیان سیاست و REINFORCE استفاده می‌کنیم؟

روش‌های مبتنی بر تابع ارزش مثل Q-learning برای اکشن‌های پیوسته و سیاست‌های تصادفی ناکارآمد هستند؛ گرادیان سیاست مستقیماً توزیع اکشن‌ها را بهینه‌سازی می‌کند و نیازی به محاسبه‌ی argmax روی اکشن‌ها ندارد.

اصلی‌ترین ضعف الگوریتم REINFORCE چیست و چطور رفع می‌شود؟

واریانس بسیار بالای گرادیان‌ها ضعف اصلی آن است. این مشکل با تفریق خط مبنا (Baseline)، استفاده از پاداش باقی‌مانده (Reward-to-go) و نرمال‌سازی بازده‌ها تا حد زیادی کنترل می‌شود.

چرا REINFORCE را یک الگوریتم هم‌سیاست (On-policy) می‌دانند؟

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

ما رو توی گوگل بیشتر ببین

با افزودن نکست ادمین به «منابع ترجیحی» گوگل، درس‌ها و مطالب ما را در بخش اخبار برتر جستجو بیشتر می‌بینید.