Q-Learning ist elegant – solange der Aktionsraum diskret und klein ist. Sobald Roboterarme, Drehmomente oder Trading-Volumen ins Spiel kommen, scheitert die argmax-Operation. Dieser Artikel zeigt den begrifflichen Sprung von Value-basierten zu Policy-basierten Methoden, erklärt den Likelihood-Ratio-Trick und implementiert REINFORCE auf einer numpy-Mini-Welt.
1. Das Problem mit Q-Werten bei kontinuierlichen Aktionen
Q-Learning wählt Aktionen über $a^* = \arg\max_a Q(s, a)$. Diese Operation ist trivial, wenn $A$ klein und diskret ist (z. B. „links/rechts/oben/unten"). Sie wird sofort schwierig, sobald $A$ kontinuierlich ist:
| Aktionsraum | argmax praktikabel? | Beispiel |
|---|---|---|
| Diskret, klein | Ja – einfache Schleife | CartPole (2 Aktionen) |
| Diskret, groß | Schon problematisch | Atari (18 Aktionen, ok), Schach (>1000) |
| Kontinuierlich, 1D | Nein – Diskretisierung möglich, aber grob | Trading-Volumen |
| Kontinuierlich, hochdim | Nein – kombinatorische Explosion | 7-DoF Roboterarm |
❌ Workaround: Diskretisierung
# Naive: kontinuierliches Drehmoment [-1, 1] in 11 Bins.
actions = np.linspace(-1, 1, 11)
best_q = max(q_net(state, a) for a in actions)
Bei einem 7-DoF-Arm explodiert das auf $11^7 \approx 2 \cdot 10^7$ Aktionen pro Schritt – unbenutzbar.
✅ Idee: Policy direkt parametrisieren
Statt $Q(s, a)$ zu lernen und dann $\arg\max$ zu suchen, lernen wir die Policy selbst: $\pi_\theta(a \mid s)$ ist ein neuronales Netz, das aus $s$ direkt eine Verteilung über Aktionen ausgibt (oder bei kontinuierlichen Aktionen Parameter einer Gauß-Verteilung). Es gibt kein argmax mehr – Aktionen werden gesampelt.
Quick-Check: Warum kann Q-Learning kontinuierliche Aktionsräume nicht direkt behandeln?
2. Das Policy-Gradient-Objektiv
Der Agent maximiert den erwarteten Return unter seiner Policy:
$$J(\theta) = \mathbb{E}{\tau \sim \pi\theta}\left[\sum_{t=0}^{T} \gamma^t r_t\right]$$
Die naive Idee wäre, $J(\theta)$ direkt zu differenzieren. Problem: Die Erwartung ist über Trajektorien $\tau$, deren Verteilung selbst von $\theta$ abhängt. Wir können nicht einfach „Reward nach $\theta$ ableiten" – Rewards sind black-box.
3. Der Likelihood-Ratio-Trick
Der zentrale Kniff der Policy-Gradient-Theorie macht das Problem lösbar:
$$\nabla_\theta J(\theta) = \mathbb{E}{\tau \sim \pi\theta}\left[\sum_{t=0}^{T} \nabla_\theta \log \pi_\theta(a_t \mid s_t) \cdot G_t\right]$$
In Worten: Der Gradient des erwarteten Returns ist gleich dem Erwartungswert des Gradienten der Log-Policy, gewichtet mit dem Return. Beweis-Skizze in zwei Zeilen:
$$\nabla_\theta \mathbb{E}\pi[f] = \int \nabla\theta \pi \cdot f \, da = \int \pi \cdot \nabla_\theta \log \pi \cdot f \, da = \mathbb{E}\pi[\nabla\theta \log \pi \cdot f]$$
Die Substitution $\nabla \pi = \pi \cdot \nabla \log \pi$ ist der Trick. Das Ergebnis: Wir können den Gradienten per Sampling schätzen – wir brauchen die Dynamik der Umwelt nicht zu kennen.
Quick-Check: Wofür dient der Likelihood-Ratio-Trick im Policy-Gradient?
4. REINFORCE – der kleinste Policy-Gradient-Algorithmus
REINFORCE (Williams, 1992) ist die direkte Umsetzung der Formel oben:
- Sammle eine vollständige Episode unter $\pi_\theta$.
- Berechne für jeden Schritt den Return $G_t$.
- Update: $\theta \leftarrow \theta + \alpha \cdot \nabla_\theta \log \pi_\theta(a_t \mid s_t) \cdot G_t$.
Das ist die ganze Komplexität – ein Naturgesetz und ein Update-Schritt.
5. Lauffähig: REINFORCE auf 1D-Gridworld
Wir setzen denselben GridWorld-Aufbau wie in Artikel 01 ein und lernen eine policy, die das Ziel (Feld rechts) bevorzugt. Die Policy ist eine einfache Tabelle: pro Zustand ein Logit, daraus per Softmax Wahrscheinlichkeiten für links/rechts.
import numpy as np
rng = np.random.default_rng(0)
LENGTH = 7
GAMMA = 0.95
LR = 0.1
EPISODES = 2000
# Policy-Parameter: pro Zustand 2 Logits (links, rechts).
theta = np.zeros((LENGTH, 2))
def softmax(x):
z = x - x.max()
e = np.exp(z)
return e / e.sum()
def policy_probs(s):
return softmax(theta[s])
def sample_action(s):
return int(rng.choice(2, p=policy_probs(s)))
def step(state, action):
state += 1 if action == 1 else -1
state = max(0, min(LENGTH - 1, state))
done = state in (0, LENGTH - 1)
if done:
r = 1.0 if state == LENGTH - 1 else -1.0
else:
r = 0.0
return state, r, done
def run_episode():
s = LENGTH // 2
transitions = []
for _ in range(50):
a = sample_action(s)
s_next, r, done = step(s, a)
transitions.append((s, a, r))
s = s_next
if done:
break
return transitions
def compute_returns(rewards):
g, returns = 0.0, []
for r in reversed(rewards):
g = r + GAMMA * g
returns.insert(0, g)
return np.array(returns)
# Training.
ep_returns = []
for ep in range(EPISODES):
traj = run_episode()
states = [t[0] for t in traj]
actions = [t[1] for t in traj]
rewards = [t[2] for t in traj]
G = compute_returns(rewards)
# REINFORCE-Update pro Schritt.
for s, a, g in zip(states, actions, G):
probs = policy_probs(s)
grad_log = -probs.copy()
grad_log[a] += 1.0 # ∂/∂θ_a log π(a|s) = 1 - π(a|s); für andere: -π
theta[s] += LR * grad_log * g
ep_returns.append(sum(rewards))
# Auswertung: erste vs. letzte 200 Episoden.
print(f"Mittlerer Return (erste 200) : {np.mean(ep_returns[:200]):+.3f}")
print(f"Mittlerer Return (letzte 200): {np.mean(ep_returns[-200:]):+.3f}")
print("Gelernte P(rechts) pro Zustand:")
for s in range(LENGTH):
print(f" s={s}: {policy_probs(s)[1]:.2f}")
Erwartetes Ergebnis: Der Return startet nahe 0 und steigt im Verlauf gegen +1. Die gelernte $P(\text{rechts})$ ist in der Mitte und besonders rechts deutlich erhöht – der Agent hat gelernt, dass „nach rechts" der profitable Default ist.
Quick-Check: Was passiert, wenn der Return $G_t$ negativ ist?
6. Die Schwäche von REINFORCE: Varianz
REINFORCE funktioniert – aber langsam. Der Grund ist hohe Varianz der Gradientenschätzung. Drei Quellen:
- Stochastische Umwelt: dieselbe Aktion liefert verschiedene Rewards.
- Stochastische Policy: dieselbe Situation führt zu verschiedenen Aktionen.
- Lange Episoden: ein einziger schlechter Move ganz am Anfang verändert alle $G_t$ der Episode.
Das Resultat: Der Schätzer ist erwartungstreu, aber sehr verrauscht – Gradient-Steps zeigen oft in die falsche Richtung, und nur die Mittelung über viele Episoden bringt das Lernen voran.
"REINFORCE is unbiased but high-variance. Almost every improvement in modern policy gradient methods – baselines, critics, GAE, trust regions – is a variance-reduction technique." – paraphrasiert nach Schulman et al., High-Dimensional Continuous Control (2015).
7. Diskussion: Value vs. Policy
| Aspekt | Value-basiert (DQN) | Policy-basiert (REINFORCE) |
|---|---|---|
| Aktionsraum | Diskret | Diskret oder kontinuierlich |
| Output | $Q$-Werte | Aktions-Wahrscheinlichkeiten |
| Stochastische Policies | Nur via $\epsilon$-Greedy | Nativ |
| Off-Policy fähig | Ja (Replay-Buffer) | Schwierig (Importance Sampling) |
| Varianz der Gradienten | Niedrig | Hoch |
| Stabilität | Mittel (Catastrophic Forgetting) | Niedrig (kleine LR nötig) |
Die nächsten Artikel (Actor-Critic, PPO, SAC) lösen die Varianzproblematik durch zusätzliche Critics, Trust-Regions und Off-Policy-Replay – und vereinen so die Stärken beider Welten.
8. Abschluss-Quiz
Was ist die Haupt-*Schwäche* von REINFORCE in der Praxis?
Welche Aussage zum Policy-Gradient-Theorem ist korrekt?
Eine Policy $\pi_\theta(a|s)$ wird bei kontinuierlichen Aktionen meist als …
Warum ist REINFORCE on-policy?
Welche Eigenschaft macht Policy-Gradients besonders attraktiv für Robotik?
9. Weiterführend
- Nächster Artikel: Actor-Critic-Architektur (Artikel 03 dieser Serie).
- Querverweis: self-learning-agents/02-rl-fuer-code-agenten.
- Knowledgebase:
masteringpytorch-secondedition.md– Kapitel zu Policy-Gradients.
Quellen
- Williams, R. J. (1992) – Simple Statistical Gradient-Following Algorithms for Connectionist RL, Machine Learning, 8(3-4).
- Sutton & Barto – Reinforcement Learning: An Introduction, 2nd ed., Kap. 13 (Policy Gradient Methods).
- Schulman, J. et al. (2015) – High-Dimensional Continuous Control Using Generalized Advantage Estimation.