Proximal Policy Optimization (PPO) ist einer der bevorzugten Algorithmen zur Lösung von Reinforcement Learning (RL) Problemen. Er wurde 2017 von John Schuman entwickelt, dem Mitbegründer von OpenAI.
PPO wurde bei OpenAI weit verbreitet eingesetzt, um Modelle zu trainieren, die menschenähnliches Verhalten nachahmen. Er verbessert frühere Methoden wie Trust Region Policy Optimization (TRPO) und ist beliebt, weil er ein robustes und effizientes Algorithmus ist.
In diesem Tutorial untersuchen wir PPO ausführlich. Wir behandeln die Theorie und zeigen, wie man sie mit PyTorch implementiert.
Verständnis von Proximal Policy Optimization (PPO)
Herkömmliche überwachte Lernalgorithmen aktualisieren die Parameter entlang der Richtung des steilsten Gradienten. Wenn sich diese Aktualisierung als übermäßig erweist, wird sie während nachfolgender Trainingsbeispiele korrigiert, die voneinander unabhängig sind.
Die Trainingsbeispiele im Reinforcement Learning bestehen jedoch aus den Aktionen des Agenten und den Rückgaben. Daher sind die Trainingsbeispiele miteinander korreliert. Der Agent erkundet die Umgebung, um die optimale Richtlinie zu ermitteln. Daher kann es dazu führen, dass große Änderungen am Gradienten dazu führen, dass die Richtlinie in einer schlechten Region mit suboptimalen Belohnungen stecken bleibt. Da der Agent die Umgebung erkunden muss, machen große Änderungen an der Richtlinie den Trainingsprozess instabil.
Verfahren auf Basis von Vertrauensregionen zielen darauf ab, dieses Problem zu vermeiden, indem sichergestellt wird, dass Politikaktualisierungen innerhalb einer vertrauenswürdigen Region liegen. Diese vertrauenswürdige Region ist ein künstlich eingeschränktes Gebiet innerhalb des Politikraums, in dem Aktualisierungen zulässig sind. Die aktualisierte Politik kann nur innerhalb einer vertrauenswürdigen Region der alten Politik liegen. Die Gewährleistung, dass Politikaktualisierungen schrittweise erfolgen, verhindert Instabilität.
Aktualisierungen der Vertrauensregionen für Politiken (TRPO)
Der Algorithmus für Vertrauensregionen für Politiken (TRPO) wurde 2015 von John Schulman vorgeschlagen (der auch PPO im Jahr 2017 vorschlug). Um den Unterschied zwischen der alten Politik und der aktualisierten Politik zu messen, verwendet TRPO Kullback-Leibler (KL) Divergenz. KL-Divergenz wird verwendet, um den Unterschied zwischen zwei Wahrscheinlichkeitsverteilungen zu messen. TRPO hat sich als effektiv erwiesen, um Vertrauensregionen zu implementieren.
Das Problem bei TRPO ist die rechnerische Komplexität, die mit der KL-Divergenz verbunden ist. Die Anwendung der KL-Divergenz muss auf die zweite Ordnung erweitert werden, indem numerische Methoden wie die Taylor-Expansion verwendet werden. Dies ist rechenintensiv. PPO wurde als einfachere und effizientere Alternative zu TRPO vorgeschlagen. PPO schneidet das Verhältnis der Politiken ab, um die Vertrauensregion approximativ zu bestimmen, ohne auf komplexe Berechnungen zur KL-Divergenz zurückgreifen zu müssen.
Deshalb hat sich PPO gegenüber TRPO bei der Lösung von RL-Problemen als bevorzugt erwiesen. Aufgrund der effizienteren Methode zur Schätzung von Vertrauensbereichen balanciert PPO effektiv Leistung und Stabilität.
Proximal Policy Approximation (PPO)
PPO wird oft als Unterklasse der Actor-Critic-Methoden betrachtet, die die Policy-Gradienten basierend auf der Wertfunktion aktualisieren. Advantage Actor-Critic (A2C) Methoden verwenden einen Parameter namens Advantage. Dieser misst den Unterschied zwischen den vom Kritiker vorhergesagten Renditen und den realisierten Renditen durch die Implementierung der Policy.
Um PPO zu verstehen, müssen Sie seine Komponenten kennen:
- Der Actor führt die Policy aus. Er wird als neuronales Netzwerk implementiert. Bei einem gegebenen Zustand als Eingabe gibt er die auszuführende Aktion aus.
- Der Kritiker ist ein weiteres neuronales Netzwerk. Es nimmt den Zustand als Eingabe und gibt den erwarteten Wert dieses Zustands aus. So drückt der Kritiker die Zustandswertfunktion aus.
- Methoden, die auf dem Policy-Gradienten basieren, können verschiedene Ziel-Funktionen wählen. Insbesondere verwendet PPO die Vorteilfunktion. Die Vorteilfunktion misst, um wie viel die kumulierte Belohnung (basierend auf der von dem Akteur umgesetzten Politik) die erwartete Basisbelohnung (wie vom Kritiker vorhergesagt) übersteigt. Das Ziel von PPO ist es, die Wahrscheinlichkeit zu erhöhen, Aktionen mit einem hohen Vorteil auszuwählen. Das Optimierungsziel von PPO verwendet Verlustfunktionen, die auf dieser Vorteilfunktion basieren.
- Die abgeschnittene Zielfunktion ist die Hauptinnovation in PPO.Sie verhindert große Richtlinienaktualisierungen in einer einzelnen Trainingsschleife. Es begrenzt, wie sehr die Richtlinie in einer einzelnen Schleife aktualisiert wird. Um inkrementelle Richtlinienaktualisierungen zu messen, verwenden methodenbasierte Methoden das Wahrscheinlichkeitsverhältnis der neuen Richtlinie zur alten Richtlinie.
- Der Ersatzverlust ist die Zielfunktion in PPO und berücksichtigt die zuvor erwähnten Innovationen.Er wird wie folgt berechnet:
- Berechnen Sie das tatsächliche Verhältnis (wie zuvor erklärt) und multiplizieren Sie es mit dem Vorteil.
- Beschränken Sie das Verhältnis auf einen gewünschten Bereich. Multiplizieren Sie das beschnittene Verhältnis zum Vorteil.
- Nehmen Sie den minimalen Wert der beiden obigen Größen.
- In der Praxis wird auch ein Entropiebegriff zum Ersatzverlust hinzugefügt. Dies wird als Entropiebonus bezeichnet. Er basiert auf der mathematischen Verteilung der Aktionswahrscheinlichkeiten. Die Idee hinter dem Entropiebonus besteht darin, in kontrollierter Weise zusätzliche Zufälligkeit einzuführen. Dadurch wird der Optimierungsprozess ermutigt, den Aktionsraum zu erkunden. Ein hoher Entropiebonus fördert Exploration gegenüber Ausbeutung.
Verständnis des Beschränkungsmechanismus
Angenommen, unter der alten Richtlinie πalt beträgt die Wahrscheinlichkeit, die Aktion a im Zustand s auszuführen, πalt(a|s). Unter der neuen Richtlinie wird die Wahrscheinlichkeit, dieselbe Aktion a aus dem gleichen Zustand s auszuführen, aktualisiert auf πneu(a|s). Das Verhältnis dieser Wahrscheinlichkeiten, als Funktion der Richtlinienparameter θ, ist r(θ). Wenn die neue Richtlinie die Aktion wahrscheinlicher macht (im gleichen Zustand), ist das Verhältnis größer als 1 und umgekehrt.
Der Clipping-Mechanismus beschränkt dieses Wahrscheinlichkeitsverhältnis so, dass die neuen Aktionswahrscheinlichkeiten innerhalb eines bestimmten Prozentsatzes der alten Aktionswahrscheinlichkeiten liegen müssen. Zum Beispiel, r(θ) kann auf Werte zwischen 0,8 und 1,2 beschränkt werden. Dies verhindert große Sprünge, was wiederum einen stabilen Trainingsprozess gewährleistet.
In diesem Artikel erfahren Sie, wie Sie die Komponenten für eine einfache Implementierung von PPO mit PyTorch zusammenstellen können.
1. Einrichten der Umgebung
Bevor PPO implementiert wird, müssen die erforderlichen Softwarebibliotheken installiert und eine geeignete Umgebung ausgewählt werden, um die Richtlinie anzuwenden.
Installation von PyTorch und erforderlichen Bibliotheken
Wir müssen die folgende Software installieren:
- PyTorch und andere Software-Bibliotheken wie
numpy
(für mathematische und statistische Funktionen) undmatplotlib
(zum Plotten von Diagrammen). - Das Open-Source Gym-Softwarepaket von OpenAI, eine Python-Bibliothek, die verschiedene Umgebungen und Spiele simuliert, die mit verstärkendem Lernen gelöst werden können. Sie können die Gym-API verwenden, um Ihren Algorithmus mit der Umgebung interagieren zu lassen. Da die Funktionalität von
gym
manchmal durch den Upgrade-Prozess geändert wird, frieren wir in diesem Beispiel seine Version auf0.25.2
.
Um es auf einem Server oder einer lokalen Maschine zu installieren, führen Sie Folgendes aus:
$ pip install torch numpy matplotlib gym==0.25.2
Um mit einem Notebook wie Google Colab oder DataLab zu installieren, verwenden Sie:
!pip install torch numpy matplotlib gym==0.25.2
Erstellen Sie die CartPole-Umgebung(en)
Verwenden Sie OpenAI Gym, um zwei Instanzen (eine zum Trainieren und eine zum Testen) der CartPole-Umgebung zu erstellen:
env_train = gym.make('CartPole-v1') env_test = gym.make('CartPole-v1')
2. Implementierung von PPO in PyTorch
Jetzt implementieren wir PPO mit PyTorch.
Definition des Policy-Netzwerks
Wie bereits erwähnt, wird PPO als ein Actor-Critic-Modell implementiert. Der Actor implementiert die Policy, und der Critic sagt ihren geschätzten Wert voraus. Sowohl die Actor- als auch die Critic-Neuronennetze nehmen dieselbe Eingabe – den Zustand zu jedem Zeitpunkt. Daher können die Actor- und Critic-Modelle ein gemeinsames neuronales Netzwerk teilen, das als Backbone-Architektur bezeichnet wird. Der Actor und der Critic können die Backbone-Architektur mit zusätzlichen Schichten erweitern.
Definieren Sie das Backbone-Netzwerk
Die folgenden Schritte beschreiben das Backbone-Netzwerk:
- Implementieren Sie ein Netzwerk mit 3 Schichten – einer Eingabe-, einer versteckten und einer Ausgabeschicht.
- Nach den Eingabe- und versteckten Schichten verwenden wir eine Aktivierungsfunktion. In diesem Tutorial wählen wir ReLU, da es rechnerisch effizient ist.
- Wir legen auch eine Dropout-Funktion nach den Eingangs- und versteckten Schichten fest, um ein robustes Netzwerk zu erhalten. Die Dropout-Funktion setzt zufällig einige Neuronen auf Null. Dies verringert die Abhängigkeit von bestimmten Neuronen und verhindert Überanpassung, wodurch das Netzwerk robuster wird.
Der folgende Code implementiert das Rückgrat:
class BackboneNetwork(nn.Module): def __init__(self, in_features, hidden_dimensions, out_features, dropout): super().__init__() self.layer1 = nn.Linear(in_features, hidden_dimensions) self.layer2 = nn.Linear(hidden_dimensions, hidden_dimensions) self.layer3 = nn.Linear(hidden_dimensions, out_features) self.dropout = nn.Dropout(dropout) def forward(self, x): x = self.layer1(x) x = f.relu(x) x = self.dropout(x) x = self.layer2(x) x = f.relu(x) x = self.dropout(x) x = self.layer3(x) return x
Definiere das Actor-Critic-Netzwerk
Jetzt können wir dieses Netzwerk verwenden, um die Actor-Critic-Klasse ActorCritic
zu definieren. Der Actor modelliert die Politik und sagt die Aktion voraus. Der Kritiker modelliert die Wertfunktion und sagt den Wert voraus. Beide nehmen den Zustand als Eingabe.
class ActorCritic(nn.Module): def __init__(self, actor, critic): super().__init__() self.actor = actor self.critic = critic def forward(self, state): action_pred = self.actor(state) value_pred = self.critic(state) return action_pred, value_pred
Instanziiere die Actor- und Kritiker-Netzwerke
Wir werden die oben definierten Netzwerke verwenden, um einen Actor und einen Kritiker zu erstellen. Dann werden wir einen Agenten erstellen, der den Actor und den Kritiker umfasst.
Bevor wir den Agenten erstellen, initialisieren wir die Parameter des Netzwerks:
- Die Dimensionen der versteckten Schicht, H, die ein konfigurierbarer Parameter ist. Die Größe und Anzahl der versteckten Schichten hängen von der Komplexität des Problems ab. Wir werden eine versteckte Schicht mit Dimensionen von 64 X 64 verwenden.
- Eingangsmerkmale, N, wobei N die Größe des Zustandsarrays ist. Die Eingabeschicht hat N X H Dimensionen. In der CartPole-Umgebung ist der Zustand ein Array mit 4 Elementen. Also ist N 4.
- Ausgangsmerkmale des Actor-Netzwerks, O, wobei O die Anzahl der Aktionen in der Umgebung ist. Die Ausgabeschicht des Actors hat H x O Dimensionen. Die CartPole-Umgebung hat 2 Aktionen.
- Ausgangsmerkmale des Kritiker-Netzwerks. Da das Kritiker-Netzwerk nur den erwarteten Wert (gegeben einen Eingabestatus) vorhersagt, beträgt die Anzahl der Ausgangsmerkmale 1.
- Dropout als Bruch.
Der folgende Code zeigt, wie die Schauspieler- und Kritikernetzwerke basierend auf dem Backbone-Netzwerk deklariert werden:
def create_agent(hidden_dimensions, dropout): INPUT_FEATURES = env_train.observation_space.shape[0] HIDDEN_DIMENSIONS = hidden_dimensions ACTOR_OUTPUT_FEATURES = env_train.action_space.n CRITIC_OUTPUT_FEATURES = 1 DROPOUT = dropout actor = BackboneNetwork( INPUT_FEATURES, HIDDEN_DIMENSIONS, ACTOR_OUTPUT_FEATURES, DROPOUT) critic = BackboneNetwork( INPUT_FEATURES, HIDDEN_DIMENSIONS, CRITIC_OUTPUT_FEATURES, DROPOUT) agent = ActorCritic(actor, critic) return agent
Berechnung der Returns
Die Umgebung gibt eine Belohnung für jeden Schritt, abhängig von der Aktion des Agenten. Die Belohnung, R, wird ausgedrückt als:
Die Return wird definiert als der angesammelte Wert der erwarteten zukünftigen Belohnungen. Belohnungen von Zeitschritten, die weiter in der Zukunft liegen, sind weniger wertvoll als unmittelbare Belohnungen. Daher wird die Return üblicherweise als die diskontierte Return, G, berechnet, definiert als:
In diesem Tutorial (und vielen anderen Referenzen) bezieht sich Return auf die diskontierte Return.
Um die Return zu berechnen:
- Beginnen Sie mit den erwarteten Belohnungen aus allen zukünftigen Zuständen.
- Multiplizieren Sie jede zukünftige Belohnung mit einem Exponenten des Diskontierungsfaktors, . Zum Beispiel wird die erwartete Belohnung nach 2 Zeitschritten (vom aktuellen Zeitpunkt aus) mit 2 multipliziert.
- Summieren Sie alle diskontierten zukünftigen Belohnungen, um die Return zu berechnen.
- Normalisieren Sie den Wert der Return.
Die Funktion calculate_returns()
führt diese Berechnungen durch, wie unten dargestellt:
def calculate_returns(rewards, discount_factor): returns = [] cumulative_reward = 0 for r in reversed(rewards): cumulative_reward = r + cumulative_reward * discount_factor returns.insert(0, cumulative_reward) returns = torch.tensor(returns) # die Return normalisieren returns = (returns - returns.mean()) / returns.std() return returns
Implementierung der Vorteilsfunktion
Der Vorteil wird berechnet als die Differenz zwischen dem Wert, der vom Kritiker vorhergesagt wird, und der erwarteten Return aus den vom Schauspieler gemäß der Richtlinie gewählten Aktionen. Für eine bestimmte Aktion drückt der Vorteil den Nutzen aus, diese spezifische Aktion gegenüber einer beliebigen (durchschnittlichen) Aktion zu ergreifen.
Im ursprünglichen PPO-Papier (Gleichung 10) wird der Vorteil, der bis zum Zeitschritt T reicht, wie folgt ausgedrückt:
Beim Codieren des Algorithmus wird die Einschränkung, bis zu einer festgelegten Anzahl von Zeitschritten nach vorne zu schauen, über die Batch-Größe durchgesetzt. Daher kann die obige Gleichung als die Differenz zwischen dem Wert und den erwarteten Renditen vereinfacht werden. Die erwarteten Renditen werden in der Zustands-Aktion-Wertefunktion Q quantifiziert.
Daher drückt die vereinfachte Formel unten den Vorteil der Auswahl aus:
- einer bestimmten Aktion
- in einem gegebenen Zustand
- unter einer bestimmten Richtlinie
- zu einem bestimmten Zeitschritt aus
Dies wird wie folgt ausgedrückt:
OpenAI verwendet diese Formel auch zur Implementierung von RL. Die Funktion calculate_advantages()
im Folgenden gezeigte Funktion berechnet den Vorteil:
def calculate_advantages(returns, values): advantages = returns - values # Den Vorteil normalisieren advantages = (advantages - advantages.mean()) / advantages.std() return advantages
Ersatzverlust und Clipping-Mechanismus
Der Verlust der Politik wäre der standardmäßige Verlust des Politikanstiegs ohne spezielle Techniken wie PPO. Der standardmäßige Verlust des Politikanstiegs wird als Produkt von:
- Den Wahrscheinlichkeiten der politischen Aktionen
- Der Vorteil-Funktion, die als Differenz zwischen:
- Der Rückkehr der Politik
- Dem erwarteten Wert
Der standardmäßige Verlust des Politikanstiegs kann keine Korrekturen für abrupten Politikwechsel vornehmen. Der surrogate Verlust modifiziert den standardmäßigen Verlust, um die Menge zu beschränken, die sich die Politik in jeder Iteration ändern kann. Es ist das Minimum von zwei Größen:
- Das Produkt von:
- Das Politikverhältnis. Dieses Verhältnis drückt den Unterschied zwischen den alten und neuen Aktionswahrscheinlichkeiten aus.
- Die Vorteilfunktion
- Das Produkt von:
- Der begrenzte Wert des Politikverhältnisses. Dieses Verhältnis wird so beschnitten, dass die aktualisierte Politik innerhalb eines bestimmten Prozentsatzes der alten Politik liegt.
- Die Vorteilfunktion
Für den Optimierungsprozess wird der Ersatzverlust als Proxy für den tatsächlichen Verlust verwendet.
Der Clipping-Mechanismus
Das Richtlinienverhältnis, R, ist der Unterschied zwischen den neuen und alten Richtlinien und wird als Verhältnis der Logarithmen der Wahrscheinlichkeiten der Richtlinie unter den neuen und alten Parametern angegeben:
Das gekappte Richtlinienverhältnis, R‘, ist so eingeschränkt, dass:
Unter Berücksichtigung des VorteilsAtaus dem vorherigen Abschnitt und des oben gezeigten Richtlinienverhältnisses wird der Ersatzverlust wie folgt berechnet:
Der folgende Code zeigt, wie man den Clip-Mechanismus und den Ersatzverlust implementiert.
def calculate_surrogate_loss( actions_log_probability_old, actions_log_probability_new, epsilon, advantages): advantages = advantages.detach() policy_ratio = ( actions_log_probability_new - actions_log_probability_old ).exp() surrogate_loss_1 = policy_ratio * advantages surrogate_loss_2 = torch.clamp( policy_ratio, min=1.0-epsilon, max=1.0+epsilon ) * advantages surrogate_loss = torch.min(surrogate_loss_1, surrogate_loss_2) return surrogate_loss
3. Agententraining
Jetzt trainieren wir den Agenten.
Berechnung des Richtlinien- und Wertverlusts
Wir sind nun bereit, den Richtlinien- und Wertverlust zu berechnen:
- Der Policy-Verlust ist die Summe aus dem Surrogatverlust und dem Entropy-Bonus.
- Der Werteverlust basiert auf der Differenz zwischen dem vom Kritiker vorhergesagten Wert und den Renditen (kumulierte Belohnung), die von der Richtlinie generiert werden. Die Berechnung des Werteverlusts verwendet die Smooth L1 Loss-Funktion. Dies hilft, die Verlustfunktion zu glätten und sie weniger empfindlich gegenüber Ausreißern zu machen.
Beide Verluste, wie oben berechnet, sind Tensoren. Das Gradientenabstiegsverfahren basiert auf skalaren Werten. Um einen einzelnen skalaren Wert darzustellen, der den Verlust repräsentiert, verwenden Sie die Funktion .sum()
, um die Elemente des Tensors zu summieren. Die folgende Funktion zeigt, wie dies gemacht wird:
def calculate_losses( surrogate_loss, entropy, entropy_coefficient, returns, value_pred): entropy_bonus = entropy_coefficient * entropy policy_loss = -(surrogate_loss + entropy_bonus).sum() value_loss = f.smooth_l1_loss(returns, value_pred).sum() return policy_loss, value_loss
Definition der Trainingsschleife
Vor Beginn des Schulungsprozesses erstellen Sie einen Satz von Puffern als leere Arrays. Der Schulungsalgorithmus wird diese Puffer verwenden, um Informationen über die Aktionen des Agenten, die Zustände der Umgebung und die Belohnungen in jedem Zeitschritt zu speichern. Die folgende Funktion initialisiert diese Puffer:
def init_training(): states = [] actions = [] actions_log_probability = [] values = [] rewards = [] done = False episode_reward = 0 return states, actions, actions_log_probability, values, rewards, done, episode_reward
Jede Trainingsschleife führt den Agenten mit den Richtlinienparametern für diese Schleife aus. Der Agent interagiert mit der Umgebung in Zeitschritten in einer Schleife, bis er eine Endbedingung erreicht.
Nach jedem Zeitschritt werden die Aktion des Agenten, die Belohnung und der Wert an die entsprechenden Puffer angehängt. Wenn die Episode endet, gibt die Funktion die aktualisierten Puffer zurück, die die Ergebnisse der Episode zusammenfassen.
Vor dem Start der Trainingsschleife:
- Setzen Sie das Modell in den Trainingsmodus mit
agent.train()
. - Setzen Sie die Umgebung auf einen zufälligen Zustand zurück mit
env.reset()
. Dies ist der Ausgangszustand für diese Trainingsiteration.
Die folgenden Schritte erklären, was in jedem Zeitschritt in der Trainingsschleife passiert:
- Übergeben Sie den Zustand an den Agenten.
- Der Agent gibt zurück:
- Die vorhergesagte Aktion basierend auf dem Zustand, basierend auf der Richtlinie (Actor). Geben Sie diesen vorhergesagten Aktionstensor durch die Softmax-Funktion, um die Menge der Aktionswahrscheinlichkeiten zu erhalten.
- Der vorhergesagte Wert des Zustands, basierend auf dem Kritiker.
- Der Agent wählt die auszuführende Aktion aus:
- Verwenden Sie die Aktionswahrscheinlichkeiten, um die Wahrscheinlichkeitsverteilung abzuschätzen.
- Wählen Sie eine Aktion zufällig aus, indem Sie eine Stichprobe aus dieser Verteilung auswählen. Die Funktion
dist.sample()
erledigt dies. - Verwenden Sie die Funktion
env.step()
, um diese Aktion an die Umgebung weiterzugeben und die Reaktion der Umgebung für diesen Zeitschritt zu simulieren. Basierend auf der Aktion des Agenten generiert die Umgebung: - Den neuen Zustand
- Die Belohnung
- Der boolesche Rückgabewert
done
(dies gibt an, ob die Umgebung einen Endzustand erreicht hat) - Fügen Sie den entsprechenden Puffern die Werte der Aktion des Agenten, der Belohnungen, der vorhergesagten Werte und des neuen Zustands hinzu.
Die Trainingsepisode endet, wenn die Funktion env.step()
einen booleschen Rückgabewert von true
für den Wert von done
zurückgibt.
Nachdem die Episode beendet wurde, verwendet man die angesammelten Werte aus jedem Zeitschritt, um die kumulativen Renditen dieser Episode zu berechnen, indem man die Belohnungen aus jedem Zeitschritt addiert. Wir verwenden die zuvor beschriebene Funktion calculate_returns()
dafür. Die Eingaben dieser Funktion sind der Diskontierungsfaktor und der Puffer, der die Belohnungen aus jedem Zeitschritt enthält. Wir verwenden diese Renditen und die angesammelten Werte aus jedem Zeitschritt, um die Vorteile mithilfe der Funktion calculate_advantages()
zu berechnen.
Die folgende Python-Funktion zeigt, wie man diese Schritte implementiert:
def forward_pass(env, agent, optimizer, discount_factor): states, actions, actions_log_probability, values, rewards, done, episode_reward = init_training() state = env.reset() agent.train() while not done: state = torch.FloatTensor(state).unsqueeze(0) states.append(state) action_pred, value_pred = agent(state) action_prob = f.softmax(action_pred, dim=-1) dist = distributions.Categorical(action_prob) action = dist.sample() log_prob_action = dist.log_prob(action) state, reward, done, _ = env.step(action.item()) actions.append(action) actions_log_probability.append(log_prob_action) values.append(value_pred) rewards.append(reward) episode_reward += reward states = torch.cat(states) actions = torch.cat(actions) actions_log_probability = torch.cat(actions_log_probability) values = torch.cat(values).squeeze(-1) returns = calculate_returns(rewards, discount_factor) advantages = calculate_advantages(returns, values) return episode_reward, states, actions, actions_log_probability, advantages, returns
Aktualisierung der Modellparameter
In jeder Trainingsiteration führt das Modell eine komplette Episode durch, die aus vielen Zeitschritten besteht (bis es eine Endbedingung erreicht). In jedem Zeitschritt speichern wir die Richtlinienparameter, die Aktion des Agenten, die Renditen und die Vorteile. Nach jeder Iteration aktualisieren wir das Modell basierend auf der Leistung der Richtlinie über alle Zeitschritte in dieser Iteration.
Die maximale Anzahl von Zeitschritten in der CartPole-Umgebung beträgt 500. In komplexeren Umgebungen gibt es mehr Zeitschritte, sogar Millionen. In solchen Fällen muss der Datensatz der Trainingsergebnisse in Batches aufgeteilt werden. Die Anzahl der Zeitschritte in jedem Batch wird als Optimierungs-Batch-Größe bezeichnet.
Somit sind die Schritte zur Aktualisierung der Modellparameter:
- Teilen Sie den Datensatz der Trainingsergebnisse in Batches auf.
- Für jeden Batch:
- Holen Sie sich die Aktion des Agenten und den vorhergesagten Wert für jeden Zustand.
- Verwenden Sie diese vorhergesagten Aktionen, um die neue Aktionswahrscheinlichkeitsverteilung zu schätzen.
- Verwenden Sie diese Verteilung, um die Entropie zu berechnen.
- Verwenden Sie diese Verteilung, um die Log-Wahrscheinlichkeit der Aktionen im Trainingsdatensatz zu erhalten. Dies ist der neue Satz von Log-Wahrscheinlichkeiten der Aktionen im Trainingsdatensatz. Der alte Satz von Log-Wahrscheinlichkeiten dieser gleichen Aktionen wurde in der im vorherigen Abschnitt erklärten Trainingsschleife berechnet.
- Berechnen Sie den Surrogatverlust unter Verwendung der alten und neuen Wahrscheinlichkeitsverteilungen der Aktionen.
- Berechnen Sie den Policy-Verlust und den Value-Verlust unter Verwendung des Surrogatverlusts, der Entropie und der Vorteile.
- Führen Sie
.backward()
separat für die Policy- und Value-Verluste aus. Dadurch werden die Gradienten auf den Verlustfunktionen aktualisiert. - Führen Sie
.step()
im Optimierer aus, um die Policy-Parameter zu aktualisieren. In diesem Fall verwenden wir den Adam-Optimierer, um Geschwindigkeit und Robustheit auszubalancieren. - Akumulieren Sie die Verluste der Policy und des Wertes.
- Wiederholen Sie den Rückwärtsdurchlauf (die oben genannten Operationen) für jedes Batch mehrmals, abhängig vom Wert des Parameters
PPO_STEPS
. Das Wiederholen des Rückwärtsdurchlaufs für jedes Batch ist rechnerisch effizient, da es effektiv die Größe des Trainingsdatensatzes erhöht, ohne zusätzliche Vorwärtsdurchläufe durchführen zu müssen. Die Anzahl der Umgebungs-Schritte in jeder Wechsel zwischen Sampling und Optimierung wird als Iterations-Batch-Größe bezeichnet. - Geben Sie den durchschnittlichen Policy-Verlust und den Wertverlust zurück.
Der folgende Code implementiert diese Schritte:
def update_policy( agent, states, actions, actions_log_probability_old, advantages, returns, optimizer, ppo_steps, epsilon, entropy_coefficient): BATCH_SIZE = 128 total_policy_loss = 0 total_value_loss = 0 actions_log_probability_old = actions_log_probability_old.detach() actions = actions.detach() training_results_dataset = TensorDataset( states, actions, actions_log_probability_old, advantages, returns) batch_dataset = DataLoader( training_results_dataset, batch_size=BATCH_SIZE, shuffle=False) for _ in range(ppo_steps): for batch_idx, (states, actions, actions_log_probability_old, advantages, returns) in enumerate(batch_dataset): # Erhalten Sie das neue Logarithmus-Probabilitätsniveau der Aktionen für alle Eingabezustände action_pred, value_pred = agent(states) value_pred = value_pred.squeeze(-1) action_prob = f.softmax(action_pred, dim=-1) probability_distribution_new = distributions.Categorical( action_prob) entropy = probability_distribution_new.entropy() # Schätzen Sie neue Logarithmus-Wahrscheinlichkeiten unter Verwendung alter Aktionen actions_log_probability_new = probability_distribution_new.log_prob(actions) surrogate_loss = calculate_surrogate_loss( actions_log_probability_old, actions_log_probability_new, epsilon, advantages) policy_loss, value_loss = calculate_losses( surrogate_loss, entropy, entropy_coefficient, returns, value_pred) optimizer.zero_grad() policy_loss.backward() value_loss.backward() optimizer.step() total_policy_loss += policy_loss.item() total_value_loss += value_loss.item() return total_policy_loss / ppo_steps, total_value_loss / ppo_steps
4. Ausführen des PPO-Agenten
Lassen Sie uns schließlich den PPO-Agenten ausführen.
Auswertung der Leistung
Um die Leistung des Agenten zu bewerten, erstellen Sie eine neue Umgebung und berechnen Sie die kumulativen Belohnungen aus der Ausführung des Agenten in dieser neuen Umgebung. Sie müssen den Agenten mit der Funktion .eval()
im Evaluierungsmodus setzen. Die Schritte sind die gleichen wie für die Trainingsschleife. Der unten stehende Code implementiert die Evaluierungsfunktion:
def evaluate(env, agent): agent.eval() rewards = [] done = False episode_reward = 0 state = env.reset() while not done: state = torch.FloatTensor(state).unsqueeze(0) with torch.no_grad(): action_pred, _ = agent(state) action_prob = f.softmax(action_pred, dim=-1) action = torch.argmax(action_prob, dim=-1) state, reward, done, _ = env.step(action.item()) episode_reward += reward return episode_reward
Visualisierung der Trainingsergebnisse
Wir werden die Bibliothek Matplotlib verwenden, um den Fortschritt des Schulungsprozesses zu visualisieren. Die folgende Funktion zeigt, wie man die Belohnungen aus den Trainings- und Testschleifen plottet:
def plot_train_rewards(train_rewards, reward_threshold): plt.figure(figsize=(12, 8)) plt.plot(train_rewards, label='Training Reward') plt.xlabel('Episode', fontsize=20) plt.ylabel('Training Reward', fontsize=20) plt.hlines(reward_threshold, 0, len(train_rewards), color='y') plt.legend(loc='lower right') plt.grid() plt.show()
def plot_test_rewards(test_rewards, reward_threshold): plt.figure(figsize=(12, 8)) plt.plot(test_rewards, label='Testing Reward') plt.xlabel('Episode', fontsize=20) plt.ylabel('Testing Reward', fontsize=20) plt.hlines(reward_threshold, 0, len(test_rewards), color='y') plt.legend(loc='lower right') plt.grid() plt.show()
In den untenstehenden Beispieldiagrammen zeigen wir die Trainings- und Testbelohnungen, die durch die Anwendung der Richtlinie in den Trainings- und Testumgebungen erhalten wurden. Beachten Sie, dass die Form dieser Diagramme jedes Mal, wenn Sie den Code ausführen, anders aussehen wird. Dies liegt an der im Schulungsprozess inhärenten Zufälligkeit.
Trainingsbelohnungen (erhalten durch Anwendung der Richtlinie in der Trainingsumgebung). Bild von Autor.
Testbelohnungen (erhalten durch Anwendung der Richtlinie in der Testumgebung). Bild von Autor.
In den oben gezeigten Ausgabediagrammen beobachten Sie den Fortschritt des Schulungsprozesses:
- Die Belohnung beginnt bei niedrigen Werten. Mit fortschreitendem Training steigen die Belohnungen.
- Die Belohnungen schwanken zufällig, während sie ansteigen. Dies liegt daran, dass der Agent den Politikraum erkundet.
- Das Training endet, und die Testbelohnungen haben sich um die Schwelle (475) für viele Iterationen stabilisiert.
- Die Belohnungen sind auf 500 begrenzt. Dies sind Einschränkungen, die durch die Umgebung auferlegt werden (Gym CartPole v1).
Ebenso können Sie die Wert- und Politikverluste über die Iterationen plotten:
def plot_losses(policy_losses, value_losses): plt.figure(figsize=(12, 8)) plt.plot(value_losses, label='Value Losses') plt.plot(policy_losses, label='Policy Losses') plt.xlabel('Episode', fontsize=20) plt.ylabel('Loss', fontsize=20) plt.legend(loc='lower right') plt.grid() plt.show()
Das folgende Beispielplot zeigt die Verluste, die über die Trainingsfolgen verfolgt wurden:
Wert- und Politikverluste durch den Trainingsprozess. Bild vom Autor
Beobachten Sie das Diagramm und beachten Sie:
- Die Verluste scheinen zufällig verteilt zu sein und folgen keinem Muster.
- Das ist typisch für das Training in RL, bei dem das Ziel nicht darin besteht, den Verlust zu minimieren, sondern die Belohnungen zu maximieren.
Führen Sie den PPO-Algorithmus aus
Sie haben jetzt alle Komponenten, um den Agenten mit PPO zu trainieren. Um alles zusammenzufügen, müssen Sie:
- Hyperparameter wie Diskontierungsfaktor, Batch-Größe, Lernrate usw. deklarieren.
- Instanziieren Sie Puffer als Null-Arrays, um die Belohnungen und Verluste aus jeder Iteration zu speichern.
- Erstellen Sie eine Agenteninstanz mit der Funktion
create_agent()
. - Führen Sie iterativ Vorwärts- und Rückwärtspässe mit den Funktionen
forward_pass()
undupdate_policy()
aus. - Testen Sie die Leistung der Richtlinie mit der Funktion
evaluate()
. - Fügen Sie die Richtlinie, Wertverluste und Belohnungen aus den Trainings- und Evaluierungsfunktionen den entsprechenden Puffern hinzu.
- Berechne den Durchschnitt der Belohnungen und Verluste über die letzten paar Zeitschritte. Das folgende Beispiel berechnet den Durchschnitt der Belohnungen und Verluste über die letzten 40 Zeitschritte.
- Gib die Ergebnisse der Bewertung alle paar Schritte aus. Das folgende Beispiel gibt alle 10 Schritte aus.
- Beende den Prozess, wenn die durchschnittliche Belohnung einen bestimmten Schwellenwert überschreitet.
Der folgende Code zeigt, wie man eine Funktion in Python deklariert, die dies tut:
def run_ppo(): MAX_EPISODES = 500 DISCOUNT_FACTOR = 0.99 REWARD_THRESHOLD = 475 PRINT_INTERVAL = 10 PPO_STEPS = 8 N_TRIALS = 100 EPSILON = 0.2 ENTROPY_COEFFICIENT = 0.01 HIDDEN_DIMENSIONS = 64 DROPOUT = 0.2 LEARNING_RATE = 0.001 train_rewards = [] test_rewards = [] policy_losses = [] value_losses = [] agent = create_agent(HIDDEN_DIMENSIONS, DROPOUT) optimizer = optim.Adam(agent.parameters(), lr=LEARNING_RATE) for episode in range(1, MAX_EPISODES+1): train_reward, states, actions, actions_log_probability, advantages, returns = forward_pass( env_train, agent, optimizer, DISCOUNT_FACTOR) policy_loss, value_loss = update_policy( agent, states, actions, actions_log_probability, advantages, returns, optimizer, PPO_STEPS, EPSILON, ENTROPY_COEFFICIENT) test_reward = evaluate(env_test, agent) policy_losses.append(policy_loss) value_losses.append(value_loss) train_rewards.append(train_reward) test_rewards.append(test_reward) mean_train_rewards = np.mean(train_rewards[-N_TRIALS:]) mean_test_rewards = np.mean(test_rewards[-N_TRIALS:]) mean_abs_policy_loss = np.mean(np.abs(policy_losses[-N_TRIALS:])) mean_abs_value_loss = np.mean(np.abs(value_losses[-N_TRIALS:])) if episode % PRINT_INTERVAL == 0: print(f'Episode: {episode:3} | \ Mean Train Rewards: {mean_train_rewards:3.1f} \ | Mean Test Rewards: {mean_test_rewards:3.1f} \ | Mean Abs Policy Loss: {mean_abs_policy_loss:2.2f} \ | Mean Abs Value Loss: {mean_abs_value_loss:2.2f}') if mean_test_rewards >= REWARD_THRESHOLD: print(f'Reached reward threshold in {episode} episodes') break plot_train_rewards(train_rewards, REWARD_THRESHOLD) plot_test_rewards(test_rewards, REWARD_THRESHOLD) plot_losses(policy_losses, value_losses)
Führe das Programm aus:
run_ppo()
Die Ausgabe sollte dem Beispiel unten ähneln:
Episode: 10 | Mean Train Rewards: 22.3 | Mean Test Rewards: 30.4 | Mean Abs Policy Loss: 0.37 | Mean Abs Value Loss: 0.39 Episode: 20 | Mean Train Rewards: 38.6 | Mean Test Rewards: 69.8 | Mean Abs Policy Loss: 0.46 | Mean Abs Value Loss: 0.37 . . . Episode: 100 | Mean Train Rewards: 289.5 | Mean Test Rewards: 427.3 | Mean Abs Policy Loss: 1.73 | Mean Abs Value Loss: 0.21 Episode: 110 | Mean Train Rewards: 357.7 | Mean Test Rewards: 461.4 | Mean Abs Policy Loss: 1.86 | Mean Abs Value Loss: 0.22 Reached reward threshold in 116 episodes
Sie können das funktionierende Programm auf diesem DataLab-Notebook anzeigen und ausführen!
5. Hyperparameter-Tuning und Optimierung
Im maschinellen Lernen steuern Hyperparameter den Trainingsprozess. Unten erkläre ich einige der wichtigen Hyperparameter, die in PPO verwendet werden:
- Lernrate: Die Lernrate entscheidet, wie stark sich die Parameter der Politik in jeder Iteration ändern können. Bei stochastischem Gradientenabstieg wird der Betrag, um den die Parameter der Politik in jeder Iteration aktualisiert werden, durch das Produkt aus der Lernrate und dem Gradienten bestimmt.
- Clipping-Parameter: Dies wird auch als Epsilon, ε, bezeichnet. Es entscheidet über das Ausmaß, in dem das Richtlinienverhältnis beschnitten wird. Das Verhältnis der neuen und alten Richtlinien darf im Bereich [1-ε, 1+ε] variieren. Wenn es über diesen Bereich hinausgeht, wird es künstlich beschnitten, um innerhalb des Bereichs zu liegen.
- Batchgröße: Dies bezieht sich auf die Anzahl der Schritte, die für jedes Gradienten-Update berücksichtigt werden. Bei PPO ist die Batchgröße die Anzahl der Zeitstufen, die benötigt werden, um die Strategie anzuwenden und den Surrogatverlust zu berechnen, um die Parameter der Strategie zu aktualisieren. In diesem Artikel haben wir eine Batchgröße von 64 verwendet.
- Iterationsschritte: Dies ist die Anzahl der Male, die jede Batch wiederverwendet wird, um den Rückwärtsdurchlauf auszuführen. Der Code in diesem Artikel bezeichnet dies als
PPO_STEPS
. In komplexen Umgebungen ist es rechenintensiv, den Vorwärtsdurchlauf viele Male auszuführen. Eine effizientere Alternative besteht darin, jede Batch ein paar Mal erneut auszuführen. Es wird typischerweise empfohlen, einen Wert zwischen 5 und 10 zu verwenden. - Rabattfaktor: Dies wird auch als Gamma, γ, bezeichnet. Es drückt aus, inwieweit sofortige Belohnungen wertvoller sind als zukünftige Belohnungen. Dies ähnelt dem Konzept der Zinssätze bei der Berechnung des Zeitwerts des Geldes. Wenn näher bei 0 liegt, bedeutet dies, dass zukünftige Belohnungen weniger wertvoll sind und der Agent sofortige Belohnungen priorisieren sollte. Wenn näher bei 1 liegt, bedeutet dies, dass zukünftige Belohnungen wichtig sind.
- Entropiekoeffizient: Der Entropiekoeffizient bestimmt den Entropie-Bonus, der als Produkt des Entropiekoeffizienten und der Entropie der Verteilung berechnet wird. Die Rolle des Entropie-Bonus besteht darin, mehr Zufälligkeit in die Richtlinie einzuführen. Dies ermutigt den Agenten, den Richtlinienraum zu erkunden. Allerdings konvergiert das Training nicht zu einer optimalen Richtlinie, wenn diese Zufälligkeit zu hoch ist.
- Erfolgskriterien für das Training: Sie müssen die Kriterien festlegen, um zu entscheiden, wann das Training erfolgreich ist. Eine übliche Methode hierfür ist die Festlegung einer Bedingung, dass die durchschnittlichen Belohnungen über den letzten N Durchläufen (Episoden) über einem bestimmten Schwellenwert liegen. Im obigen Beispielcode wird dies mit der Variablen
N_TRIALS
ausgedrückt. Wenn dieser Wert höher eingestellt ist, dauert das Training länger, da die Richtlinie den Schwellenwert über mehr Episoden erreichen muss. Dies führt auch zu einer robusteren Richtlinie, ist jedoch rechnerisch aufwendiger. Beachten Sie, dass PPO eine stochastische Richtlinie ist und es Episoden geben wird, in denen der Agent den Schwellenwert nicht überschreitet. Wenn der Wert vonN_TRIALS
zu hoch ist, könnte Ihr Training möglicherweise nicht enden.
Strategien zur Optimierung der PPO-Performance
Die Optimierung der Leistung von PPO-Algorithmen erfordert Versuch und Irrtum sowie Experimente mit verschiedenen Hyperparametern. Es gibt jedoch einige allgemeine Richtlinien:
- Abzinsungsfaktor: Wenn langfristige Belohnungen wichtig sind, wie im CartPole-Umfeld, wo der Mast über die Zeit stabil bleiben muss, beginnen Sie mit einem moderaten Gamma-Wert, wie 0,99.
- Entropie-Bonus: In komplexen Umgebungen muss der Agent den Aktionsraum erkunden, um die optimale Politik zu finden. Der Entropie-Bonus fördert die Erkundung. Der Entropie-Bonus wird zum Surrogatverlust hinzugefügt. Überprüfen Sie die Größe des Surrogatverlusts und die Entropie der Verteilung, bevor Sie den Entropie-Koeffizienten festlegen. In diesem Artikel haben wir einen Entropie-Koeffizienten von 0,01 verwendet.
- Clipping-Parameter: Der Clipping-Parameter bestimmt, wie unterschiedlich die aktualisierte Richtlinie von der aktuellen Richtlinie sein kann. Ein hoher Wert des Clipping-Parameters fördert eine bessere Erkundung der Umgebung, birgt jedoch das Risiko, das Training zu destabilisieren. Sie möchten einen Clipping-Parameter, der eine allmähliche Erkundung ermöglicht, während destabilisierende Aktualisierungen verhindert werden. In diesem Artikel haben wir einen Clipping-Parameter von 0,2 verwendet.
- Lernrate: Wenn die Lernrate zu hoch ist, wird die Richtlinie in großen Schritten aktualisiert, und jeder Iteration, und der Trainingsprozess könnte instabil werden. Ist sie zu niedrig, dauert das Training zu lange. In diesem Tutorial wurde eine Lernrate von 0,001 verwendet, die gut für die Umgebung funktioniert. In vielen Fällen wird empfohlen, eine Lernrate von 1e-5 zu verwenden.
Herausforderungen und bewährte Verfahren bei PPO
Nachdem die Konzepte und Implementierungsdetails von PPO erklärt wurden, wollen wir nun die Herausforderungen und bewährten Praktiken diskutieren.
Gemeinsame Herausforderungen beim Training von PPO
Auch wenn PPO weit verbreitet ist, müssen Sie sich der potenziellen Herausforderungen bewusst sein, um erfolgreich reale Probleme mit dieser Technik lösen zu können. Einige solcher Herausforderungen sind:
- Langsame Konvergenz:In komplexen Umgebungen kann PPO sample-ineffizient sein und viele Interaktionen mit der Umgebung benötigen, um auf die optimale Richtlinie zu konvergieren. Dies macht das Training langsam und teuer.
- Sensibilität gegenüber Hyperparametern: PPO basiert auf der effizienten Exploration des Richtlinienraums. Die Stabilität des Schulungsprozesses und die Konvergenzgeschwindigkeit sind empfindlich gegenüber den Werten der Hyperparameter. Die optimalen Werte dieser Hyperparameter können oft nur durch Ausprobieren bestimmt werden.
- Overfitting: RL-Umgebungen werden typischerweise mit zufälligen Parametern initialisiert. Das PPO-Training basiert darauf, die optimale Richtlinie basierend auf der Umgebung des Agenten zu finden. Manchmal konvergiert der Schulungsprozess zu einem Satz optimaler Parameter für eine bestimmte Umgebung, aber nicht für eine beliebig randomisierte Umgebung. Dies wird typischerweise durch viele Iterationen adressiert, jede mit einer unterschiedlich randomisierten Trainingsumgebung.
- Dynamische Umgebungen:Einfache RL-Umgebungen, wie die CartPole-Umgebung, sind statisch – die Regeln bleiben über die Zeit gleich. Viele andere Umgebungen, wie ein Roboter, der lernt, auf einer instabilen bewegten Oberfläche zu laufen, sind dynamisch – die Regeln der Umgebung ändern sich mit der Zeit. Um in solchen Umgebungen gut abzuschneiden, benötigt PPO oft zusätzliches Feintuning.
- Exploration vs. Ausbeutung:Der Clipping-Mechanismus von PPO stellt sicher, dass Richtlinienaktualisierungen innerhalb eines vertrauenswürdigen Bereichs liegen. Es verhindert jedoch auch, dass der Agent den Aktionsraum erkundet. Dies kann dazu führen, dass er sich auf lokale Optima konvergiert, insbesondere in komplexen Umgebungen. Andererseits kann es, wenn dem Agenten zu viel Erkundung erlaubt wird, verhindern, dass er sich auf eine optimale Richtlinie konvergiert.
Best Practices für das Training von PPO-Modellen
Um gute Ergebnisse mit PPO zu erzielen, empfehle ich einige bewährte Verfahren, wie zum Beispiel:
- Eingabemerkmale normalisieren: Durch die Normalisierung der Werte von Rückgaben und Vorteilen wird die Variabilität in den Daten reduziert und zu stabilen Gradientenaktualisierungen geführt. Die Normalisierung der Daten bringt alle Werte in einen konsistenten numerischen Bereich. Sie hilft, den Effekt von Ausreißern und extremen Werten zu reduzieren, die sonst die Gradientenaktualisierungen verzerren und die Konvergenz verlangsamen könnten.
- Verwenden Sie geeignet große Batch-Größen: Kleine Batches ermöglichen schnellere Updates und Training, können jedoch dazu führen, dass lokale Optima und Instabilität im Schulungsprozess erreicht werden. Größere Batch-Größen ermöglichen es dem Agenten, robuste Richtlinien zu erlernen, was zu einem stabilen Schulungsprozess führt. Batch-Größen, die jedoch zu groß sind, sind ebenfalls suboptimal. Neben der Erhöhung der Rechenkosten machen sie die Richtlinienupdates weniger reaktionsschnell auf die Wertefunktion, da die Gradientenupdates auf Durchschnittswerten beruhen, die über große Batches geschätzt werden. Darüber hinaus kann dies dazu führen, dass die Updates zu diesem spezifischen Batch überangepasst werden.
- Iterationsschritte: Es ist im Allgemeinen ratsam, jeden Batch für 5-10 Iterationen wiederzuverwenden. Dies macht den Schulungsprozess effizienter. Wenn der gleiche Batch zu oft wiederverwendet wird, führt dies zu Überanpassung. Der Code bezieht sich auf diesen Hyperparameter als
PPO_STEPS
. - Führen Sie regelmäßige Bewertungen durch: Um Overfitting zu erkennen, ist es wichtig, die Wirksamkeit der Richtlinie regelmäßig zu überwachen. Wenn die Richtlinie in bestimmten Szenarien unwirksam ist, kann weiteres Training oder Feinabstimmung erforderlich sein.
- Stimmen Sie die Hyperparameter ab: Wie bereits erläutert, reagiert das PPO-Training empfindlich auf die Werte der Hyperparameter. Experimentieren Sie mit verschiedenen Hyperparameter-Werten, um den richtigen Satz von Werten für Ihr spezifisches Problem zu ermitteln.
- Gemeinsames Backbone-Netzwerk: Wie in diesem Artikel dargestellt, verhindert die Verwendung eines gemeinsamen Backbones Ungleichgewichte zwischen den Schauspieler- und Kritikernetzwerken. Das Teilen eines Backbone-Netzwerks zwischen Schauspieler und Kritiker hilft bei der gemeinsamen Merkmalsextraktion und einem gemeinsamen Verständnis der Umgebung. Dies macht den Lernprozess effizienter und stabiler. Es hilft auch, den Rechenaufwand und die Zeitkomplexität des Algorithmus zu reduzieren.
- Anzahl und Größe der versteckten Schichten: Erhöhen Sie die Anzahl der versteckten Schichten und Dimensionen für komplexere Umgebungen. Einfachere Probleme wie CartPole können mit einer einzigen versteckten Schicht gelöst werden. Die in diesem Artikel verwendete versteckte Schicht hat 64 Dimensionen. Ein Netzwerk viel größer zu machen als notwendig, ist rechnerisch verschwenderisch und kann es instabil machen.
- Frühes Stoppen: Das Training wird gestoppt, wenn die Bewertungsmetriken erfüllt sind, um ein Übertraining zu verhindern und Ressourcenverschwendung zu vermeiden. Eine gängige Bewertungsmetrik ist, wenn der Agent die Schwellenbelohnungen über die letzten N Ereignisse überschreitet.
Schlussfolgerung
In diesem Artikel haben wir PPO als Lösung für RL-Probleme diskutiert. Anschließend haben wir die Schritte zur Implementierung von PPO mit PyTorch detailliert beschrieben. Abschließend haben wir einige Leistungstipps und bewährte Praktiken für PPO vorgestellt.
Der beste Weg zu lernen, ist den Code selbst zu implementieren. Sie können den Code auch anpassen, um mit anderen klassischen Steuerungsumgebungen in Gym zu arbeiten. Um zu lernen, wie man RL-Agenten mit Python und OpenAI’s Gymnasium implementiert, folgen Sie dem Kurs Reinforcement Learning mit Gymnasium in Python!
Source:
https://www.datacamp.com/tutorial/proximal-policy-optimization