What is reinforcement learning?
The training method behind ChatGPT, AlphaGo, and self-driving cars
Most AI you hear about is trained by showing it millions of examples with the right answers attached. That is supervised learning -- you hand it the textbook and the answer key. Reinforcement learning is different. You give the AI a goal and a scoring system, then let it figure out how to get there on its own. No answer key. Just trial, error, and a score.
Think of it like learning a video game without reading the manual. You press buttons, things happen, sometimes you score points, sometimes you die. Over time, you learn which buttons to press in which situations. That loop -- try something, see what happens, adjust -- is RL.
The agent is the learner. The environment is whatever world it operates in -- a game, a chatbot conversation, a robot arm. Every step, the agent picks an action, the environment responds with a new state and a reward signal (a number that says how well it did), and the agent adjusts its strategy.
Core vocabulary
| Term | What it means | Example |
|---|---|---|
| Agent | The thing that learns and makes decisions | A chess engine, a chatbot, a robot |
| Environment | The world the agent interacts with | A chess board, a conversation, a warehouse |
| State | A snapshot of where things stand right now | Current board position, current conversation history |
| Action | A choice the agent makes | Move a piece, generate a sentence, pick up a box |
| Reward | A score signal -- higher is better | +1 for winning, -1 for an unsafe response |
| Policy | The agent's learned strategy (state → action) | "When losing, play aggressively" |
| Episode | One complete run from start to finish | One full chess game, one conversation |
RL vs supervised vs unsupervised
| Supervised | Reinforcement | |
|---|---|---|
| Data | Labeled examples (input + correct output) | A goal and a scoring function |
| Learning | Memorize patterns from examples | Explore, fail, discover what works |
| Ceiling | Limited by the quality of training data | Can discover strategies no human designed |
| Cost | Need expensive labeled data | Need a reliable reward signal |
How RL trains language models (RLHF / GRPO)
This is where RL gets really relevant today. Every major chatbot -- ChatGPT, Claude, Gemini -- uses RL after initial training to learn which responses humans actually prefer. The original method is called RLHF (Reinforcement Learning from Human Feedback). Here is how it works in three stages:
Stage 1: Supervised fine-tuning (SFT). Take a pretrained model and fine-tune it on high-quality conversation examples. This gives it a baseline ability to follow instructions.
Stage 2: Train a reward model. Humans look at pairs of responses and pick which one is better. A separate model learns to predict those preferences. Now you have an automated scoring function.
Stage 3: RL optimization. The language model generates responses, the reward model scores them, and an RL algorithm (PPO, GRPO, etc.) adjusts the model to produce higher-scoring responses more often.
The algorithm landscape
Different RL algorithms make different tradeoffs between complexity, memory, and data requirements. Here is what matters in 2026:
| Algorithm | What it does | Needs critic? | Memory | Best for |
|---|---|---|---|---|
| PPO | Policy gradient with value baseline | Yes (separate model) | ~3x model | Maximum quality, big budgets |
| GRPO | Groups outputs, uses mean as baseline | No | ~2x model | Best quality-per-dollar |
| DPO | Learns from preference pairs directly | No | ~2x model | When you have preference data |
| DAPO | GRPO + dynamic sampling | No | ~2x model | Better exploration |
| CISPO | Clipped importance, per-expert safety | No | ~2x model | MoE models (prevents expert collapse) |
How GRPO works, step by step
GRPO is the breakout algorithm of 2025-2026. DeepSeek used it for R1, and it became the default because it gets PPO-level results without needing a separate critic model (which halves memory cost). Here is the actual process:
- Sample a prompt from your dataset
- Generate G completions (typically 8-16) from the current model
- Score each completion using a verifiable reward (math: did it get the right answer? code: did the tests pass?)
- Normalize scores within the group:
advantage_i = (reward_i - group_mean) / group_std - Update the model: outputs that scored above average get reinforced, below average get suppressed
- Repeat for thousands of prompts
Training cost comparison
Key numbers to know
Resources
- HuggingFace Deep RL Course -- free, interactive, covers fundamentals to PPO
- The Illustrated GRPO -- visual walkthrough of the algorithm
- DeepLearning.AI GRPO course -- hands-on with Andrew Ng
- Nilenso: RL with GRPO -- practical walkthrough
- Gymnasium -- the standard RL environment toolkit
- CleanRL -- single-file RL algorithm implementations
RL in your work life
Where RL is already deployed and making money
RL is not just research. It runs in products you use every day. Every time ChatGPT gives you a helpful answer instead of a weird one, that is RLHF at work. Every time Google Maps finds a faster route, that is RL. Every time YouTube keeps you watching, that is an RL-like system optimizing for engagement.
The RL pipeline inside every major LLM
This loop runs continuously at every frontier lab. It is the reason models keep getting better at following instructions, refusing harmful requests, and writing useful code.
Real deployments
| Company | What they did | Result | RL method |
|---|---|---|---|
| MiniMax | Trained M2.5 with Forge RL framework to be a coding, search, and office agent | 80.2% SWE-Bench Verified (top score), 76.3% BrowseComp | CISPO + Forge |
| DeepSeek | Trained R1 reasoning model from scratch with pure RL | First open model to match o1 on math reasoning | GRPO |
| Google DeepMind | Data center cooling optimization | 30% energy savings across Google data centers | Deep RL |
| Amazon | Warehouse staffing and inventory placement | Reduced idle time, fewer late shipments | Offline RL + LLM |
| OpenAI | RLHF for ChatGPT alignment | Made GPT-4 actually follow instructions instead of rambling | PPO + RLHF |
| Anthropic | Constitutional AI for Claude | Model critiques its own responses, then improves them via RL | RLHF + CAI |
SWE-Bench: who can actually fix real code?
SWE-Bench Verified takes real GitHub issues from popular Python repos and asks models to write the fix. This is the hardest coding benchmark because it requires reading thousands of lines of existing code, understanding the bug, and writing a working patch.
Cost per task
M2.5 costs roughly 10-20x less than Opus per task at similar quality. This is the power of efficient RL training -- you can get frontier performance without frontier prices.
MiniMax Forge: how they got to #1
MiniMax built a custom RL framework called Forge that solves three problems at once: throughput (training fast enough to iterate), stability (RL training loves to collapse), and flexibility (agents need to use tools, browse the web, write code, not just generate text).
RL inside products you already use
| Product | What RL does | Why it matters |
|---|---|---|
| ChatGPT / Claude / Gemini | RLHF picks helpful, safe responses | Without it, models just autocomplete -- often badly |
| GitHub Copilot | RL reduces hallucinated code | Suggests code that actually compiles |
| Google Maps | RL optimizes routes in real-time | Adapts to traffic, construction, accidents |
| YouTube / TikTok | RL-like systems optimize engagement | Learns what keeps you watching |
| Tesla Autopilot | RL for decision-making at intersections | When to brake, accelerate, change lanes |
Should you build or buy?
Most people do not need to train from scratch. If an existing model gets you 80% of the way there, prompt engineering or a small GRPO fine-tune on your specific domain data will close the gap.
Resources
Data for RL
What data you need depends entirely on what kind of RL you are doing
Here is the thing that confuses most people: classic RL does not need a dataset at all. The agent generates its own data by interacting with the environment. Play a game a million times and you have a million games of training data, generated for free.
LLM RL is different. You need prompts (questions to ask the model) and a reward signal (a way to score the answers). The reward signal is the hard part.
Two types of RL data
What each task requires
| Task | Prompts / Input | Reward signal | Example datasets |
|---|---|---|---|
| Game playing | Environment (built in) | Score / win-loss | Gymnasium CartPole, Atari, Chess |
| Math reasoning | Math problems with known answers | Binary: correct or wrong | DeepMath-103K, OpenR1-Math-220K |
| Code generation | Coding tasks with test cases | Test suite pass/fail | SWE-Bench, MBPP, HumanEval |
| General helpfulness | User questions | Human preference ratings | UltraFeedback, Anthropic HH |
| Safety alignment | Adversarial prompts | Human safety ratings | Red-teaming datasets |
The reward signal matters more than the data
Verifiable rewards are the gold standard. If you can automatically check whether an answer is correct (math, code tests, game outcomes), your RL training will be much more stable and effective. This is why math and code are the dominant GRPO training domains -- you get free, noise-free reward signals.
Learned rewards (reward models trained on human preferences) are noisier. The reward model can have blind spots, and the RL agent will exploit them -- a problem called reward hacking.
Dataset sizes
Where to find datasets
| Dataset | Type | Size | Link |
|---|---|---|---|
| DeepMath-103K | Math for GRPO | 103K | HF |
| OpenR1-Math-220K | Verified math | 220K | HF |
| UltraFeedback | Preference pairs | 64K | HF |
| Gymnasium | RL environments | N/A | farama.org |
| Minari | Offline RL trajectories | Various | farama.org |
| Lichess Elite | Chess games 2200+ ELO | ~3M | lichess.org |
Data format for GRPO training
At minimum, you need a prompt and a way to verify the answer. TRL expects this format:
{"prompt": "What is 15 * 23?", "answer": "345"}
{"prompt": "Solve: 2x + 5 = 17", "answer": "6"}
{"prompt": "What is the derivative of x^3?", "answer": "3x^2"}
Quick start: load and inspect a dataset
pip install trl datasets transformers
from datasets import load_dataset
ds = load_dataset("trl-lib/DeepMath-103K", split="train")
print(f"Loaded {len(ds)} prompts")
print(f"Example: {ds[0]['prompt'][:100]}...")
print(f"Answer: {ds[0]['answer']}")
Tooling: from solo to lab
The right tool depends on your budget, your hardware, and your model size
Pick your tier
| Tier | Cost | Hardware | Tools | What you can train |
|---|---|---|---|---|
| Solo | Free | Laptop / Colab | Gymnasium, CleanRL, SB3 | CartPole, Atari, FrozenLake, tabular RL |
| 1 GPU | $0-50/mo | RTX 4090 / L4 | TRL, Unsloth, simple_grpo | GRPO on 0.5B-3B models |
| Team | $200-2K/mo | 2-8x A100 | OpenRLHF, veRL, NeMo-RL | GRPO on 7B-70B |
| Lab | $5K+/mo | 16+ H100 | Forge, DAPO, Nanotron | Foundation models, frontier agents |
GRPO frameworks compared
If you want to run GRPO on a language model, these are your options as of April 2026:
| Framework | Min hardware | Difficulty | What makes it special |
|---|---|---|---|
| TRL | 1 GPU | Easiest | HuggingFace native. GRPOTrainer class, works out of the box. Best docs. |
| Unsloth | 1 GPU 16GB | Easy | 2x speed, 60% less VRAM. Great for 3B models on consumer GPUs. |
| simple_grpo | 1 GPU | Easy | Single file. Read the code, understand the algorithm. |
| NeMo-RL | 1-8 GPU | Medium | NVIDIA native. Best integration with TensorRT, Triton. |
| OpenRLHF | 2+ GPU | Medium | Ray + vLLM. Scales to 70B+ models. |
| veRL | 2+ GPU | Medium | FSDP + vLLM. Clean architecture. |
| Forge (MiniMax) | 16+ GPU | Internal | 40x throughput vs TRL. CISPO algorithm. Not publicly available. |
Throughput comparison
The GRPO training loop in code
This is what a minimal GRPO training run looks like with TRL. About 15 lines of actual code:
from trl import GRPOTrainer, GRPOConfig
from transformers import AutoModelForCausalLM, AutoTokenizer
from datasets import load_dataset
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B")
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B")
ds = load_dataset("trl-lib/DeepMath-103K", split="train[:1000]")
def reward_fn(completions, prompts):
# return list of floats -- your scoring logic here
return [1.0 if "answer" in c else 0.0 for c in completions]
config = GRPOConfig(
output_dir="grpo-output",
num_generations=8, # G: outputs per prompt
per_device_train_batch_size=2,
learning_rate=5e-6,
num_train_epochs=1,
)
trainer = GRPOTrainer(model=model, config=config,
train_dataset=ds, reward_funcs=[reward_fn], tokenizer=tokenizer)
trainer.train()
Classic RL setup
pip install gymnasium stable-baselines3
from stable_baselines3 import PPO
import gymnasium as gym
env = gym.make("CartPole-v1")
model = PPO("MlpPolicy", env, verbose=1)
model.learn(total_timesteps=50_000)
# Done. Model can balance a pole.
Supporting tools
Hardware
You can do real RL training on a single GPU. Here is exactly what fits where.
The most common question: "How much GPU do I need?" The answer depends on whether you are doing classic RL (almost nothing) or LLM RL (depends on model size).
What fits on what
| Task | Hardware | Cost | Time |
|---|---|---|---|
| CartPole / FrozenLake / Taxi | Laptop CPU | $0 | Seconds |
| Atari (DQN/PPO) | CPU or GPU | $0 | 1-4 hours |
| Chess CNN 23M params | 1x L4 24GB | ~$5 | ~6 hours |
| GRPO 0.5B (Qwen2.5-0.5B) | 1x GPU 16GB+ | $5-15 | 2-8 hours |
| GRPO 1.7B (SmolLM3) | 1x GPU 24GB | $10-30 | 4-24 hours |
| GRPO 3B + Unsloth + LoRA | 1x GPU 24GB | $15-50 | 12-48 hours |
| GRPO 7B full fine-tune | 1x A100 80GB | $50-200 | 1-3 days |
| GRPO 14B+ | 4-8x A100/H100 | $500+ | 2-7 days |
GPU cloud pricing (April 2026)
VRAM math: why GRPO is cheaper than PPO
Memory estimation formula
VRAM (GRPO full) = params_in_billions x 2 bytes x 2 copies + 3 GB overhead 0.5B model: 0.5 x 2 x 2 + 3 = 5 GB -> fits 16GB GPU 1.7B model: 1.7 x 2 x 2 + 3 = 10 GB -> fits 16GB GPU 3B model: 3.0 x 2 x 2 + 3 = 15 GB -> fits 24GB GPU 3B + LoRA: 3.0 x 2 x 1 + 3 = 9 GB -> fits 16GB GPU 7B model: 7.0 x 2 x 2 + 3 = 31 GB -> needs A100 40GB+
Where to rent GPUs
| Provider | Cheapest option | Best GPU | Notes |
|---|---|---|---|
| Google Colab | Free | T4 16GB | Time limited, can disconnect |
| Vast.ai | $0.15/hr | 3090 | Cheapest marketplace, variable quality |
| RunPod | $0.35/hr | 4090 | Good spot pricing |
| Lambda | $1.10/hr | A100 | Reliable, good for multi-day runs |
| Nebius | Varies | H100 | Nebius, competitive H100 pricing |
Own vs rent
If you are training more than a few times per month, buying a used 3090 or 4090 pays for itself fast.
Benchmarking
How to measure whether your RL training actually worked
Training without evaluation is just burning money. You need to measure performance before training (baseline), during training (are things improving?), and after training (did it actually get better?).
The eval loop
LLM benchmarks you should know
| Benchmark | What it tests | Best score (Apr 2026) | Why it matters |
|---|---|---|---|
| SWE-Bench Verified | Fix real GitHub issues | 80.2% (M2.5) | Hardest coding test. Requires reading real repos. |
| MMLU | General knowledge, 57 subjects | ~90% | Broad competence check |
| MATH / AIME | Competition math | ~80% | Tests reasoning, not just recall |
| HumanEval | Code generation from docstrings | ~95% | Can the model write working code? |
| BrowseComp | Find information on the web | 76.3% (M2.5) | Tests agent web browsing ability |
| GPQA | Graduate-level science questions | ~65% | PhD-level reasoning |
| IFEval | Instruction following accuracy | ~90% | Does it do what you asked? |
Coding benchmark comparison
What to watch during training
| Metric | What it tells you | Healthy | Danger sign |
|---|---|---|---|
| Average reward | Is the model improving? | Trends upward | Flat or declining |
| Reward std | Is it converging? | Gradually decreasing | Chaotic / increasing |
| KL divergence | How far from the original model? | <10-15 | Spike = reward hacking or collapse |
| Policy entropy | Still exploring? | Slow decrease | Drops to 0 = degenerate policy |
| Completion length | Is it gaming the reward? | Stable | Exploding length = exploitation |
Eval pipeline (from HF Smol Playbook)
Each training stage targets different capabilities. Pretraining builds knowledge (tested by MMLU). SFT teaches instruction following (tested by IFEval). RL training improves reasoning and correctness (tested by MATH and code benchmarks).
Running evals yourself
pip install lm-eval # General knowledge lm_eval --model hf --model_args pretrained=your-model --tasks mmlu --num_fewshot 5 # Math reasoning lm_eval --model hf --model_args pretrained=your-model --tasks gsm8k --num_fewshot 8 # Code generation pip install evalplus evalplus.evaluate --model your-model --dataset humaneval
Leaderboards
- Open LLM Leaderboard -- community-run, updated weekly
- Chatbot Arena -- human preference voting, most trusted
- Artificial Analysis -- speed, cost, and quality comparisons
Demo scripts
7 scripts you can run right now on your laptop. All CPU. Copy, paste, run.
| # | Script | What it teaches | Time | Dependencies |
|---|---|---|---|---|
| 1 | CartPole PPO | Balance a pole using PPO. The "hello world" of RL. | 30s | gymnasium stable-baselines3 |
| 2 | FrozenLake Q-learning | Tabular Q-learning. See the Q-table update in real time. | 5s | gymnasium numpy |
| 3 | Chess CNN | Train a tiny CNN to predict chess moves from board states. | 1m | python-chess torch |
| 4 | GRPO simulation | See the GRPO algorithm work on a math task. No GPU needed. | 2s | none |
| 5 | Multi-armed bandit | The explore-vs-exploit tradeoff. The oldest RL problem. | 1s | numpy |
| 6 | Taxi + action masking | Q-learning with illegal action masking. | 10s | gymnasium numpy |
| 7 | Reward shaping | Same algo, same env, different rewards = different behavior. | 3s | gymnasium numpy |
1. CartPole PPO -- balance a pole on a cart
import gymnasium as gym
from stable_baselines3 import PPO
env = gym.make("CartPole-v1")
model = PPO("MlpPolicy", env, verbose=1, n_steps=1024, batch_size=64)
model.learn(total_timesteps=50_000)
scores = []
for _ in range(10):
obs, _ = env.reset(); total = 0; done = False
while not done:
action, _ = model.predict(obs, deterministic=True)
obs, r, term, trunc, _ = env.step(action); total += r; done = term or trunc
scores.append(total)
print(f"Trained agent: {sum(scores)/len(scores):.0f}/500 avg score")2. FrozenLake -- learn a path across a frozen lake
import gymnasium as gym
import numpy as np
env = gym.make("FrozenLake-v1", map_name="4x4", is_slippery=False)
q = np.zeros((16, 4)); lr, gamma, eps = 0.8, 0.95, 1.0
for ep in range(20_000):
s, _ = env.reset(); done = False
while not done:
a = env.action_space.sample() if np.random.random() < eps else np.argmax(q[s])
s2, r, t, tr, _ = env.step(a)
q[s, a] += lr * (r + gamma * np.max(q[s2]) - q[s, a])
s, done = s2, t or tr
eps = max(0.05, eps * 0.999)
arrows = ["←", "↓", "→", "↑"]; holes = {5,7,11,12}
for row in range(4):
line = ""
for c in range(4):
idx = row*4+c
if idx in holes: line += " H "
elif idx == 15: line += " G "
else: line += f" {['L','D','R','U'][np.argmax(q[idx])]} "
print(line)
wins = 0
for _ in range(1000):
s, _ = env.reset()
for _ in range(100):
s, r, t, tr, _ = env.step(np.argmax(q[s]))
if t or tr: break
wins += r
print(f"Win rate: {wins/10:.1f}%")3. Chess CNN -- predict moves from board positions
import random, numpy as np, chess, torch, torch.nn as nn
def board_to_tensor(b):
p = np.zeros((12,8,8), dtype=np.float32)
for sq, piece in b.piece_map().items():
r,c = divmod(sq,8)
p[(piece.piece_type-1)+(6 if piece.color==chess.BLACK else 0)][r][c]=1.
return torch.tensor(p)
class Net(nn.Module):
def __init__(self):
super().__init__()
self.net = nn.Sequential(nn.Conv2d(12,32,3,padding=1),nn.ReLU(),
nn.Conv2d(32,32,3,padding=1),nn.ReLU(),nn.Flatten(),
nn.Linear(32*64,256),nn.ReLU(),nn.Linear(256,4096))
def forward(self,x): return self.net(x)
data = []
for _ in range(500):
b = chess.Board()
for _ in range(40):
if b.is_game_over(): break
m = random.choice(list(b.legal_moves)); data.append((b.copy(),m)); b.push(m)
print(f"{len(data)} positions")
model = Net(); opt = torch.optim.Adam(model.parameters(), lr=1e-3)
for epoch in range(5):
random.shuffle(data); correct = total = 0
for i in range(0,len(data)-64,64):
batch = data[i:i+64]
X = torch.stack([board_to_tensor(b) for b,_ in batch])
Y = torch.tensor([m.from_square*64+m.to_square for _,m in batch])
opt.zero_grad(); loss = nn.CrossEntropyLoss()(model(X),Y)
loss.backward(); opt.step()
correct += (model(X).argmax(1)==Y).sum().item(); total += len(Y)
print(f"Epoch {epoch+1}: {correct/total*100:.1f}% accuracy")4. GRPO simulation -- watch the algorithm learn math
import random
G, skill = 8, 0.3
prompts = [f"{a}+{b}" for a in range(1,20) for b in range(1,20)]
random.shuffle(prompts)
print("Simulating GRPO on simple addition...")
print(f"Starting accuracy: {skill:.0%}")
print()
for epoch in range(10):
rewards = []
for p in prompts[:50]:
correct_answer = eval(p)
group_rewards = []
for _ in range(G):
if random.random() < skill:
group_rewards.append(1.0) # correct
else:
group_rewards.append(0.0) # wrong
rewards.extend(group_rewards)
skill = min(0.99, skill + (1-skill) * 0.15)
avg_r = sum(rewards) / len(rewards)
print(f"Epoch {epoch+1:2d} | avg reward: {avg_r:.3f} | model accuracy: {skill:.1%}")
print(f"\nFinal accuracy: {skill:.1%} (started at 30%)")5. Multi-armed bandit -- explore vs exploit
import numpy as np
np.random.seed(42)
true_rewards = np.random.normal([1.0, 1.5, 0.8, 2.0, 1.2], 0.3)
Q = np.zeros(5) # estimated value of each arm
N = np.zeros(5) # times each arm was pulled
for t in range(1, 2001):
if np.random.random() < 0.1:
arm = np.random.randint(5) # explore: random arm
else:
arm = np.argmax(Q) # exploit: best known arm
reward = np.random.normal(true_rewards[arm], 0.5)
N[arm] += 1
Q[arm] += (reward - Q[arm]) / N[arm] # incremental mean update
if t in [100, 500, 1000, 2000]:
print(f"t={t:4d} | Q={np.round(Q,2)} | pulls={N.astype(int)}")
print(f"\nBest arm: {np.argmax(Q)} (true best: {np.argmax(true_rewards)})")6. Taxi -- Q-learning with action masking
import gymnasium as gym
import numpy as np
env = gym.make("Taxi-v3")
q = np.zeros((env.observation_space.n, env.action_space.n))
lr, gamma, eps = 0.1, 0.99, 1.0
for _ in range(10_000):
s, info = env.reset(); done = False
while not done:
mask = info.get("action_mask", np.ones(env.action_space.n))
if np.random.random() < eps:
a = np.random.choice(np.where(mask)[0]) # explore legal actions
else:
a = np.argmax(np.where(mask, q[s], -1e9)) # exploit best legal
s2, r, t, tr, info = env.step(a)
q[s, a] += lr * (r + gamma * np.max(q[s2]) - q[s, a])
s, done = s2, t or tr
eps = max(0.01, eps * 0.9995)
results = []
for _ in range(100):
s, info = env.reset(); tot = 0
for _ in range(200):
mask = info.get("action_mask", np.ones(6))
s, r, t, tr, info = env.step(np.argmax(np.where(mask, q[s], -1e9)))
tot += r
if t or tr: break
results.append(tot)
print(f"Avg reward: {np.mean(results):.1f} (optimal ~8)")7. Reward shaping -- same algo, different rewards, different behavior
import gymnasium as gym
import numpy as np
env = gym.make("MountainCar-v0")
def train(env, reward_fn, episodes=3000):
bins = [20, 20]
lo, hi = env.observation_space.low, env.observation_space.high
sz = (hi - lo) / bins
q = np.zeros(bins + [env.action_space.n])
def discretize(obs):
return tuple(np.clip(((obs - lo) / sz).astype(int), 0, np.array(bins) - 1))
lr, gamma, ep = 0.1, 0.99, 1.0
for _ in range(episodes):
obs, _ = env.reset(); s = discretize(obs)
for _ in range(200):
a = env.action_space.sample() if np.random.random() < ep else np.argmax(q[s])
obs2, r, t, tr, _ = env.step(a)
shaped_r = reward_fn(obs, obs2, r, t)
s2 = discretize(obs2)
q[s][a] += lr * (shaped_r + gamma * np.max(q[s2]) - q[s][a])
s, obs = s2, obs2
if t or tr: break
ep = max(0.01, ep * 0.999)
return q, discretize
for name, fn in [
("Default reward", lambda o, o2, r, t: r),
("Shaped reward", lambda o, o2, r, t: r + (o2[0] - o[0]) * 10 + abs(o2[1]) * 5),
]:
q, disc = train(env, fn)
wins = 0
for _ in range(100):
obs, _ = env.reset()
for _ in range(200):
obs, r, t, tr, _ = env.step(np.argmax(q[disc(obs)]))
if t: wins += 1; break
if tr: break
print(f"{name}: {wins}/100 reached the goal")
print("\nSame algorithm, same environment.")
print("Different reward function = completely different behavior.")