REINFORCE অ্যালগরিদম
এই পাঠে যা শিখবেন
- REINFORCE algorithm — pseudocode + intuition
- Causality trick — only future rewards matter
- Baseline subtraction — variance reduction
- CartPole-এ scratch থেকে full PyTorch implementation
১ · Algorithm-এর pseudocode
Initialize policy $\pi_\theta$ with random $\theta$।
For episode $= 1, 2, \ldots$:
- Generate trajectory $\tau = (s_0, a_0, r_1, s_1, \ldots, s_T)$ following $\pi_\theta$।
- For each $t = 0, \ldots, T-1$:
- $G_t = \sum_{k=t}^{T-1} \gamma^{k-t} r_{k+1}$।
- $\theta \leftarrow \theta + \alpha \nabla_\theta \log \pi_\theta(a_t | s_t) \cdot G_t$।
২ · Causality trick
Original gradient:
$$\nabla J = \mathbb{E}\left[ \left(\sum_t \nabla \log \pi(a_t|s_t)\right) \left(\sum_t r_t\right) \right]$$
Insight: $a_t$ পরের reward-এ প্রভাব ফেলে, আগের reward-এ না। তাই pre-time-$t$ rewards drop করা যায় (causality):
$$\nabla J = \mathbb{E}\left[ \sum_t \nabla \log \pi(a_t|s_t) \cdot G_t \right]$$
Variance reduction without bias। REINFORCE এই form-এ।
৩ · Baseline subtraction
$$\nabla J = \mathbb{E}\left[ \sum_t \nabla \log \pi(a_t|s_t) \cdot (G_t - b(s_t)) \right]$$
Common baselines:
- $b = \bar{G}$ (running average)।
- $b(s_t) = V_\phi(s_t)$ — separate value network → এটাই Actor-Critic।
- $b = $ mean over trajectory batch।
৪ · Loss function trick (PyTorch)
$\nabla J$ — gradient of $J$, যা maximize করতে চাই। PyTorch minimize করে। Loss = $-\mathbb{E}[\sum_t \log \pi \cdot G_t]$।
$\nabla \log \pi$ — automatic differentiation handle করবে।
৫ · CartPole REINFORCE — full PyTorch
import gym
import torch
import torch.nn as nn
import torch.optim as optim
from torch.distributions import Categorical
import numpy as np
env = gym.make("CartPole-v1")
n_actions = env.action_space.n
state_dim = env.observation_space.shape[0]
gamma = 0.99
lr = 1e-3
class Policy(nn.Module):
def __init__(self):
super().__init__()
self.net = nn.Sequential(
nn.Linear(state_dim, 128), nn.ReLU(),
nn.Linear(128, n_actions),
)
def forward(self, s):
return Categorical(logits=self.net(s))
policy = Policy()
opt = optim.Adam(policy.parameters(), lr=lr)
returns_history = []
for ep in range(500):
state, _ = env.reset()
log_probs, rewards = [], []
while True:
s_t = torch.FloatTensor(state)
dist = policy(s_t)
a = dist.sample()
next_state, r, term, trunc, _ = env.step(a.item())
log_probs.append(dist.log_prob(a))
rewards.append(r)
state = next_state
if term or trunc: break
# Compute returns G_t (backward)
G = 0
returns = []
for r in reversed(rewards):
G = r + gamma * G
returns.insert(0, G)
returns = torch.FloatTensor(returns)
returns = (returns - returns.mean()) / (returns.std() + 1e-8) # baseline (normalize)
# Loss
loss = -(torch.stack(log_probs) * returns).sum()
opt.zero_grad()
loss.backward()
opt.step()
total_r = sum(rewards)
returns_history.append(total_r)
if ep % 25 == 0:
print(f"Ep {ep:3d} | return = {total_r:.1f} | avg(last 25)={np.mean(returns_history[-25:]):.1f}")
৬ · Variance reduction trick
কোডে দেখুন: (returns - returns.mean()) / (returns.std() + 1e-8) — return normalize করা হয়েছে। এটাই simplest baseline (mean) + scaling।
Empirical-ভাবে — REINFORCE এই trick ছাড়া unstable। mean baseline সরল কিন্তু effective।
৭ · REINFORCE-এর সীমা
- High variance: Monte Carlo $G$ — long episode-এ noisy।
- Episode wait: continuing task-এ কাজ করে না।
- Sample inefficient: on-policy — প্রতি episode-এ সব data discard।
- Unstable: learning rate-এ very sensitive।
৮ · REINFORCE-এর descendants
- Actor-Critic: baseline = learned $V$, online TD।
- A2C/A3C: parallel rollout, advantage estimate।
- TRPO/PPO: trust region — large step prevent।
- SAC/DDPG: off-policy variant।
প্রতিটি — REINFORCE-এর কোনো-না-কোনো limitation address করার চেষ্টা।
৯ · ঐতিহাসিক perspective
Williams 1992 paper — "Simple Statistical Gradient-Following Algorithms for Connectionist Reinforcement Learning"। সেই সময়ে:
- Connectionism (neural net) revival।
- Tabular RL dominant — function approximation rare।
- REINFORCE — neural net + RL-এর প্রথম successful marriage।
আজকের ChatGPT-এর RLHF — মূলত এই Williams-এর REINFORCE-এর descendant।
ভাবনার প্রশ্ন
প্র ০১Causality trick কেন variance কমায়?
Original: $\sum_t \nabla \log \pi(a_t|s_t) \cdot \sum_k r_k$।
Reduced: $\sum_t \nabla \log \pi(a_t|s_t) \cdot G_t$ where $G_t = \sum_{k \ge t} \gamma^{k-t} r_k$।
Variance argument:
- Original-এ — past reward (যা $a_t$-এ প্রভাব ফেলেনি) gradient-এ noise।
- Causality drop — শুধু future reward।
- Each $a_t$-এর "credit" তুলনামূলকভাবে cleaner।
Bias issue নেই: past rewards expectation-এ $\nabla \log \pi(a_t|s_t)$ থেকে independent। expectation থেকে drop করা valid।
Mathematically: $\mathbb{E}[\nabla \log \pi(a_t|s_t) \cdot r_k] = 0$ for $k < t$ (under appropriate independence condition)।
প্র ০২Return normalization কি unbiased gradient ভাঙে?
Strict-ভাবে — হ্যাঁ, slightly। return-এর mean ও std batch-এর।
$\hat{G}_t = (G_t - \bar{G}) / \hat{\sigma}_G$।
- $\bar{G}$ — true expectation না, batch sample mean।
- $\hat{\sigma}_G$ — scale change — gradient direction same, magnitude শুধু changed।
Practical impact:
- Bias minor, variance reduction major।
- Theoretically — scale-only adjustment learning rate-এর তুল্য।
- "Reward whitening" নাম দেওয়া যেতে পারে।
Modern practice: অনেক RL implementation reward normalize/clip করে (PPO-এ standard)। small bias-এর বদলে large variance reduction ভাল trade।
প্র ০৩REINFORCE কেন CartPole-এ DQN-এর চেয়ে slow?
Empirical comparison — CartPole-এ:
- DQN: ~১০০-২০০ episode-এ solve।
- REINFORCE: ~৩০০-৫০০ episode।
কেন slower:
- On-policy: প্রতিটি sample একবার ব্যবহার। DQN replay-এ সব sample বহুবার।
- High variance: Monte Carlo G — noisy gradient।
- No bootstrap: per-step learning signal নেই।
কেন তবু practical:
- Continuous action — DQN argmax problem।
- Stochastic optimal — REINFORCE natural।
- Theoretical clarity — ablation study সহজ।
- RLHF-এ — GPU rollout sample expensive কিন্তু once collected, single update standard।
প্র ০৪RLHF-এ REINFORCE কেন ব্যবহার হয় (PPO-এর বদলে কেন না)?
আসলে RLHF-এ মূলত PPO ব্যবহার হয় — pure REINFORCE নয়। কিন্তু underlying conceptual framework REINFORCE-ই।
OpenAI ChatGPT — RLHF stack:
- SFT model (supervised fine-tune)।
- Reward model (human preference থেকে)।
- PPO (REINFORCE + clipping + KL penalty)।
RLHF-এর জন্য PPO modifications:
- Per-token policy gradient — $\sum_t \nabla \log \pi(token_t)$।
- KL constraint — base model থেকে drift এড়ানো।
- Batched rollout — generate large set, then update।
- Reward = scalar from RM, KL penalty।
Pure REINFORCE-এর সমস্যা RLHF-এ:
- Policy collapse — large step generates incoherent text।
- Training unstable — variance বিশাল।
PPO clipping এই issues address করে। কিন্তু conceptually — log-prob × advantage এর underlying কাঠামো REINFORCE-ই।
DPO (পাঠ ২৯): PPO ছাড়াই preference থেকে directly — RL-এর পথ এড়ানো।
অনুশীলন
-
Manual G_t: rewards $[1, 2, 3, 4]$, $\gamma=0.9$। $G_0, G_1, G_2$?
$G_3 = 4$। $G_2 = 3 + 0.9 \cdot 4 = 6.6$। $G_1 = 2 + 0.9 \cdot 6.6 = 7.94$। $G_0 = 1 + 0.9 \cdot 7.94 = 8.146$।
-
Code modify: উপরের REINFORCE-এ separate value network বানিয়ে $G - V(s)$ baseline ব্যবহার করুন (Actor-Critic preview)।
class ValueNet(nn.Module): def __init__(self): super().__init__() self.net = nn.Sequential(nn.Linear(state_dim, 128), nn.ReLU(), nn.Linear(128, 1)) def forward(self, s): return self.net(s).squeeze()Train V_φ alongside — MSE loss with G_t target। Use V(s_t) as baseline। পরের পাঠ এই Actor-Critic বিস্তারিত।
-
Continuous action: Pendulum-এর জন্য (continuous) — Categorical-এর জায়গায় Gaussian policy ব্যবহার করুন।
Output: mu (Linear), log_std (parameter)। sample:
Normal(mu, std).sample()।log_prob = dist.log_prob(action).sum()(multi-D)।
আরও পড়ুন
- পাঠ ১৮ · Actor-Critic পরবর্তী পাঠREINFORCE + learned baseline।
- পাঠ ১৬ · Policy Gradient theorem আগের পাঠTheoretical foundation।
- পাঠ ২৮ · RLHF এই পাঠের সাথে সম্পর্কিতREINFORCE-এর modern application।
- সব AI Courses ABCL TECHPython, ML, DL, NLP, CV, GenAI, RL — সব একসাথে।