Reinforcement Learning

Verstärkungslernen verstehen: Von Q-Learning bis zu Deep Reinforcement Learning für autonome Agenten

Was ist Reinforcement Learning?

Reinforcement Learning (RL) ist ein Paradigma des Machine Learning, bei dem ein Agent lernt, durch Interaktion mit einer Umgebung optimale Entscheidungen zu treffen. Anders als beim überwachten Lernen gibt es keine vordefinierten richtigen Antworten - der Agent lernt durch Trial-and-Error und Belohnungen.

RL Agent-Environment Interaction Loop

RL hat spektakuläre Erfolge erzielt: von AlphaGo's Sieg gegen den Go-Weltmeister über autonome Fahrzeuge bis hin zu Robotersteuerung. Es ist besonders geeignet für sequentielle Entscheidungsprobleme, bei denen Aktionen langfristige Konsequenzen haben.

Die RL-Komponenten

Ein RL-System besteht aus vier Hauptkomponenten: Agent (Lerner), Environment (Umgebung), Actions (Aktionen) und Rewards (Belohnungen). Der Agent wählt Aktionen, die Umgebung reagiert mit neuen Zuständen und Belohnungen.

Q-Learning: Der klassische Ansatz

Q-Learning ist einer der fundamentalen RL-Algorithmen. Er lernt eine Q-Funktion, die den erwarteten zukünftigen Reward für jede Zustands-Aktions-Kombination schätzt.

import numpy as np import gym class QLearningAgent: def __init__(self, n_states, n_actions, learning_rate=0.1, discount_factor=0.95, epsilon=1.0): # Q-Table initialisieren self.q_table = np.zeros((n_states, n_actions)) self.lr = learning_rate self.gamma = discount_factor self.epsilon = epsilon self.epsilon_decay = 0.995 self.epsilon_min = 0.01 def choose_action(self, state): # Epsilon-Greedy Exploration if np.random.random() < self.epsilon: return np.random.randint(0, self.q_table.shape[1]) else: return np.argmax(self.q_table[state]) def update(self, state, action, reward, next_state): # Q-Learning Update-Regel current_q = self.q_table[state, action] max_next_q = np.max(self.q_table[next_state]) new_q = current_q + self.lr * (reward + self.gamma * max_next_q - current_q) self.q_table[state, action] = new_q # Epsilon decay self.epsilon = max(self.epsilon_min, self.epsilon * self.epsilon_decay) # Training Loop env = gym.make('FrozenLake-v1') agent = QLearningAgent(env.observation_space.n, env.action_space.n) for episode in range(10000): state = env.reset()[0] done = False while not done: action = agent.choose_action(state) next_state, reward, done, truncated, info = env.step(action) agent.update(state, action, reward, next_state) state = next_state

Q-Learning Kernkonzepte

  • Q-Value: Erwarteter kumulativer Reward für eine Aktion in einem Zustand
  • Exploration vs Exploitation: Balance zwischen Erkunden und Ausnutzen
  • Epsilon-Greedy: Strategie für Exploration (hohe Epsilon = mehr Exploration)
  • Discount Factor: Gewichtung zukünftiger vs. sofortiger Rewards

Deep Q-Networks (DQN)

DQN kombiniert Q-Learning mit Deep Neural Networks und ermöglicht RL in hochdimensionalen Zustandsräumen wie Videospielen. Dies war der Durchbruch von DeepMind mit Atari-Spielen.

DQN Architektur
import torch import torch.nn as nn import torch.optim as optim from collections import deque import random class DQN(nn.Module): def __init__(self, state_size, action_size): super(DQN, self).__init__() self.fc1 = nn.Linear(state_size, 128) self.fc2 = nn.Linear(128, 128) self.fc3 = nn.Linear(128, action_size) def forward(self, x): x = torch.relu(self.fc1(x)) x = torch.relu(self.fc2(x)) return self.fc3(x) class DQNAgent: def __init__(self, state_size, action_size): self.state_size = state_size self.action_size = action_size self.memory = deque(maxlen=10000) self.gamma = 0.95 self.epsilon = 1.0 self.epsilon_decay = 0.995 self.epsilon_min = 0.01 self.learning_rate = 0.001 # Neuronale Netze self.model = DQN(state_size, action_size) self.target_model = DQN(state_size, action_size) self.optimizer = optim.Adam(self.model.parameters(), lr=self.learning_rate) def remember(self, state, action, reward, next_state, done): self.memory.append((state, action, reward, next_state, done)) def act(self, state): if np.random.random() <= self.epsilon: return random.randrange(self.action_size) state = torch.FloatTensor(state).unsqueeze(0) q_values = self.model(state) return torch.argmax(q_values).item() def replay(self, batch_size): if len(self.memory) < batch_size: return batch = random.sample(self.memory, batch_size) for state, action, reward, next_state, done in batch: target = reward if not done: next_state_tensor = torch.FloatTensor(next_state).unsqueeze(0) target = reward + self.gamma * torch.max( self.target_model(next_state_tensor) ).item() state_tensor = torch.FloatTensor(state).unsqueeze(0) q_values = self.model(state_tensor) target_f = q_values.clone() target_f[0][action] = target loss = nn.MSELoss()(q_values, target_f) self.optimizer.zero_grad() loss.backward() self.optimizer.step()

Policy Gradient Methoden

Policy Gradient Methoden optimieren direkt die Policy (Handlungsstrategie) statt einer Value-Funktion. Dies ist besonders nützlich für kontinuierliche Aktionsräume.

import torch import torch.nn as nn from torch.distributions import Categorical class PolicyNetwork(nn.Module): def __init__(self, state_size, action_size): super(PolicyNetwork, self).__init__() self.fc1 = nn.Linear(state_size, 128) self.fc2 = nn.Linear(128, action_size) def forward(self, x): x = torch.relu(self.fc1(x)) action_probs = torch.softmax(self.fc2(x), dim=-1) return action_probs class REINFORCEAgent: def __init__(self, state_size, action_size): self.policy = PolicyNetwork(state_size, action_size) self.optimizer = optim.Adam(self.policy.parameters(), lr=0.001) self.gamma = 0.99 self.saved_log_probs = [] self.rewards = [] def select_action(self, state): state = torch.FloatTensor(state) probs = self.policy(state) m = Categorical(probs) action = m.sample() # Log probability speichern self.saved_log_probs.append(m.log_prob(action)) return action.item() def update_policy(self): # Diskontierte Rewards berechnen R = 0 returns = [] for r in self.rewards[::-1]: R = r + self.gamma * R returns.insert(0, R) returns = torch.tensor(returns) returns = (returns - returns.mean()) / (returns.std() + 1e-9) # Policy Gradient berechnen policy_loss = [] for log_prob, R in zip(self.saved_log_probs, returns): policy_loss.append(-log_prob * R) # Update durchführen self.optimizer.zero_grad() policy_loss = torch.cat(policy_loss).sum() policy_loss.backward() self.optimizer.step() # Reset self.saved_log_probs = [] self.rewards = []
Policy Gradient Visualisierung

Actor-Critic Methoden

Actor-Critic kombiniert die Vorteile von Value-Based und Policy-Based Methoden. Der Actor wählt Aktionen, während der Critic die Qualität dieser Aktionen bewertet.

import torch import torch.nn as nn class ActorCritic(nn.Module): def __init__(self, state_size, action_size): super(ActorCritic, self).__init__() # Gemeinsame Feature-Extraction self.shared = nn.Sequential( nn.Linear(state_size, 128), nn.ReLU() ) # Actor (Policy) self.actor = nn.Sequential( nn.Linear(128, 128), nn.ReLU(), nn.Linear(128, action_size), nn.Softmax(dim=-1) ) # Critic (Value Function) self.critic = nn.Sequential( nn.Linear(128, 128), nn.ReLU(), nn.Linear(128, 1) ) def forward(self, state): features = self.shared(state) action_probs = self.actor(features) state_value = self.critic(features) return action_probs, state_value class A2CAgent: def __init__(self, state_size, action_size): self.model = ActorCritic(state_size, action_size) self.optimizer = optim.Adam(self.model.parameters(), lr=0.001) def train_step(self, state, action, reward, next_state, done): state = torch.FloatTensor(state) next_state = torch.FloatTensor(next_state) # Forward pass action_probs, value = self.model(state) _, next_value = self.model(next_state) # TD Error berechnen td_target = reward + (1 - done) * 0.99 * next_value td_error = td_target - value # Actor Loss m = Categorical(action_probs) actor_loss = -m.log_prob(torch.tensor(action)) * td_error.detach() # Critic Loss critic_loss = td_error.pow(2) # Gesamtverlust loss = actor_loss + critic_loss # Backpropagation self.optimizer.zero_grad() loss.backward() self.optimizer.step()

Proximal Policy Optimization (PPO)

PPO ist einer der modernsten und zuverlässigsten RL-Algorithmen. Er ist die Grundlage vieler erfolgreicher Anwendungen, einschließlich ChatGPT's RLHF-Training.

from stable_baselines3 import PPO from stable_baselines3.common.vec_env import DummyVecEnv from stable_baselines3.common.callbacks import EvalCallback import gym # Umgebung erstellen env = gym.make('CartPole-v1') env = DummyVecEnv([lambda: env]) # Evaluation Environment eval_env = gym.make('CartPole-v1') eval_env = DummyVecEnv([lambda: eval_env]) # Evaluation Callback eval_callback = EvalCallback( eval_env, best_model_save_path='./logs/', log_path='./logs/', eval_freq=1000, deterministic=True ) # PPO Modell erstellen und trainieren model = PPO( "MlpPolicy", env, learning_rate=3e-4, n_steps=2048, batch_size=64, n_epochs=10, gamma=0.99, gae_lambda=0.95, clip_range=0.2, verbose=1, tensorboard_log="./ppo_tensorboard/" ) # Training starten model.learn( total_timesteps=100000, callback=eval_callback ) # Modell speichern model.save("ppo_cartpole") # Gelerntes Modell testen obs = env.reset() for i in range(1000): action, _states = model.predict(obs, deterministic=True) obs, reward, done, info = env.step(action) if done: obs = env.reset()
PPO Vorteile

PPO ist sample-effizient, stabil und einfach zu implementieren. Es verwendet einen Clipping-Mechanismus, um zu große Policy-Updates zu vermeiden und damit das Training zu stabilisieren.

Best Practices für RL-Projekte

Reinforcement Learning kann herausfordernd sein. Hier sind bewährte Praktiken für erfolgreiche RL-Implementierungen:

RL Best Practices

  • Einfach beginnen: Starten Sie mit einfachen Umgebungen (CartPole, FrozenLake)
  • Reward Shaping: Design Sie informative Reward-Funktionen
  • Hyperparameter: Experimentieren Sie systematisch mit Lernrate, Gamma, etc.
  • Stabilität: Nutzen Sie bewährte Algorithmen wie PPO oder SAC
  • Monitoring: Tracken Sie Episode Rewards und Success Rate
  • Reproducibility: Setzen Sie Random Seeds für reproduzierbare Ergebnisse

Fazit

Reinforcement Learning ist ein faszinierendes und mächtiges Paradigma des Machine Learning. Von einfachen Q-Learning-Algorithmen bis zu fortgeschrittenen Deep RL-Methoden - RL ermöglicht es Agenten, komplexe Aufgaben durch Erfahrung zu meistern.

Der Einstieg in RL erfordert Geduld und Experimentierfreude. Beginnen Sie mit klassischen Algorithmen, verstehen Sie die Grundkonzepte und arbeiten Sie sich zu modernen Deep RL-Methoden vor. Die Belohnung ist die Fähigkeit, autonome Systeme zu entwickeln, die selbstständig lernen und sich verbessern.

Nächste Schritte

Erkunden Sie fortgeschrittene Themen wie Multi-Agent RL, Inverse RL und Model-Based RL. OpenAI Gym und Stable-Baselines3 sind exzellente Ressourcen für praktisches Lernen!