Reinforcement Learning ist weder überwacht noch unüberwacht – es lernt aus Konsequenzen. Dieser Artikel baut das Vokabular für die gesamte Serie: State, Action, Reward, Policy, Markov-Eigenschaft, Diskontierung, Bellman-Gleichung. Eine lauffähige Mini-Env aus reinem numpy macht die Begriffe greifbar.
1. Das Problem: Lernen ohne Lehrer, aber mit Folgen
Klassisches Supervised Learning bekommt zu jedem Input das richtige Label. Unsupervised Learning sucht Struktur ohne Label. Reinforcement Learning bekommt keine Labels – sondern Belohnungen, oft erst lange nach der Aktion.
"Reinforcement learning is learning what to do – how to map situations to actions – so as to maximize a numerical reward signal." – Sutton & Barto, Reinforcement Learning: An Introduction
Die folgende Tabelle trennt die drei Paradigmen:
| Paradigma | Trainings-Signal | Typische Frage |
|---|---|---|
| Supervised | $(x, y)$-Paare | „Welches Label hat dieses Bild?" |
| Unsupervised | nur $x$ | „Welche Cluster gibt es?" |
| Reinforcement | $(s, a, r, s')$-Tupel über Zeit | „Welche Aktion maximiert langfristigen Reward?" |
Der entscheidende Unterschied: In RL beeinflusst die Aktion des Agenten die zukünftigen Daten. Es gibt keine feste i.i.d.-Verteilung – die Verteilung ist die Policy.
2. Das MDP – das formale Gerüst
Ein Markov-Entscheidungsprozess ist das mathematische Standard-Modell für RL. Er ist ein Tupel $(S, A, P, R, \gamma)$:
- $S$ – Zustandsraum (alles, was der Agent über die Welt weiß).
- $A$ – Aktionsraum (was der Agent tun kann; diskret wie „links/rechts" oder kontinuierlich wie „Drehmoment 1.7 Nm").
- $P(s' \mid s, a)$ – Übergangswahrscheinlichkeit (wie die Welt auf Aktionen reagiert).
- $R(s, a)$ – Belohnungsfunktion (das einzige Trainingssignal).
- $\gamma \in [0, 1)$ – Diskontfaktor (wie sehr zählt Zukunft).
Eine Policy $\pi(a \mid s)$ ist die Strategie des Agenten – eine Wahrscheinlichkeitsverteilung über Aktionen, gegeben den Zustand.
Quick-Check: Was bedeutet die Markov-Eigenschaft?
Wann ist die Markov-Annahme verletzt?
In der Praxis ständig. Ein Roboter sieht nur ein Kamerabild, nicht die Geschwindigkeit. Ein Trading-Agent sieht den Kurs, nicht die Orderbuch-Tiefe. Die übliche Antwort: Frame-Stacking (letzte $k$ Beobachtungen als Zustand) oder rekurrente Netze (LSTM/GRU als State-Komprimierer). Mathematisch wechselt man dann vom MDP zum POMDP (Partially Observable MDP) – konzeptionell aber bleibt der Rahmen gleich.
3. Rewards, Returns und Diskontierung
Ein einzelner Reward $r_t$ ist nicht das Lernziel. Der Agent maximiert den Return $G_t$ – die diskontierte Summe zukünftiger Rewards:
$$G_t = \sum_{k=0}^{\infty} \gamma^k r_{t+k+1}$$
Drei Spezialfälle machen $\gamma$ greifbar:
| $\gamma$ | Verhalten | Beispiel |
|---|---|---|
| $0$ | Greedy: nur unmittelbarer Reward zählt | Multi-Armed-Bandit |
| $0.99$ | Langer Horizont, „normaler" Default | CartPole, Atari |
| $\to 1$ | Quasi-unendlicher Horizont, Konvergenz heikel | Lange Robotik-Trajektorien |
Quick-Check: Was passiert mit $\gamma = 0$?
4. Value-Functions und die Bellman-Gleichung
Aus dem Return lassen sich zwei zentrale Funktionen ableiten:
- State-Value $V^\pi(s)$: erwarteter Return, wenn man in $s$ startet und $\pi$ folgt.
- Action-Value $Q^\pi(s, a)$: erwarteter Return, wenn man in $s$ Aktion $a$ wählt und dann $\pi$ folgt.
Die Bellman-Gleichung zerlegt $V^\pi$ rekursiv:
$$V^\pi(s) = \mathbb{E}_{a \sim \pi, s' \sim P}\left[R(s, a) + \gamma V^\pi(s')\right]$$
In Worten: Der Wert eines Zustands ist der erwartete sofortige Reward plus der diskontierte Wert des nächsten Zustands. Diese Selbstbezüglichkeit ist der Hebel hinter sämtlichen Value-basierten RL-Verfahren (Q-Learning, DQN, SAC-Critic).
5. Eine lauffähige Mini-Welt: 1D-Gridworld
Statt gymnasium zu importieren (das im Pyodide-Playground nicht funktioniert), bauen wir eine winzige Umgebung selbst – als pure-numpy-Variante. Der Agent steht auf einer 1D-Linie der Länge 7. Aktion 0 = links, 1 = rechts. Ziel ist Feld 6 (Reward +1), Feld 0 ist Falle (Reward -1). Episode endet bei beiden Terminal-Zuständen.
import numpy as np
rng = np.random.default_rng(0)
class GridWorld1D:
"""Mini-MDP: 7 Felder, Start in der Mitte, Ziel rechts, Falle links."""
def __init__(self, length: int = 7):
self.length = length
self.reset()
def reset(self):
self.state = self.length // 2
return self.state
def step(self, action: int):
# 0 = links, 1 = rechts
self.state += 1 if action == 1 else -1
self.state = max(0, min(self.length - 1, self.state))
done = self.state in (0, self.length - 1)
if done:
reward = 1.0 if self.state == self.length - 1 else -1.0
else:
reward = 0.0
return self.state, reward, done
def run_episode(env, policy, max_steps: int = 50):
s = env.reset()
total, steps = 0.0, 0
for _ in range(max_steps):
a = policy(s)
s, r, done = env.step(a)
total += r
steps += 1
if done:
break
return total, steps
# Random-Policy als Baseline: 50/50 links/rechts.
random_policy = lambda s: int(rng.integers(0, 2))
env = GridWorld1D()
results = [run_episode(env, random_policy) for _ in range(500)]
returns = np.array([r for r, _ in results])
lengths = np.array([n for _, n in results])
print(f"Mittlerer Return : {returns.mean():+.3f}")
print(f"Win-Rate : {(returns > 0).mean():.1%}")
print(f"Mittlere Länge : {lengths.mean():.1f} Schritte")
Die Ausgabe sollte einen Return nahe 0 und eine Win-Rate nahe 50 % zeigen – exakt das, was eine Random-Policy in einer symmetrischen Welt liefert. Das ist die Baseline, die jeder gelernte Agent in den folgenden Artikeln schlagen muss.
Quick-Check: Warum ist die Random-Policy in diesem GridWorld nahe Return = 0?
6. RL-Loop als funktionale Idee
❌ Imperativ: alles in einer Schleife
total = 0
state = env.reset()
while True:
action = pick_action(state)
next_state, reward, done = env.step(action)
total += reward
state = next_state
if done:
break
Funktioniert, ist aber schwer zu testen und zu komponieren. Jeder Forschungs-Codebase, der so beginnt, endet in 800-Zeilen-Methoden.
✅ Funktional: Schritte als Datenstrom
from dataclasses import dataclass
@dataclass(frozen=True)
class Transition:
state: int
action: int
reward: float
next_state: int
done: bool
def rollout(env, policy, max_steps=200):
s = env.reset()
for _ in range(max_steps):
a = policy(s)
s_next, r, done = env.step(a)
yield Transition(s, a, r, s_next, done)
if done:
return
s = s_next
Jede Transition ist ein unveränderliches Datenobjekt. rollout ist ein Generator – damit lassen sich Trajektorien streamen, filtern, batchen, ohne dass die Lern-Logik die Daten-Logik kennt. Genau dieses Muster nutzen wir in den Folgeartikeln für PPO und SAC.
7. Diskussion: Was RL schwer macht
Drei Schwierigkeiten begleiten uns durch die ganze Serie:
- Credit-Assignment – Der Reward kommt oft viele Schritte nach der ursächlichen Aktion. Welcher Move war eigentlich entscheidend?
- Exploration vs. Exploitation – Folgt der Agent dem aktuell besten Plan oder probiert er neue Aktionen? Falsche Balance → lokale Optima.
- Nicht-stationäre Daten – Die Trainings-Verteilung hängt von der aktuellen Policy ab. Was gestern gelernt wurde, kann heute schon veraltet sein.
8. Abschluss-Quiz
Welches Element gehört NICHT zum klassischen MDP-Tupel $(S, A, P, R, \gamma)$?
Was unterscheidet RL grundlegend von Supervised Learning?
Wofür steht das Q in $Q^\pi(s, a)$?
Welche Konsequenz hat ein hoher Diskontfaktor $\gamma$ nahe 1?
Welche der folgenden ist NICHT eine typische RL-Schwierigkeit?
9. Weiterführend
- Nächster Artikel: Von Q-Learning zu Policy Gradients (Artikel 02 dieser Serie).
- Querverweis: self-learning-agents/02-rl-fuer-code-agenten.
- Knowledgebase:
masteringpytorch-secondedition.md– Kapitel zu RL-Grundlagen.
Quellen
- Sutton, R. & Barto, A. – Reinforcement Learning: An Introduction, 2nd ed., Kap. 3 (Finite MDPs).
- Mastering PyTorch (2nd ed.) – Kapitel zu Deep RL Fundamentals.
- Machine Learning with PyTorch and Scikit-Learn (Raschka et al.) – Abschnitt zu RL-Paradigmen.