فاز 9 · درس 7

یادگیری تقویتی بازیگر-نقاد: پیاده‌سازی الگوریتم‌های A2C و A3C

نوع
ساختنی
زمان
حدود 75 دقیقه
زبان‌ها
Python
پیش‌نیاز
فاز 9 · 04 (یادگیری تفاضل زمانی / TD)، فاز 9 · 06 (الگوریتم REINFORCE)
دو وزنه بر روی یک ترازوی آزمایشگاهی دقیق که نشان‌دهنده موازنه تورش و واریانس در معماری بازیگر نقاد است
فهرست مطالب
  1. صورت‌مسئله
  2. مبانی نظری
  3. پیاده‌سازی از صفر
  4. گام 1: ساخت نقاد
  5. گام 2: محاسبه‌ی مزیت n-گام
  6. گام 3: به‌روزرسانی ترکیبی
  7. گام 4: موازی‌سازی (A3C در برابر A2C)
  8. خطاهای رایج
  9. استفاده از ابزارهای واقعی
  10. خروجی این درس
  11. تمرین‌ها
  12. اصطلاحات کلیدی
  13. برای مطالعه‌ی بیشتر

اگر تا به حال الگوریتم REINFORCE را پیاده کرده باشید، احتمالاً متوجه ناپایداری شدید و نوسان‌های بسیار بالای آن در طول یادگیری شده‌اید. دلیل این مشکل، اتکا به بازده‌های مونت‌کارلو است که واریانس فوق‌العاده بالایی تولید می‌کنند و فرایند آموزش را بسیار کند و پرهزینه می‌سازند. روش بازیگر-نقاد (Actor-Critic) دقیقاً برای حل همین چالش ساخته شده است؛ یعنی استفاده از یک شبکه‌ی ارزیاب در نقش خط پایه تا واریانس گرادیان‌ها به‌شدت کاهش یابد.

درک معماری‌های A2C و A3C پایه‌ی مفهومی تمام پیشرفت‌های نوین یادگیری تقویتی عمیق نظیر PPO، SAC و حتی روش‌های ترازسازی مدل‌های زبانی مانند DPO و GRPO را تشکیل می‌دهد. کدهای این درس به گونه‌ای طراحی شده‌اند که بدون نیاز به GPUهای سنگین ابری و با حداقل پیش‌نیازها روی سیستم شخصی یا پردازنده‌های معمولی (CPU) اجرا شوند و درک شهودی و عمیقی از این ساختار به شما بدهند.

الگوریتم REINFORCE پر از نویز است. یک نقاد (critic) اضافه کنید که V^(s)\hat{V}(s) را یاد بگیرد، آن را از بازده کم کنید، و به مزیتی (advantage) برسید که امید ریاضی یکسانی دارد اما واریانس آن بسیار کمتر است. این همان بازیگر-نقاد (actor-critic) است. A2C آن را به‌صورت همگام اجرا می‌کند؛ A3C آن را روی رشته‌ها (threads) پیش می‌برد. هر دوی این‌ها مدل ذهنی پشت تک‌تک روش‌های مدرن یادگیری تقویتی (Reinforcement Learning) عمیق هستند.

صورت‌مسئله

الگوریتم پایه‌ای REINFORCE کار می‌کند، اما واریانس فاجعه‌باری دارد. بازده‌های مونت‌کارلو GtG_t ممکن است بین اپیزودهای مختلف بیش از 10 برابر نوسان کنند. ضرب کردن این نویز در ∇log⁡π\nabla \log \pi و میانگین‌گیری از آن، تخمین‌گری از گرادیان (gradient) می‌سازد که به هزاران اپیزود نیاز دارد تا خط‌مشی را به همان اندازه‌ای جابه‌جا کند که با به‌روزرسانی‌های به‌مراتب کمتری در DQN به آن می‌رسیدید.

این واریانس بالا ناشی از استفاده‌ی مستقیم از بازده‌های خام است. اگر یک خط پایه (baseline) مانند b(st)b(s_t) — یعنی هر تابعی از وضعیت، از جمله یک مقدار تخمینیِ یادگرفته‌شده — را از بازده کم کنید، امید ریاضی تغییری نمی‌کند اما واریانس افت محسوسی خواهد داشت. بهترین خط پایه‌ی عملی و در دسترس، V^(st)\hat{V}(s_t) است. حالا مقداری که در ∇log⁡π\nabla \log \pi ضرب می‌شود، همان مزیت است:

A(s,a)=G−V^(s)A(s, a) = G - \hat{V}(s)

یک عمل در صورتی خوب است که بازدهی بالاتر از میانگین ایجاد کرده باشد، و اگر پایین‌تر باشد بد است. ترکیب REINFORCE با یک نقاد یادگیرنده، همان بازیگر-نقاد است. نقاد برای بازیگر نقش یک آموزگار با واریانس پایین را ایفا می‌کند. تمام روش‌های مبتنی بر خط‌مشی عمیق پس از سال 2015 (مثل A2C، A3C، PPO، SAC و IMPALA) بر همین پایه بنا شده‌اند.

مبانی نظری

بازیگر-نقاد: شبکه‌ی خط‌مشی به همراه شبکه‌ی ارزش، خطای تفاضل زمانی به عنوان مزیت

دو شبکه، یک تابع زیان (loss) مشترک:

  • بازیگر (Actor) πθ(a∣s)\pi_\theta(a \mid s): همان خط‌مشی است؛ برای دست زدن به عمل نمونه‌گیری می‌شود و با گرادیان خط‌مشی آموزش می‌بیند.
  • نقاد (Critic) Vϕ(s)V_\phi(s): بازده مورد انتظار از یک وضعیت را تخمین می‌زند و برای کمینه‌سازی (Vϕ(s)−target)2(V_\phi(s) - \text{target})^2 آموزش داده می‌شود.

مزیت. دو حالت استاندارد دارد:

  • مزیت مونت‌کارلو (MC): At=Gt−Vϕ(st)A_t = G_t - V_\phi(s_t). بدون تورش (unbiased)، با واریانس بالاتر.
  • مزیت تفاضل زمانی (TD): At=rt+1+γVϕ(st+1)−Vϕ(st)A_t = r_{t+1} + \gamma V_\phi(s_{t+1}) - V_\phi(s_t). دارای تورش (چون از VϕV_\phi استفاده می‌کند)، با واریانس به‌مراتب کمتر. به آن خطای تفاضل زمانی (TD residual) یا δt\delta_t هم می‌گویند.

مزیت n-گام. درونیابی بین این دو حالت:

At(n)=rt+1+γrt+2+…+γn−1rt+n+γnVϕ(st+n)−Vϕ(st)A_t^{(n)} = r_{t+1} + \gamma r_{t+2} + \ldots + \gamma^{n-1} r_{t+n} + \gamma^n V_\phi(s_{t+n}) - V_\phi(s_t)

مقدار n=1n = 1 همان TD خالص است. مقدار n=∞n = \infty بازده مونت‌کارلو است. بیشتر پیاده‌سازی‌ها از n=5n = 5 برای محیط‌های Atari و از n=2048n = 2048 برای PPO روی MuJoCo استفاده می‌کنند.

تخمین تعمیم‌یافته‌ی مزیت (GAE). شولمن و همکاران (2016) میانگین وزندار نمایی را روی تمام مزیت‌های n-گام پیشنهاد کردند:

AtGAE=∑l=0∞(γλ)lδt+lA_t^{\text{GAE}} = \sum_{l=0}^{\infty} (\gamma \lambda)^l \delta_{t+l}

به طوری که λ∈[0,1]\lambda \in [0, 1]. حالت λ=0\lambda = 0 معادل TD است (واریانس پایین، تورش بالا). حالت λ=1\lambda = 1 معادل مونت‌کارلو است (واریانس بالا، بدون تورش). مقدار λ=0.95\lambda = 0.95 گزینه‌ی پیش‌فرض سال 2026 محسوب می‌شود — آن‌قدر تغییرش دهید تا تعادل تورش/واریانس به نقطه‌ی دلخواهتان برسد.

الگوریتم A2C: بازیگر-نقاد همگام با مزیت. تعداد TT گام را در طول NN محیط موازی جمع‌آوری کنید. مزیت‌ها را برای هر گام به دست آورید. بازیگر و نقاد را روی این دسته‌ی (batch) ترکیبی به‌روزرسانی کنید. همین روند را تکرار کنید. این نسخه، همتای ساده‌تر و مقیاس‌پذیرترِ A3C است.

الگوریتم A3C: بازیگر-نقاد ناهمگام با مزیت. منیح و همکاران (2016). تعداد NN رشته‌ی پردازشی (worker thread) بسازید که هر کدام یک محیط را اجرا می‌کنند. هر پردازشگر گرادیان‌ها را به‌طور محلی روی نمونه‌برداری خودش محاسبه می‌کند و سپس آن‌ها را به‌شکل ناهمگام روی یک سرور پارامتر مشترک اعمال می‌نماید. نیازی به بافر بازپخش (replay buffer) نیست — با اجرای مسیرهای مختلف توسط پردازشگرها، همبستگی داده‌ها خودبه‌خود از بین می‌رود. الگوریتم A3C ثابت کرد که می‌توان مدل‌ها را در مقیاس بالا روی CPU آموزش داد. در سال 2026، روش A2C مبتنی بر GPU (محیط‌های موازی دسته‌ای) دست بالا را دارد، چون پردازنده‌های گرافیکی به دسته‌های داده‌ی بزرگ تمایل دارند.

تابع زیان (loss) ترکیبی.

L(θ,ϕ)=−E[At⋅log⁡πθ(at∣st)]+cv⋅E[(Vϕ(st)−Gt)2]−ce⋅E[H(πθ(⋅∣st))]L(\theta, \phi) = -\mathbb{E}[ A_t \cdot \log \pi_\theta(a_t \mid s_t) ] + c_v \cdot \mathbb{E}[(V_\phi(s_t) - G_t)^2] - c_e \cdot \mathbb{E}[H(\pi_\theta(\cdot \mid s_t))]

سه عبارت دارد: تابع زیان گرادیان خط‌مشی، رگرسیون مقدار ارزش، و پاداش آنتروپی. مقادیر c_v ~ 0.5 و c_e ~ 0.01 نقطه‌های شروع استاندارد هستند.

کنشگر-نقاد (ACTOR-CRITIC)خطای TD را بکشید
ACTOR-CRITICThe critic estimates the value V of a state (grey baseline); the actor proposes the action that produced the return Q (blue dot). The advantage A = Q - V, which equals the one-step TD error, measures whether the action did better or worse than the critic expected. A positive advantage pushes the actor toward that action, a negative one pushes it away, and the critic moves its baseline toward the observed return.V (critic) = 1.00Q = V + delta = 1.60
نقاد مقدار V یک حالت (خط مبنای خاکستری) را تخمین می‌زند؛ کنشگر عملی را پیشنهاد می‌دهد که بازده Q (نقطه آبی) را ایجاد کرده است. مزیت (Advantage) یعنی A = Q - V، که برابر با خطای تک‌مرحله‌ای TD است، می‌سنجد که آیا عمل بهتر یا بدتر از انتظار نقاد عمل کرده است یا خیر. مزیت مثبت، کنشگر را به سمت آن عمل push می‌کند، مزیت منفی آن را دور می‌کند، و نقاد نیز خط مبنای خود را به سمت بازده مشاهده‌شده حرکت می‌دهد.

پیاده‌سازی از صفر

گام 1: ساخت نقاد

یک نقاد خطی Vϕ(s)=w⋅features(s)V_\phi(s) = w \cdot \text{features}(s) که با خطای میانگین مربعات (MSE) به‌روزرسانی می‌شود:

def critic_update(w, x, target, lr):
    v_hat = dot(w, x)
    err = target - v_hat
    for j in range(len(w)):
        w[j] += lr * err * x[j]
    return v_hat

روی یک محیط جدولی، نقاد طی چند صد اپیزود همگرا می‌شود. روی بازی‌های Atari، نقاد خطی را با یک بدنه‌ی اصلی CNN مشترک + سرِ مقدار (value head) جایگزین کنید.

گام 2: محاسبه‌ی مزیت n-گام

با داشتن یک مسیر پیمایش (rollout) به طول TT و یک مقدار پایانیِ تخمین‌زده‌شده (bootstrapped) در نقطه‌ی پایان V(sT)V(s_T):

def compute_advantages(rewards, values, gamma=0.99, lam=0.95, last_value=0.0):
    advantages = [0.0] * len(rewards)
    gae = 0.0
    for t in reversed(range(len(rewards))):
        next_v = values[t + 1] if t + 1 < len(values) else last_value
        delta = rewards[t] + gamma * next_v - values[t]
        gae = delta + gamma * lam * gae
        advantages[t] = gae
    returns = [a + v for a, v in zip(advantages, values)]
    return advantages, returns

متغیر returns هدف یادگیری نقاد است. آرایه‌ی advantages همان مقداری است که در ∇log⁡π\nabla \log \pi ضرب می‌شود.

گام 3: به‌روزرسانی ترکیبی

for step_i, (x, a, _r, probs) in enumerate(traj):
    adv = advantages[step_i]
    target_v = returns[step_i]

    # critic
    critic_update(w, x, target_v, lr_v)

    # actor
    for i in range(N_ACTIONS):
        grad_logpi = (1.0 if i == a else 0.0) - probs[i]
        for j in range(N_FEAT):
            theta[i][j] += lr_a * adv * grad_logpi * x[j]

به‌صورت مبتنی بر خط‌مشی حاضر (on-policy)، یک مسیر پیمایش به ازای هر به‌روزرسانی، و با نرخ‌های یادگیری (learning rate) مجزا برای بازیگر و نقاد.

گام 4: موازی‌سازی (A3C در برابر A2C)

  • روش A3C: ساخت NN رشته‌ی پردازشی. هر کدام محیط و گذر رو به جلوی خودشان را اجرا می‌کنند. به‌طور دوره‌ای به‌روزرسانی‌های گرادیان را روی سرور اصلی push می‌کنند. هیچ قفلی (lock) روی مدل اصلی اعمال نمی‌شود — وقوع تداخل پردازش‌ها (races) ایرادی ندارد و فقط مقداری نویز اضافه می‌کند.
  • روش A2C: اجرای NN نمونه‌ی محیط در یک پردازش واحد، قرار دادن مشاهدات درون یک دسته‌ی [N, obs_dim]، اجرای دسته‌ای گذر رو به جلو، و اجرای دسته‌ای گام رو به عقب. این روش بهره‌وری بهتری از GPU دارد، قطعی (deterministic) است و تحلیل رفتار آن آسان‌تر خواهد بود؛ گزینه‌ی پیش‌فرض در سال 2026.

کد نمونه‌ی ما برای وضوح بیشتر تک‌رشته‌ای نوشته شده است؛ تبدیل آن به A2C دسته‌ای فقط سه خط کد در numpy نیاز دارد.

خطاهای رایج

  • تورش اولیه‌ی نقاد قبل از محاسبه‌ی گرادیان بازیگر. اگر نقاد مقادیری کاملاً تصادفی بدهد، خط پایه‌ی آن فاقد اطلاعات مفید است و عملاً خط‌مشی را روی نویز خالص آموزش می‌دهید. نقاد را قبل از فعال کردن گرادیان خط‌مشی برای چند صد گام گرم‌کردن اولیه (warm up) کنید، یا برای بازیگر نرخ یادگیری بسیار پایینی در نظر بگیرید.
  • نرمال‌سازی مزیت. مزیت‌ها را در هر دسته به میانگین صفر و انحراف معیار یک تبدیل کنید. این کار بدون هزینه‌ی پردازشیِ خاصی، پایداری آموزش را به شدت بالا می‌برد.
  • بدنه‌ی مشترک شبکه. برای ورودی‌های تصویری، از یک استخراج‌کننده‌ی ویژگی مشترک برای بازیگر و نقاد استفاده کنید و فقط سرها (heads) را جدا نگه دارید. ویژگی‌های مشترک از هر دو تابع زیان به‌رایگان بهره‌مند می‌شوند.
  • قاعده‌ی مبتنی بر خط‌مشی حاضر (On-policy). در A2C داده‌ها دقیقاً برای یک بار به‌روزرسانی استفاده می‌شوند. استفاده‌ی بیشتر باعث ایجاد تورش در گرادیان خواهد شد (تعدیل با نمونه‌گیری اهمیت همان چیزی است که PPO به ماجرا اضافه می‌کند).
  • فروپاشی آنتروپی. بدون عبارت ce>0c_e > 0، خط‌مشی ظرف چند صد به‌روزرسانی تقریباً قطعی می‌شود و اکتشاف را متوقف می‌کند.
  • مقیاس پاداش. اندازه‌ی مزیت‌ها به مقیاس پاداش‌ها بستگی دارد. پاداش‌ها را نرمال‌سازی کنید (مثلاً با تقسیم بر انحراف معیار متحرک) تا بزرگی گرادیان‌ها در تسک‌های گوناگون یکدست بماند.

استفاده از ابزارهای واقعی

در سال 2026 روش‌های A2C و A3C به‌ندرت گزینه‌ی نهایی برای پیاده‌سازی هستند، اما ساختار پایه‌ای به شمار می‌روند که تمام روش‌های بعدی بر اساس آن‌ها توسعه یافته‌اند:

روش رابطه‌ی آن با A2C
PPO همان A2C به اضافه‌ی نسبت نمونه‌گیری اهمیت بریده‌شده (clipped) برای چند دور به‌روزرسانی
IMPALA همان A3C به اضافه‌ی اصلاح خارج از خط‌مشی با V-trace
SAC (فصل 9 · 07) روش A2C مستقل از خط‌مشی با یک نقاد ارزش ملایم (درس بعد)
GRPO (فصل 9 · 12) همان A2C بدون نقاد — مزیت نسبی گروهی
DPO تبدیل ساختار A2C به یک تابع زیانِ رتبه‌بندی اولویت‌ها، بدون نیاز به نمونه‌گیری
AlphaStar / OpenAI Five همان A2C با آموزش لیگ و پیش‌آموزش تقلیدی

در مقالات سال 2026 هر جا کلمه‌ی «مزیت» را دیدید، ساختار بازیگر-نقاد را در ذهن بیاورید.

خروجی این درس

متن زیر را در فایل outputs/skill-actor-critic-trainer.md ذخیره کنید:

---
name: actor-critic-trainer
description: Produce an A2C / A3C / GAE configuration for a given environment, with advantage estimation and loss weights specified.
version: 1.0.0
phase: 9
lesson: 7
tags: [rl, actor-critic, gae]
---

Given an environment and compute budget, output:

1. Parallelism. A2C (GPU batched) vs A3C (CPU async) and the number of workers.
2. Rollout length T. Steps per env per update.
3. Advantage estimator. n-step or GAE(λ); specify λ.
4. Loss weights. `c_v` (value), `c_e` (entropy), gradient clip.
5. Learning rates. Actor and critic (separate if using).

Refuse single-worker A2C on environments with horizon > 1000 (too on-policy, too slow). Refuse to ship without advantage normalization. Flag any run with `c_e = 0` and observed entropy < 0.1 as entropy-collapsed.

تمرین‌ها

  1. ساده. مدل بازیگر-نقاد را با مزیت مونت‌کارلو (Gt−V(st))(G_t - V(s_t)) روی محیط GridWorld با ابعاد 4×4 آموزش دهید. کارایی داده‌ای (sample efficiency) آن را با REINFORCE دارای خط پایه‌ی میانگین متحرک از درس 06 مقایسه کنید.
  2. متوسط. به مزیت خطای تفاضل زمانی (r+γV(s′)−V(s))(r + \gamma V(s') - V(s)) سوییچ کنید. واریانس دسته‌های مزیت را اندازه بگیرید. واریانس چقدر افت می‌کند؟
  3. سخت. الگوریتم GAE(λ) را پیاده کنید. بازه‌ی λ∈{0,0.5,0.9,0.95,1.0}\lambda \in \lbrace 0, 0.5, 0.9, 0.95, 1.0 \rbrace را آزمایش (sweep) کنید. نمودار بازده نهایی در برابر کارایی داده‌ای را رسم نمایید. نقطه‌ی طلایی موازنه‌ی تورش/واریانس برای این مسئله کجاست؟

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

اصطلاح آنچه گفته می‌شود معنای دقیق آن
بازیگر (Actor) «شبکه‌ی خط‌مشی» πθ(a∣s)\pi_\theta(a \mid s)، که با گرادیان خط‌مشی به‌روزرسانی می‌شود.
نقاد (Critic) «شبکه‌ی ارزش» Vϕ(s)V_\phi(s)، که با رگرسیون خطای میانگین مربعات روی بازده‌ها یا اهداف تفاضل زمانی به‌روزرسانی می‌شود.
مزیت (Advantage) «چقدر از حد متوسط بهتر است» A(s,a)=Q(s,a)−V(s)A(s, a) = Q(s, a) - V(s) یا تخمین‌گرهای آن؛ ضریبی برای ∇log⁡π\nabla \log \pi.
خطای تفاضل زمانی (TD residual) «δ» δt=r+γV(s′)−V(s)\delta_t = r + \gamma V(s') - V(s)؛ تخمین مزیت تک‌گام.
تخمین تعمیم‌یافته‌ی مزیت (GAE) «اهرم درونیابی» مجموع وزندار نمایی از مزیت‌های n-گام، با پارامتر λ\lambda.
A2C «بازیگر-نقاد همگام» دسته‌بندی‌شده در چندین محیط؛ یک گام گرادیان به ازای هر پیمایش.
A3C «بازیگر-نقاد ناهمگام» رشته‌های پردازشی گرادیان‌ها را روی یک سرور پارامتر مشترک push می‌کنند؛ مقاله‌ی اصلی که در سال 2026 کاربرد کمتری دارد.
تخمین اولیه (Bootstrap) «استفاده از V در انتهای افق» بریدن ادامه‌ی مسیر و افزودن γnV(st+n)\gamma^n V(s_{t+n}) برای بستن مجموع مقادیر.

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

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

تفاوت اصلی بین الگوریتم‌های A2C و A3C چیست؟

الگوریتم A3C محیط‌ها را به صورت ناهمگام و روی چندین رشته پردازشی (Thread) مجزا اجرا می‌کند و گرادیان‌ها را به سرور پارامتر می‌فرستد، در حالی که A2C به صورت همگام، داده‌های تمام محیط‌ها را در یک دسته (Batch) جمع‌آوری و همزمان به‌روزرسانی می‌کند که برای اجرا روی GPU بسیار بهینه‌تر است.

چرا در ساختار بازیگر-نقاد از مزیت (Advantage) به جای بازده خام استفاده می‌شود؟

کسر کردن ارزش تخمینی نقاد از بازده (محاسبه مزیت)، امید ریاضی گرادیان را تغییر نمی‌دهد اما واریانس آن را به طرز چشمگیری کاهش می‌دهد و آموزش را پایدار و سریع می‌کند.

تخمین تعمیم‌یافته‌ی مزیت (GAE) چه کاربردی دارد؟

الگوریتم GAE با ترکیب وزندار نمایی بین مزیت تک‌گام تفاضل زمانی (تورش بالا، واریانس پایین) و مزیت مونت‌کارلو (بدون تورش، واریانس بالا)، امکان تنظیم بهینه‌ی تعادل میان تورش و واریانس را فراهم می‌کند.

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

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