Verstärkendes Lernen (RL) ist eines der drei Hauptparadigmen des maschinellen Lernens, die anderen beiden sind überwachtes und unüberwachtes Lernen. Im RL lernt ein Agent, mit seiner Umgebung zu interagieren, um die kumulativen Belohnungen zu maximieren. Er lernt die optimale Aktion unter verschiedenen Umweltbedingungen durch Versuch und Irrtum. Verstärkendes Lernen mit menschlichem Feedback (RLHF) ermöglicht es dem Agenten, das Verhalten basierend auf menschlichen Eingaben bei jedem Schritt zu modifizieren.
RL löst Probleme wie selbstfahrende Autos, automatisierten Handel, Computer-Spieler in Videospielen, Training von Robotern und mehr. Wenn tiefe neuronale Netzwerke verwendet werden, um RL-Algorithmen anzuwenden, wird dies als Tiefes Verstärkendes Lernen bezeichnet.
In diesem Tutorial zeige ich Ihnen, wie Sie mit Gymnasium beginnen können, einer Open-Source-Python-Bibliothek zur Entwicklung und zum Vergleich von Verstärkungslernalgorithmen. Ich werde demonstrieren, wie man es einrichtet, verschiedene RL-Umgebungen erkundet und Python verwendet, um einen einfachen Agenten zu erstellen, um einen RL-Algorithmus umzusetzen.
Was ist Gymnasium?
Gymnasium ist eine Open-Source-Python-Bibliothek, die zur Unterstützung der Entwicklung von RL-Algorithmen konzipiert wurde. Um die Forschung und Entwicklung in RL zu erleichtern, bietet Gymnasium:
- Eine Vielzahl von Umgebungen, von einfachen Spielen bis hin zu Problemen, die reale Szenarien nachbilden.
- Optimierte APIs und Wrapper zur Interaktion mit den Umgebungen.
- Die Möglichkeit, benutzerdefinierte Umgebungen zu erstellen und das API-Framework zu nutzen.
Entwickler können RL-Algorithmen erstellen und API-Aufrufe für Aufgaben wie:
- Die Übermittlung der vom Agenten gewählten Aktion an die Umgebung.
- Das Wissen über den Zustand der Umgebung und die Belohnung nach jeder Aktion.
- Das Modell trainieren.
- Die Leistung des Modells testen.
OpenAI’s Gym versus Farama’s Gymnasium
OpenAI hat keine signifikanten Ressourcen für die Entwicklung von Gym bereitgestellt, da es keine geschäftliche Priorität für das Unternehmen war. Die Farama Foundation wurde gegründet, um RL-Bibliotheken langfristig zu standardisieren und zu pflegen. Gymnasium ist der Fork der Farama Foundation von OpenAI’s Gym. Gymnasium 0.26.2 ist ein Plug-and-Play-Ersatz für Gym 0.26.2. Mit dem Fork strebt Farama an, funktionale (zusätzlich zu klassenbasierten) Methoden für alle API-Aufrufe hinzuzufügen, Vektorumgebungen zu unterstützen und die Wrapper zu verbessern. Das übergeordnete Ziel ist es, das Framework sauberer und effizienter zu gestalten.
Einrichten von Gymnasium
Gymnasium benötigt spezifische Versionen (nicht die neuesten Releases) verschiedener Abhängigkeitsprogramme wie NumPy und PyTorch. Daher empfehlen wir, eine frische Conda- oder venv-Umgebung oder ein neues Notebook zu erstellen, um Gymnasium zu installieren, zu verwenden und RL-Programme auszuführen.
Sie können dieses DataLab-Workbook verwenden, um dem Tutorial zu folgen.w
Gymnasium installieren
Um Gymnasium auf einem Server oder einer lokalen Maschine zu installieren, führen Sie aus:
$ pip install gymnasium
Um mittels eines Notebooks wie Google Colab oder DataCamp’s DataLab zu installieren, verwenden Sie:
!pip install gymnasium
Der obige Befehl installiert Gymnasium und die korrekten Versionen der Abhängigkeiten.
Erkundung von Gymnasium-Umgebungen
Stand November 2024 umfasst Gymnasium über 60 integrierte Umgebungen. Um verfügbare integrierte Umgebungen zu durchsuchen, verwenden Sie die gym.envs.registry.all()
Funktion, wie im folgenden Beispiel dargestellt:
import gymnasium as gym for i in gym.envs.registry.keys(): print(i)
Sie können auch die Homepage des Gymnasiums besuchen. Der linke Rand enthält Links zu allen Umgebungen. Die Webseite jeder Umgebung enthält Details darüber, wie Aktionen, Zustände, usw.
Die Umgebungen sind in Kategorien wie Classic Control, Box2D und mehr organisiert. Im Folgenden liste ich einige der gängigen Umgebungen in jeder Gruppe auf:
- Classic Control: Dies sind Standardumgebungen, die in der RL-Entwicklung verwendet werden; sie bilden die Grundlage vieler Beispiele in Lehrbüchern. Sie bieten die richtige Mischung aus Komplexität und Einfachheit, um neue RL-Algorithmen zu testen und zu benchmarken. Zu den Classic-Control-Umgebungen in Gymnasium gehören:
- Acrobot
- Cart Pole
- Mountain Car Discrete
- Mountain Car Continuous
- Pendulum
- Box2D: Box2D ist ein 2D-Physik-Engine für Spiele. Umgebungen, die auf dieser Engine basieren, umfassen einfache Spiele wie:
- Lunar Lander
- Autorennen
- ToyText: Dies sind kleine und einfache Umgebungen, die häufig zur Fehlerbehebung von RL-Algorithmen verwendet werden. Viele dieser Umgebungen basieren auf dem Modell der kleinen Rasterwelt und einfachen Kartenspielen. Beispiele sind:
- Blackjack
- Taxi
- Frozen Lake
- MuJoCo: Multi-Joint Dynamics with Contact (MuJoCo) ist eine Open-Source-Physik-Engine, die Umgebungen für Anwendungen wie Robotik, Biomechanik, ML usw. simuliert. MuJoCo-Umgebungen in Gymnasium umfassen:
- Ant
- Hopper
- Humanoid
- Swimmer
- Und mehr
Neben den integrierten Umgebungen kann Gymnasium mit vielen externen Umgebungen mit derselben API verwendet werden.
In diesem Tutorial verwenden wir eine der klassischen Steuerungsumgebungen. Verwenden Sie den Befehl .make()
, um eine spezifische Umgebung zu importieren, und übergeben Sie den Namen der Umgebung als Argument. Um beispielsweise eine neue Umgebung basierend auf CartPole (Version 1) zu erstellen, verwenden Sie den folgenden Befehl:
import gymnasium as gym env = gym.make("CartPole-v1")
Verständnis der Konzepte des Reinforcement Learning in Gymnasium
Zusammengefasst besteht Reinforcement Learning darin, dass ein Agent (wie ein Roboter) mit seiner Umgebung interagiert. Eine Richtlinie bestimmt die Aktionen des Agenten. Abhängig von den Aktionen des Agenten gibt die Umgebung zu jedem Zeitschritt eine Belohnung (oder Strafe). Der Agent verwendet RL, um die optimale Richtlinie zu ermitteln, die die insgesamt verdienten Belohnungen maximiert.
Komponenten einer RL-Umgebung
Die folgenden sind die Schlüsselkomponenten einer RL-Umgebung:
- Umgebung: Das externe System, die Welt oder der Kontext. Der Agent interagiert mit der Umgebung in einer Reihe von Zeitschritten. In jedem Zeitschritt, basierend auf der Aktion des Agenten, gibt die Umgebung:
- Belohnung (oder Strafe)
- Entscheidet über den nächsten Zustand
- Zustand: Eine mathematische Darstellung der aktuellen Konfiguration der Umgebung.
- Zum Beispiel kann der Zustand einer Pendelumgebung die Position und die Winkelgeschwindigkeit des Pendels zu jedem Zeitpunkt umfassen.
- Terminalzustand: Ein Zustand, der nicht zu neuen/anderen Zuständen führt.
- Agent: Der Algorithmus, der die Umgebung beobachtet und basierend auf dieser Beobachtung verschiedene Aktionen ausführt. Das Ziel des Agenten ist es, seine Belohnungen zu maximieren.
- Zum Beispiel entscheidet der Agent, wie stark und in welche Richtung er das Pendel anstoßen soll.
- Beobachtung: Eine mathematische Darstellung der Ansicht des Agenten von der Umgebung, die z. B. mithilfe von Sensoren erfasst wird.
- Aktion: Die Entscheidung, die der Agent trifft, bevor er zum nächsten Schritt übergeht. Die Aktion beeinflusst den nächsten Zustand der Umgebung und bringt dem Agenten eine Belohnung ein.
- Belohnung: Das Feedback von der Umgebung an den Agenten. Es kann je nach Aktion und Zustand der Umgebung positiv oder negativ sein.
- Rendite: Die erwartete kumulative Rendite über zukünftige Zeitschritte. Belohnungen aus zukünftigen Zeitschritten können mit einem Diskontfaktor abgezinst werden.
- Politik: Die Strategie des Agenten, welche Aktion in verschiedenen Zuständen ergriffen werden soll. Sie wird typischerweise als Wahrscheinlichkeitsmatrix dargestellt, P, die Zustände den Aktionen zuordnet.
- Gegeben eine endliche Menge von m möglichen Zuständen und n möglichen Aktionen, bezeichnet das Element Pmn in der Matrix die Wahrscheinlichkeit, die Aktion an im Zustand sm auszuführen.
- Episode: Die Reihe von Zeitstufen vom (randomisierten) Anfangszustand bis der Agent einen Endzustand erreicht.
Beobachtungsraum und Aktionsraum
Die Beobachtung ist die Information, die der Agent über die Umgebung sammelt. Ein Agent, zum Beispiel ein Roboter, könnte Umgebungsinformationen mithilfe von Sensoren sammeln. Idealerweise sollte der Agent in der Lage sein, den vollständigen Zustand zu beobachten, der alle Aspekte der Umgebung beschreibt. In der Praxis verwendet der Agent seine Beobachtungen als Stellvertreter für den Zustand. Daher entscheiden die Beobachtungen über die Aktionen des Agents.
Ein Raum ist analog zu einer mathematischen Menge. Der Raum der Elemente X umfasst alle möglichen Instanzen von X. Der Raum von X definiert auch die Struktur (Syntax und Format) aller Elemente des Typs X. Jede Gymnasium-Umgebung hat zwei Räume, den Aktionsraum, action_space
, und den Beobachtungsraum, observation_space
. Sowohl der Aktions- als auch der Beobachtungsraum leiten sich von der übergeordneten gymnasium.spaces.Space
Superklasse ab.
Beobachtungsraum
Der Beobachtungsraum ist der Raum, der alle möglichen Beobachtungen umfasst. Er definiert auch das Format, in dem Beobachtungen gespeichert werden. Der Beobachtungsraum wird typischerweise als ein Objekt des Datentyps Box dargestellt. Dies ist ein ndarray, das die Parameter der Beobachtungen beschreibt. Die Box gibt die Grenzen jeder Dimension an. Sie können den Beobachtungsraum für eine Umgebung mit der observation_space
Methode anzeigen:
print("observation space: ", env.observation_space)
Im Fall der CartPole-v1
Umgebung sieht die Ausgabe wie im folgenden Beispiel aus:
observation space: Box([-4.8 -inf -0.41887903 -inf], [4.8 inf 0.41887903 inf], (4,), float32)
In diesem Beispiel hat der CartPole-v1
Beobachtungsraum 4 Dimensionen. Die 4 Elemente des Beobachtungsarrays sind:
- Position des Wagens – variiert zwischen -4.8 und +4.8
- Wagen-Geschwindigkeit – reicht von – bis +
- Pfostenwinkel – variiert zwischen -0.4189 und +0.4189
- Polwinkelgeschwindigkeit – liegt zwischen – und +
Um ein Beispiel eines einzelnen Beobachtungsarrays zu sehen, verwenden Sie den Befehl .reset()
.
observation, info = env.reset() print("observation: ", observation)
Im Fall der Umgebung CartPole-v1
sieht die Ausgabe wie folgt aus:
[ 0.03481963 -0.0277232 0.01703267 -0.04870504]
Die vier Elemente dieses Arrays entsprechen den vier beobachteten Größen (Position des Wagens, Geschwindigkeit des Wagens, Winkel des Stabes, Winkelgeschwindigkeit des Stabes), wie zuvor erklärt.
Aktionsraum
Der Aktionsraum umfasst alle möglichen Aktionen, die der Agent ausführen kann. Der Aktionsraum definiert auch das Format, in dem Aktionen dargestellt werden. Sie können den Aktionsraum für eine Umgebung mit der Methode action_space
anzeigen:
print("action space: ", env.action_space)
Im Fall der CartPole-v1
-Umgebung sieht die Ausgabe wie folgt aus:
action space: Discrete(2)
Im Fall der CartPole-v1
-Umgebung ist der Aktionsraum diskret. Es gibt insgesamt zwei Aktionen, die der Agent ausführen kann:
- 0: Den Wagen nach links schieben
- 1: Den Wagen nach rechts schieben
Erstellen Ihres ersten RL-Agenten mit Gymnasium
In den vorherigen Abschnitten haben wir die grundlegenden Konzepte von RL und Gymnasium erkundet. Dieser Abschnitt zeigt Ihnen, wie Sie Gymnasium verwenden können, um einen RL-Agenten zu erstellen.
Erstellen und Zurücksetzen der Umgebung
Der erste Schritt besteht darin, eine Instanz der Umgebung zu erstellen. Verwenden Sie die Methode .make()
, um neue Umgebungen zu erstellen.
env = gym.make('CartPole-v1')
Die Interaktionen des Agenten verändern den Zustand der Umgebung. Die Methode .reset()
setzt die Umgebung auf einen initialen Zustand zurück. Standardmäßig wird die Umgebung auf einen zufälligen Zustand initialisiert. Sie können einen SEED
-Parameter mit der Methode .reset()
verwenden, um die Umgebung jedes Mal auf denselben Zustand zu initialisieren, wenn das Programm ausgeführt wird. Der folgende Code zeigt, wie dies gemacht wird:
SEED = 1111 env.reset(seed=SEED)
Die Auswahl von Aktionen beinhaltet auch Zufälligkeit. Um diese Zufälligkeit zu kontrollieren und einen vollständig reproduzierbaren Trainingspfad zu erhalten, können wir die Zufallsgeneratoren von NumPy und PyTorch initialisieren:
np.random.seed(SEED) torch.manual_seed(SEED)
Zufällige gegen intelligente Aktionen
In jedem Schritt in einem Markov-Prozess kann der Agent zufällig eine Aktion wählen und die Umgebung erkunden, bis er einen Endzustand erreicht. Durch zufällige Auswahl von Aktionen:
- Kann es lange dauern, bis der Endzustand erreicht wird.
- Die kumulativen Belohnungen sind viel niedriger als sie hätten sein können.
Das Training des Agenten, die Auswahl von Aktionen basierend auf früheren Erfahrungen (im Umgang mit der Umgebung) zu optimieren, ist effizienter, um langfristige Belohnungen zu maximieren.
Der ungeschulte Agent beginnt mit zufälligen Aktionen, die auf einer zufällig initialisierten Richtlinie basieren. Diese Richtlinie wird typischerweise als neuronales Netzwerk dargestellt. Während des Trainings lernt der Agent die optimale Richtlinie, die die Belohnungen maximiert. Im RL wird der Trainingsprozess auch als Richtlinienoptimierung bezeichnet.
Es gibt verschiedene Methoden der Richtlinienoptimierung. Die Bellman-Gleichungen beschreiben, wie der Wert von RL-Richtlinien berechnet und die optimale Richtlinie bestimmt wird. In diesem Tutorial verwenden wir eine einfache Technik namens Richtliniengradienten. Andere Methoden wie Proximal Policy Optimization (PPO) existieren ebenfalls.
Implementierung eines einfachen Richtliniengradienten-Agents
Um einen RL-Agenten aufzubauen, der Policy-Gradienten verwendet, erstellen wir ein neuronales Netzwerk, um die Richtlinie umzusetzen, schreiben Funktionen zur Berechnung der Erträge und des Verlusts aus den schrittweisen Belohnungen und den Aktionswahrscheinlichkeiten, und aktualisieren die Richtlinie iterativ mit Hilfe von Standard-Backpropagation-Techniken.
Einrichten des Richtliniennetzwerks
Wir verwenden ein neuronales Netzwerk, um die Richtlinie umzusetzen. Da CartPole-v1
eine einfache Umgebung ist, verwenden wir ein neuronales Netzwerk mit:
- Eingabedimensionen, die der Dimensionalität des Beobachtungsraums der Umgebung entsprechen.
- Einer einzigen versteckten Schicht mit 64 Neuronen.
- Ausgabedimensionen entsprechen der Dimensionalität des Aktionsraums der Umgebung.
Die Funktion des Richtliniennetzwerks besteht daher darin, beobachtete Zustände auf Aktionen abzubilden. Bei einer Eingabebeobachtung sagt es die richtige Aktion voraus. Der folgende Code implementiert das Richtliniennetzwerk:
class PolicyNetwork(nn.Module): def __init__(self, input_dim, hidden_dim, output_dim, dropout): super().__init__() self.layer1 = nn.Linear(input_dim, hidden_dim) self.layer2 = nn.Linear(hidden_dim, output_dim) self.dropout = nn.Dropout(dropout) def forward(self, x): x = self.layer1(x) x = self.dropout(x) x = F.relu(x) x = self.layer2(x) return x
Belohnungssammlung und Vorwärtsdurchlauf
Wie bereits erwähnt, gibt die Umgebung in jedem Schritt des Markov-Prozesses eine Belohnung basierend auf der Aktion und dem Zustand des Agenten. Das Ziel in der RL besteht darin, die Gesamtrückkehr zu maximieren.
- Die Rückkehr zu jedem Zeitschritt ist die kumulierte Summe der Belohnungen, die von Anfang an bis zu diesem Schritt erhalten wurden.
- Die Gesamtrückkehr in jeder Episode wird durch die Akkumulation aller schrittweisen Belohnungen aus dieser Episode erhalten. Die Gesamtrückkehr ist somit die Rückkehr zum letzten Zeitschritt (wenn der Agent einen terminalen Zustand erreicht).
In der Praxis ist es beim Akkumulieren von Belohnungen üblich:
- Zukünftige Belohnungen mithilfe eines Diskontierungsfaktors anzupassen.
- Das Array der schrittweisen Rückgaben zu normalisieren, um ein reibungsloses und stabiles Training sicherzustellen.
Der folgende Code zeigt, wie das gemacht wird:
def calculate_stepwise_returns(rewards, discount_factor): returns = [] R = 0 for r in reversed(rewards): R = r + R * discount_factor returns.insert(0, R) returns = torch.tensor(returns) normalized_returns = (returns - returns.mean()) / returns.std() return normalized_returns
Der Vorwärtspass besteht darin, den Agenten gemäß der aktuellen Richtlinie laufen zu lassen, bis er einen Endzustand erreicht, und die schrittweisen Belohnungen und Aktionswahrscheinlichkeiten zu sammeln. Die folgenden Schritte erläutern, wie der Vorwärtspass implementiert wird:
- Setzen Sie die Umgebung auf einen Anfangszustand zurück.
- Initialisieren Sie Puffer zum Speichern der Aktionswahrscheinlichkeiten, der Belohnungen und der kumulierten Rendite
- Verwenden Sie die Funktion
.step()
zum iterativen Ausführen des Agenten in der Umgebung, bis sie endet: - Holen Sie die Beobachtung des Zustands der Umgebung ein.
- Erhalten Sie die Aktion, die von der Richtlinie basierend auf der Beobachtung vorhergesagt wird.
- Verwenden Sie die
Softmax
-Funktion, um die Wahrscheinlichkeit der Ausführung der vorhergesagten Aktion zu schätzen. - Simulieren Sie eine kategoriale Wahrscheinlichkeitsverteilung basierend auf diesen geschätzten Wahrscheinlichkeiten.
- Wählen Sie diese Verteilung aus, um die Aktion des Agenten zu erhalten.
- Schätzen Sie die Log-Wahrscheinlichkeit der ausgewählten Aktion aus der simulierten Verteilung.
- Fügen Sie die Log-Wahrscheinlichkeit der Aktionen und die Belohnungen aus jedem Schritt ihren jeweiligen Puffern hinzu.
- Schätzen Sie die normalisierten und rabattierten Werte der Rückgaben in jedem Schritt basierend auf den Belohnungen.
def forward_pass(env, policy, discount_factor): log_prob_actions = [] rewards = [] done = False episode_return = 0 policy.train() observation, info = env.reset() while not done: observation = torch.FloatTensor(observation).unsqueeze(0) action_pred = policy(observation) action_prob = F.softmax(action_pred, dim = -1) dist = distributions.Categorical(action_prob) action = dist.sample() log_prob_action = dist.log_prob(action) observation, reward, terminated, truncated, info = env.step(action.item()) done = terminated or truncated log_prob_actions.append(log_prob_action) rewards.append(reward) episode_return += reward log_prob_actions = torch.cat(log_prob_actions) stepwise_returns = calculate_stepwise_returns(rewards, discount_factor) return episode_return, stepwise_returns, log_prob_actions
Aktualisierung der Richtlinie basierend auf Belohnungen
Der Verlust stellt die Größe dar, auf die wir Gradientenabstieg anwenden. Das Ziel in RL ist es, die Rückgaben zu maximieren. Daher verwenden wir den erwarteten Rückgabewert als Proxy für den Verlust. Der erwartete Rückgabewert wird als das Produkt der schrittweisen erwarteten Rückgaben und der Log-Wahrscheinlichkeit der schrittweisen Aktionen berechnet. Der folgende Code berechnet den Verlust:
def calculate_loss(stepwise_returns, log_prob_actions): loss = -(stepwise_returns * log_prob_actions).sum() return loss
Um die Richtlinie zu aktualisieren, führen Sie Backpropagation in Bezug auf die Verlustfunktion aus. Die update_policy()
Methode unten ruft die calculate_loss()
Methode auf. Anschließend wird die Backpropagation auf diesen Verlust ausgeführt, um die Richtlinienparameter, d.h. die Modellgewichte des Richtliniennetzwerks, zu aktualisieren.
def update_policy(stepwise_returns, log_prob_actions, optimizer): stepwise_returns = stepwise_returns.detach() loss = calculate_loss(stepwise_returns, log_prob_actions) optimizer.zero_grad() loss.backward() optimizer.step() return loss.item()
Die Aktualisierung der Richtlinie basierend auf dem Gradienten der Erträge wird als Policy-Gradient-Methode bezeichnet.
Die Richtlinie trainieren
Wir haben nun alle Komponenten, die benötigt werden, um die Richtlinie zu trainieren und zu evaluieren. Wir implementieren die Trainingsschleife, wie in den folgenden Schritten erklärt:
Bevor wir beginnen, deklarieren wir die Hyperparameter, instanziieren eine Richtlinie und erstellen einen Optimierer:
- Deklarieren Sie die Hyperparameter als Python-Konstanten:
MAX_EPOCHS
ist die maximale Anzahl von Iterationen, die wir bereit sind auszuführen, um die Richtlinie zu trainieren.DISCOUNT_FACTOR
bestimmt die relative Bedeutung von Belohnungen aus zukünftigen Zeitschritten. Ein Diskontierungsfaktor von 1 bedeutet, dass alle Belohnungen gleich wichtig sind, während ein Wert von 0 bedeutet, dass nur die Belohnung aus dem aktuellen Zeitschritt wichtig ist.N_TRIALS
ist die Anzahl der Episoden, über die wir die Rückgaben mitteln, um die Leistung des Agenten zu bewerten. Wir entscheiden, dass das Training erfolgreich ist, wenn die durchschnittliche Rückgabe überN_TRIALS
Episoden über dem Schwellenwert liegt.REWARD_THRESHOLD
: Wenn die Strategie eine Rückgabe erzielen kann, die höher als der Schwellenwert ist, wird sie als erfolgreich angesehen.DROPOUT
bestimmt den Anteil der Gewichte, die zufällig auf null gesetzt werden sollen. Die Dropout-Funktion setzt zufällig einen Teil der Modellgewichte auf null. Dies verringert die Abhängigkeit von spezifischen Neuronen und verhindert Überanpassung, wodurch das Netzwerk robuster wird.LEARNING_RATE
bestimmt, wie stark die Richtlinienparameter in jedem Schritt geändert werden können. Die Aktualisierung der Parameter in jeder Iteration ist das Produkt des Gradienten und der Lernrate.- Definieren Sie die Richtlinie als eine Instanz der Klasse
PolicyNetwork
(die zuvor implementiert wurde). - Erstellen Sie einen Optimierer unter Verwendung des Adam-Algorithmus und der Lernrate.
Um die Richtlinie zu trainieren, führen wir iterativ die Trainingsschritte aus, bis der durchschnittliche Rückgabewert (über N_TRIALS
) größer als der Belohnungsschwellenwert ist:
- Führen Sie für jede Episode den Vorwärtsschritt einmal aus. Sammeln Sie die Protokollwahrscheinlichkeit von Aktionen, die schrittweisen Rückgabewerte und die Gesamtrückgabe aus dieser Episode. Akkumulieren Sie die episodischen Rückgaben in einem Array.
- Berechne den Verlust unter Verwendung der logarithmischen Wahrscheinlichkeiten und der schrittweisen Renditen. Führe die Rückpropagation auf den Verlust durch. Verwende den Optimierer, um die Politikparameter zu aktualisieren.
- Überprüfe, ob die durchschnittliche Rendite über
N_TRIALS
die Belohnungsschwelle überschreitet.
Der folgende Code implementiert diese Schritte:
def main(): MAX_EPOCHS = 500 DISCOUNT_FACTOR = 0.99 N_TRIALS = 25 REWARD_THRESHOLD = 475 PRINT_INTERVAL = 10 INPUT_DIM = env.observation_space.shape[0] HIDDEN_DIM = 128 OUTPUT_DIM = env.action_space.n DROPOUT = 0.5 episode_returns = [] policy = PolicyNetwork(INPUT_DIM, HIDDEN_DIM, OUTPUT_DIM, DROPOUT) LEARNING_RATE = 0.01 optimizer = optim.Adam(policy.parameters(), lr = LEARNING_RATE) for episode in range(1, MAX_EPOCHS+1): episode_return, stepwise_returns, log_prob_actions = forward_pass(env, policy, DISCOUNT_FACTOR) _ = update_policy(stepwise_returns, log_prob_actions, optimizer) episode_returns.append(episode_return) mean_episode_return = np.mean(episode_returns[-N_TRIALS:]) if episode % PRINT_INTERVAL == 0: print(f'| Episode: {episode:3} | Mean Rewards: {mean_episode_return:5.1f} |') if mean_episode_return >= REWARD_THRESHOLD: print(f'Reached reward threshold in {episode} episodes') break
Zuletzt rufe die main()
Funktion auf, um die Politik zu trainieren:
main()
Verwenden Sie dieses DataLab-Arbeitsbuch, um den obigen Algorithmus direkt auszuführen und die CartPole-Umgebung mithilfe von RL zu lösen.
Fortgeschrittene Techniken im Fitnessstudio
Nachdem wir gezeigt haben, wie man einen RL-Algorithmus implementiert, diskutieren wir nun einige fortgeschrittene Techniken, die in der Praxis häufig verwendet werden.
Verwendung vorgefertigter Architekturen
Die Implementierung von RL-Algorithmen von Grund auf ist ein langer und schwieriger Prozess, insbesondere für komplexe Umgebungen und modernste Richtlinien.
Eine praktischere Alternative ist die Verwendung von Software wie Stable Baselines3. Es enthält erprobte Implementierungen von RL-Algorithmen. Es umfasst vortrainierte Agenten, Trainingsskripte, Evaluierungstools und Module zum Zeichnen von Grafiken und Aufzeichnen von Videos.
Ray RLib ist ein weiteres beliebtes Tool für RL. RLib ist als skalierbare Lösung konzipiert, die es einfach macht, RL-Algorithmen auf Multi-GPU-Systemen zu implementieren. Es unterstützt auch Multi-Agenten-RL, was neue Möglichkeiten eröffnet, wie:
- Unabhängiges Lernen von Multi-Agenten: Jeder Agent betrachtet andere Agenten als Teil der Umgebung.
- Kollaboratives Multi-Agent-Training: Eine Gruppe von Agenten teilt sich dieselbe Politik und Wertfunktionen und lernt parallel aus den Erfahrungen der anderen.
- Adversariales Training: Agenten (oder Gruppen von Agenten) treten in wettbewerbsorientierten spielähnlichen Umgebungen gegeneinander an.
Mit sowohl RLib als auch Stable Baselines3 können Sie Umgebungen aus OpenAI Gymnasium importieren und verwenden.
Benutzerdefinierte Umgebungen
Umgebungen, die mit Gymnasium geliefert werden, sind die richtige Wahl für das Testen neuer RL-Strategien und das Trainieren von Richtlinien. Für die meisten praktischen Anwendungen müssen Sie jedoch eine Umgebung erstellen und verwenden, die das Problem, das Sie lösen möchten, genau widerspiegelt. Sie können Gymnasium verwenden, um eine benutzerdefinierte Umgebung zu erstellen. Der Vorteil der Verwendung von benutzerdefinierten Umgebungen in Gymnasium besteht darin, dass viele externe Tools wie RLib und Stable Baselines3 bereits so konfiguriert sind, dass sie mit der Gymnasium-API-Struktur funktionieren.
Um eine benutzerdefinierte Umgebung in Gymnasium zu erstellen, müssen Sie Folgendes definieren:
- Den Beobachtungsraum.
- Die Endbedingungen.
- Die Menge an Aktionen, die der Agent wählen kann.
- Wie man die Umgebung initialisiert (wenn die
reset()
Funktion aufgerufen wird). - Wie die Umgebung den nächsten Zustand basierend auf den Aktionen des Agenten bestimmt (wenn die
step()
Funktion aufgerufen wird).
Um mehr zu erfahren, folgen Sie dem Leitfaden zur Erstellung benutzerdefinierter Umgebungen des Gymnasiums..
Best Practices für die Verwendung von Gymnasium
Experimentieren Sie mit verschiedenen Umgebungen
Der Code in diesem Tutorial zeigte, wie man den Policy-Gradient-Algorithmus in der CartPole-Umgebung implementiert. Dies ist eine einfache Umgebung mit einem diskreten Aktionsraum. Um das RL besser zu verstehen, empfehlen wir Ihnen, denselben Policy-Gradient-Algorithmus (und andere Algorithmen, wie PPO) in anderen Umgebungen anzuwenden.
Zum Beispiel hat die Pendelumgebung einen kontinuierlichen Aktionsraum. Er besteht aus einem einzelnen Eingang, der als kontinuierliche Variable dargestellt wird – dem (Betrag und Richtung des) Drehmoments, das dem Pendel in einem beliebigen Zustand zugeführt wird. Dieses Drehmoment kann jeden Wert zwischen -2 und +2 annehmen.
Das Experimentieren mit verschiedenen Algorithmen in verschiedenen Umgebungen hilft Ihnen, verschiedene Arten von RL-Lösungen und deren Herausforderungen besser zu verstehen.
Überwachen Sie den Schulungsfortschritt.
RL-Umgebungen bestehen oft aus Robotern, Pendeln, Bergautos, Videospielen usw. Die Visualisierung der Handlungen des Agenten innerhalb der Umgebung ermöglicht ein besseres intuitives Verständnis der Leistung der Richtlinie.
In der Turnhalle visualisiert die Methode env.render()
die Interaktionen des Agenten mit der Umgebung. Sie zeigt graphisch den aktuellen Zustand der Umgebung an – Spielbildschirme, die Position des Pendels oder des Wagenpfostens usw. Das visuelle Feedback über die Handlungen des Agenten und die Reaktionen der Umgebung hilft, die Leistung des Agenten und den Fortschritt im Schulungsprozess zu überwachen.
Es gibt vier Render-Modi: „human“, „rgb_array“, „ansi“ und „rgb_array_list“. Verwenden Sie den Render-Modus „human“, um die Leistung des Agenten zu visualisieren. Der Render-Modus wird beim Initialisieren der Umgebung angegeben. Zum Beispiel:
env = gym.make(‘CartPole-v1’, render_mode=’human’)
Zur Durchführung der Darstellung den .render()
Methode nach jeder Aktion, die vom Agenten durchgeführt wird (durch Aufruf der .step()
Methode), einbeziehen. Das nachstehende Pseudocode veranschaulicht, wie dies zu tun ist:
while not done: … step, reward, terminated, truncated, info = env.step(action.item()) env.render() …
Fehlerbehebung bei häufigen Fehlern
Gymnasium erleichtert die Interaktion mit komplexen RL-Umgebungen. Allerdings ist es eine kontinuierlich aktualisierte Software mit vielen Abhängigkeiten. Daher ist es wichtig, auf einige gängige Arten von Fehlern zu achten.
Versionsinkompatibilitäten
- Gymnasium Versionskonflikt: Farama’s Gymnasium-Softwarepaket wurde aus OpenAI’s Gym ab Version 0.26.2 abgezweigt. Es gab einige grundlegende Änderungen zwischen älteren Gym-Versionen und den neuen Versionen von Gymnasium. Viele öffentlich verfügbare Implementierungen basieren auf den älteren Gym-Versionen und funktionieren möglicherweise nicht direkt mit der neuesten Version. In solchen Fällen ist es notwendig, entweder die Installation auf eine ältere Version zurückzusetzen oder den Code anzupassen, um mit der neueren Version zu arbeiten.
- Umgebungsversionen ungleich: Viele Gymnasiumsumgebungen haben unterschiedliche Versionen. Zum Beispiel gibt es zwei CartPole-Umgebungen –
CartPole-v1
undCartPole-v0
. Obwohl das Verhalten der Umgebung in beiden Versionen gleich ist, können einige Parameter wie die Episodenlänge, die Belohnungsschwelle usw. unterschiedlich sein. Ein auf einer Version trainiertes Modell könnte auf einer anderen Version derselben Umgebung nicht so gut abschneiden. Sie müssen die Trainingsparameter aktualisieren und das Modell für jede Umgebungsversion neu trainieren. - Abhängigkeitsversionskonflikt: Das Gymnasium hängt von Abhängigkeiten wie NumPy und PyTorch ab. Stand Dezember 2024 sind die neuesten Versionen dieser Abhängigkeiten
numpy 2.1.3
undtorch 2.5.1
. Allerdings funktioniert das Gymnasium am besten mittorch 1.13.0
undnumpy 1.23.3
. Es können Probleme auftreten, wenn Sie das Gymnasium in einer Umgebung mit diesen vorinstallierten Abhängigkeiten installieren. Wir empfehlen, das Gymnasium in einer frischen Conda-Umgebung zu installieren und zu verwenden.
Konvergenzprobleme
- Hyperparameter: Wie andere Machine-Learning-Algorithmen sind RL-Policies empfindlich gegenüber Hyperparametern wie Lernrate, Diskontierungsfaktor usw. Wir empfehlen, die Hyperparameter manuell zu experimentieren und anzupassen oder automatisierte Techniken wie Rastersuche und Zufallssuche zu verwenden.
- Exploration versus Exploitation: Für einige Richtlinienklassen (wie PPO) verfolgt der Agent eine zweigleisige Strategie: Erkunden der Umgebung, um neue Pfade zu entdecken, und Annahme eines gierigen Ansatzes, um die Belohnungen auf der Grundlage der bisher bekannten Pfade zu maximieren. Wenn er zu viel erkundet, konvergiert die Richtlinie nicht. Andererseits wird der optimale Pfad nie ausprobiert, wenn nicht genügend erkundet wird. Daher ist es wichtig, das richtige Gleichgewicht zwischen Exploration und Ausbeutung zu finden. Es ist auch üblich, die Exploration in früheren Episoden zu priorisieren und die Ausbeutung in späteren Episoden während des Trainings.
Trainingsinstabilität
- Große Lernraten: Wenn die Lernrate zu hoch ist, unterliegen die Richtlinienparameter in jedem Schritt großen Aktualisierungen. Dies könnte dazu führen, dass der optimale Wertebereich verfehlt wird. Eine übliche Lösung besteht darin, die Lernrate allmählich zu reduzieren, um kleinere und stabilere Aktualisierungen sicherzustellen, wenn das Training konvergiert.
- Übermäßige Exploration: Zu viel Zufälligkeit (Entropie) bei der Auswahl von Aktionen verhindert die Konvergenz und führt zu großen Variationen in der Verlustfunktion zwischen aufeinanderfolgenden Schritten. Um einen stabilen und konvergenten Trainingsprozess zu haben, sollte die Exploration mit der Ausbeutung ausgeglichen werden.
- Falsche Wahl des Algorithmus:Einfache Algorithmen wie Policy-Gradienten können zu instabilem Training in komplexen Umgebungen mit großen Aktions- und Zustandsräumen führen. In solchen Fällen empfehlen wir die Verwendung robusterer Algorithmen wie PPO und Trust Region Policy Optimization (TRPO). Diese Algorithmen vermeiden große Richtlinienaktualisierungen in jedem Schritt und können stabiler sein.
- Zufälligkeit:RL-Algorithmen reagieren bekanntermaßen empfindlich auf Anfangszustände und die Zufälligkeit, die in der Aktionsauswahl vorhanden ist. Wenn ein Training instabil ist, kann es manchmal stabilisiert werden, indem ein anderer Zufallsseed verwendet wird oder die Richtlinie neu initialisiert wird.
Conclusion
In diesem Tutorial haben wir die grundlegenden Prinzipien von RL erkundet, Gymnasium als Softwarepaket mit einer sauberen API zur Schnittstelle mit verschiedenen RL-Umgebungen diskutiert und gezeigt, wie man ein Python-Programm schreibt, um einen einfachen RL-Algorithmus zu implementieren und ihn in einer Gymnasium-Umgebung anzuwenden.
Nachdem Sie die Grundlagen in diesem Tutorial verstanden haben, empfehle ich, Gymnasium-Umgebungen zu verwenden, um die Konzepte von RL anzuwenden, um praktische Probleme wie die Optimierung von Taxirouten und Aktienhandelssimulationen zu lösen.
Source:
https://www.datacamp.com/tutorial/reinforcement-learning-with-gymnasium