Cursus
Reinforcement Learning (RL) is een van de drie belangrijkste machine learning‑paradigma’s, naast supervised en unsupervised learning. In RL leert een agent met zijn omgeving te interageren om de cumulatieve beloningen te maximaliseren. Het leert via trial-and-error de optimale actie onder verschillende omgevingscondities. Reinforcement Learning with Human Feedback (RLHF) stelt de agent in staat om gedrag bij elke stap aan te passen op basis van menselijke input.
RL lost problemen op zoals zelfrijdende auto’s, geautomatiseerde handel, computerspelers in videogames, het trainen van robots en meer. Wanneer diepe neurale netwerken worden gebruikt om RL‑algoritmen toe te passen, heet dat Deep Reinforcement Learning.
In deze tutorial laat ik je zien hoe je aan de slag gaat met Gymnasium, een open‑source Python‑bibliotheek voor het ontwikkelen en vergelijken van reinforcement learning‑algoritmen. Ik demonstreer hoe je het installeert, verschillende RL‑omgevingen verkent en met Python een eenvoudige agent bouwt om een RL‑algoritme te implementeren.
Wat is Gymnasium?
Gymnasium is een open‑source Python‑bibliotheek die is ontworpen om de ontwikkeling van RL‑algoritmen te ondersteunen. Om onderzoek en ontwikkeling in RL te faciliteren, biedt Gymnasium:
- Een grote variatie aan omgevingen, van eenvoudige games tot problemen die echte scenario’s nabootsen.
- Gestroomlijnde API’s en wrappers om met de omgevingen te interfacen.
- De mogelijkheid om aangepaste omgevingen te creëren en te profiteren van het API‑raamwerk.
Ontwikkelaars kunnen RL‑algoritmen bouwen en API‑aanroepen gebruiken voor taken zoals:
- De door de agent gekozen actie doorgeven aan de omgeving.
- Inzicht krijgen in de toestand en beloning van de omgeving na elke actie.
- Het model trainen.
- De prestaties van het model testen.
OpenAI’s Gym versus Farama’s Gymnasium
OpenAI heeft niet veel middelen ingezet voor de ontwikkeling van Gym omdat het geen zakelijke prioriteit was voor het bedrijf. De Farama Foundation werd opgericht om RL‑bibliotheken op de lange termijn te standaardiseren en te onderhouden. Gymnasium is de fork van OpenAI’s Gym door de Farama Foundation. Gymnasium 0.26.2 is een drop‑in‑vervanging voor Gym 0.26.2. Met de fork wil Farama functionele (naast klassen‑gebaseerde) methoden toevoegen voor alle API‑aanroepen, vectoromgevingen ondersteunen en de wrappers verbeteren. Het algemene doel is om het framework schoner en efficiënter te maken.
Gymnasium instellen
Gymnasium heeft specifieke versies nodig (niet de allernieuwste releases) van verschillende afhankelijkheden zoals NumPy en PyTorch. We raden daarom aan om een nieuwe Conda‑ of venv‑omgeving of een nieuw notebook te maken om Gymnasium te installeren, te gebruiken en RL‑programma’s uit te voeren.
Je kunt deze DataLab‑werkmap gebruiken om de tutorial stap voor stap te volgen.
Gymnasium installeren
Om Gymnasium op een server of lokale machine te installeren, voer je uit:
$ pip install gymnasium
Om te installeren in een Notebook zoals Google Colab of DataCamp’s DataLab, gebruik je:
!pip install gymnasium
Bovenstaande opdracht installeert Gymnasium en de juiste versies van de afhankelijkheden.
Gymnasium‑omgevingen verkennen
Vanaf november 2024 bevat Gymnasium meer dan 60 ingebouwde omgevingen. Om de beschikbare ingebouwde omgevingen te bekijken, gebruik je de functie gym.envs.registry.all(), zoals geïllustreerd in het onderstaande voorbeeld:
import gymnasium as gym
for i in gym.envs.registry.keys():
print(i)
Je kunt ook de Gymnasium‑homepage bezoeken. De linkerkolom bevat links naar alle omgevingen. De webpagina van elke omgeving bevat details, zoals acties, toestanden, enz.
Omgevingen zijn georganiseerd in categorieën zoals Classic Control, Box2D en meer. Hieronder noem ik enkele veelvoorkomende omgevingen per groep:
- Classic Control: Dit zijn canonieke omgevingen die in RL‑ontwikkeling worden gebruikt; ze vormen de basis van veel voorbeelden uit leerboeken. Ze bieden de juiste mix van complexiteit en eenvoud om nieuwe RL‑algoritmen te testen en te benchmarken. Classic Control‑omgevingen in Gymnasium omvatten:
- Acrobot
- Cart Pole
- Mountain Car Discrete
- Mountain Car Continuous
- Pendulum
- Box2D: Box2D is een 2D‑physics engine voor games. Omgevingen gebaseerd op deze engine omvatten eenvoudige games zoals:
- Lunar Lander
- Car Racing
- ToyText: Dit zijn kleine en eenvoudige omgevingen die vaak worden gebruikt om RL‑algoritmen te debuggen. Veel van deze omgevingen zijn gebaseerd op het small grid world‑model en eenvoudige kaartspellen. Voorbeelden zijn:
- Blackjack
- Taxi
- Frozen Lake
- MuJoCo: Multi‑Joint dynamics with Contact (MuJoCo) is een open‑source physics engine die omgevingen simuleert voor toepassingen zoals robotica, biomechanica, ML, enz. MuJoCo‑omgevingen in Gymnasium omvatten:
- Ant
- Hopper
- Humanoid
- Swimmer
- En meer
Naast de ingebouwde omgevingen kan Gymnasium met veel externe omgevingen worden gebruikt via dezelfde API.
We gebruiken in deze tutorial een van de canonieke Classic Control‑omgevingen. Om een specifieke omgeving te importeren, gebruik je het commando .make() en geef je de naam van de omgeving als argument door. Om bijvoorbeeld een nieuwe omgeving op basis van CartPole (versie 1) te maken, gebruik je onderstaand commando:
import gymnasium as gym
env = gym.make("CartPole-v1")
Reinforcement learning‑concepten in Gymnasium begrijpen
Kort gezegd bestaat Reinforcement Learning uit een agent (zoals een robot) die met zijn omgeving interageert. Een policy bepaalt de acties van de agent. Afhankelijk van de acties van de agent geeft de omgeving op elke timestep een beloning (of straf). De agent gebruikt RL om de optimale policy te vinden die de totale beloningen maximaliseert die de agent verdient.
Componenten van een RL‑omgeving
De volgende elementen zijn de sleutelcomponenten van een RL‑omgeving:
- Omgeving: Het externe systeem, de wereld of context. De agent interageert met de omgeving in een reeks timesteps. In elke timestep doet de omgeving, op basis van de actie van de agent:
- Een beloning (of straf) geven
- De volgende toestand bepalen
- Toestand: Een wiskundige representatie van de huidige configuratie van de omgeving.
- Bijvoorbeeld: de toestand van een pendulum‑omgeving kan bij elke timestep de positie en de hoeksnelheid van de slinger bevatten.
- Terminale toestand: een toestand die niet tot nieuwe/andere toestanden leidt.
- Agent: Het algoritme dat de omgeving observeert en op basis daarvan verschillende acties onderneemt. Het doel van de agent is om zijn beloningen te maximaliseren.
- Bijvoorbeeld: de agent beslist hoe hard en in welke richting hij de slinger duwt.
- Observatie: Een wiskundige representatie van het zicht van de agent op de omgeving, bijvoorbeeld verkregen via sensoren.
- Actie: De beslissing die de agent neemt voordat hij naar de volgende stap gaat. De actie beïnvloedt de volgende toestand van de omgeving en levert de agent een beloning op.
- Beloning: De feedback van de omgeving aan de agent. Deze kan positief of negatief zijn, afhankelijk van de actie en de toestand van de omgeving.
- Opbrengst (return): De verwachte cumulatieve opbrengst over toekomstige timesteps. Beloningen uit toekomstige timesteps kunnen worden verdisconteerd met een discontovoet.
- Policy: De strategie van de agent over welke actie te nemen in verschillende toestanden. Deze wordt meestal weergegeven als een waarschijnlijkheidsmatrix, P, die toestanden aan acties koppelt.
- Gegeven een eindige set van m mogelijke toestanden en n mogelijke acties, duidt element Pmn in de matrix de kans aan om actie an te nemen in toestand sm.
- Episode: De reeks timesteps vanaf de (gerandomiseerde) initiële toestand totdat de agent een terminale toestand bereikt.
Observatieruimte en actieruimte
De observatie is de informatie die de agent over de omgeving verzamelt. Een agent, bijvoorbeeld een robot, kan informatie uit de omgeving verzamelen met sensoren. Idealiter moet de agent de volledige toestand kunnen observeren, die alle aspecten van de omgeving beschrijft. In de praktijk gebruikt de agent zijn observaties als proxy voor de toestand. Zo bepalen de observaties de acties van de agent.
Een ruimte is analoog aan een wiskundige verzameling. De ruimte van items X bevat alle mogelijke instanties van X. De ruimte van X definieert ook de structuur (syntaxis en formaat) van alle items van het type X. Elke Gymnasium‑omgeving heeft twee ruimtes: de actieruimte, action_space, en de observatieruimte, observation_space. Zowel de actie‑ als observatieruimte zijn afgeleid van de superklasse gymnasium.spaces.Space.
Observatieruimte
De observatieruimte is de ruimte die alle mogelijke observaties bevat. Het definieert ook het formaat waarin observaties worden opgeslagen. De observatieruimte wordt doorgaans weergegeven als een object van het datitype Box. Dit is een ndarray die de parameters van de observaties beschrijft. De box specificeert de grenzen van elke dimensie. Je kunt de observatieruimte voor een omgeving bekijken met de methode observation_space:
print("observation space: ", env.observation_space)
In het geval van de omgeving CartPole-v1 ziet de uitvoer eruit zoals in het voorbeeld hieronder:
observation space: Box([-4.8 -inf -0.41887903 -inf], [4.8 inf 0.41887903 inf], (4,), float32)
In dit voorbeeld heeft de observatieruimte van CartPole-v1 4 dimensies. De 4 elementen van de observatie‑array zijn:
- Positie van de kar – varieert tussen −4,8 en +4,8
- Snelheid van de kar – varieert tussen − en +
- Hoek van de paal – varieert tussen −0,4189 en +0,4189
- Hoeksnelheid van de paal – varieert tussen − en +
Om een voorbeeld van een individuele observatie‑array te zien, gebruik je het commando .reset().
observation, info = env.reset()
print("observation: ", observation)
In het geval van de omgeving CartPole-v1 ziet de uitvoer eruit zoals in het voorbeeld hieronder:
[ 0.03481963 -0.0277232 0.01703267 -0.04870504]
De vier elementen van deze array komen overeen met de vier geobserveerde grootheden (positie van de kar, snelheid van de kar, hoek van de paal, hoeksnelheid van de paal), zoals eerder uitgelegd.
Actieruimte
De actieruimte omvat alle mogelijke acties die de agent kan nemen. De actieruimte definieert ook het formaat waarin acties worden weergegeven. Je kunt de actieruimte voor een omgeving bekijken met de methode action_space:
print("action space: ", env.action_space)
In het geval van de omgeving CartPole-v1 is de actieruimte discreet. Er zijn in totaal twee acties die de agent kan nemen:
- 0: Duw de kar naar links
- 1: Duw de kar naar rechts
Je eerste RL‑agent bouwen met Gymnasium
In de vorige secties hebben we de basisconcepten van RL en Gymnasium verkend. In deze sectie laat ik zien hoe je Gymnasium gebruikt om een RL‑agent te bouwen.
De omgeving maken en resetten
De eerste stap is het aanmaken van een instantie van de omgeving. Om nieuwe omgevingen te maken, gebruik je de methode .make().
env = gym.make('CartPole-v1')
De interacties van de agent veranderen de toestand van de omgeving. De methode .reset() zet de omgeving terug naar een initiële toestand. Standaard wordt de omgeving geïnitialiseerd naar een willekeurige toestand. Je kunt een parameter SEED gebruiken met de methode .reset() om de omgeving elke keer dat het programma draait in dezelfde toestand te initialiseren. De onderstaande code laat zien hoe dit werkt:
SEED = 1111
env.reset(seed=SEED)
Het samplen van acties bevat ook willekeur. Om deze willekeur te beheersen en een volledig reproduceerbaar trainingstraject te krijgen, kunnen we de random generators van NumPy en PyTorch seeden:
np.random.seed(SEED)
torch.manual_seed(SEED)
Willekeurige versus slimme acties
In elke stap in een Markov‑proces kan de agent willekeurig een actie kiezen en de omgeving verkennen totdat hij een terminale toestand bereikt. Door acties willekeurig te kiezen:
- Kan het lang duren om de terminale toestand te bereiken.
- Zijn de cumulatieve beloningen veel lager dan ze hadden kunnen zijn.
Het trainen van de agent om de selectie van acties te optimaliseren op basis van eerdere ervaringen (van interactie met de omgeving) is efficiënter om langetermijnbeloningen te maximaliseren.
De ongetrainde agent begint met willekeurige acties op basis van een willekeurig geïnitialiseerde policy. Deze policy wordt meestal weergegeven als een neuraal netwerk. Tijdens het trainen leert de agent de optimale policy die de beloningen maximaliseert. In RL wordt het trainingsproces ook wel policy‑optimalisatie genoemd.
Er zijn verschillende methoden voor policy‑optimalisatie. De Bellman‑vergelijkingen beschrijven hoe je de waarde van RL‑policies berekent en de optimale policy bepaalt. In deze tutorial gebruiken we een eenvoudige techniek genaamd policy gradients. Er bestaan ook andere methoden, zoals Proximal Policy Optimization (PPO).
Een eenvoudige policy‑gradient‑agent implementeren
Om een RL‑agent te bouwen die policy gradients gebruikt, maken we een neuraal netwerk om de policy te implementeren, schrijven we functies om de returns en de loss te berekenen op basis van de stapgewijze beloningen en de actiekansen, en updaten we iteratief de policy met standaard backpropagation‑technieken.
De policy‑netwerkarchitectuur opzetten
We gebruiken een neuraal netwerk om de policy te implementeren. Omdat CartPole-v1 een eenvoudige omgeving is, gebruiken we een neuraal netwerk met:
- Invoerdimensies gelijk aan de dimensionaliteit van de observatieruimte van de omgeving.
- Eén verborgen laag met 64 neuronen.
- Uitvoerdimensies gelijk aan de dimensionaliteit van de actieruimte van de omgeving.
De functie van het policy‑netwerk is dus om geobserveerde toestanden naar acties te mappen. Gegeven een inputobservatie, voorspelt het de juiste actie. De onderstaande code implementeert het policy‑netwerk:
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
Beloningen verzamelen en de forward pass
Zoals vermeld, geeft de omgeving in elke stap van het Markov‑proces een beloning op basis van de actie en toestand van de agent. Het doel in RL is om de totale opbrengst te maximaliseren.
- De opbrengst op elke timestep is de cumulatieve som van de beloningen die vanaf het begin tot aan die stap zijn behaald.
- De totale opbrengst in elke episode wordt verkregen door alle stapgewijze beloningen uit die episode op te tellen. De totale opbrengst is dus de opbrengst op de laatste timestep (wanneer de agent een terminale toestand bereikt).
In de praktijk is het bij het accumuleren van beloningen gebruikelijk om:
- Toekomstige beloningen aan te passen met een discontovoet.
- De array met stapgewijze returns te normaliseren om een soepele en stabiele training te verzekeren.
De onderstaande code laat zien hoe je dit doet:
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
De forward pass bestaat uit het laten draaien van de agent op basis van de huidige policy totdat een terminale toestand is bereikt en het verzamelen van de stapgewijze beloningen en actiekansen. De onderstaande stappen leggen uit hoe je de forward pass implementeert:
- Reset de omgeving naar een initiële toestand.
- Initialiseer buffers om de actiekansen, de beloningen en de cumulatieve opbrengst op te slaan
- Gebruik de functie
.step()om de agent iteratief in de omgeving te laten draaien totdat deze stopt: - Verkrijg de observatie van de toestand van de omgeving.
- Bepaal de actie die door de policy wordt voorspeld op basis van de observatie.
- Gebruik de functie
Softmaxom de kans te schatten op het nemen van de voorspelde actie. - Simuleer een categorische kansverdeling op basis van deze geschatte kansen.
- Sample deze verdeling om de actie van de agent te krijgen.
- Schat de log‑kans van de gesamplede actie uit de gesimuleerde verdeling.
- Voeg de log‑kansen van de acties en de beloningen van elke stap toe aan hun respectieve buffers.
- Schat de genormaliseerde en verdisconteerde waarden van de returns op elke stap op basis van de beloningen.
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
Policy updaten op basis van beloningen
De loss vertegenwoordigt de grootheid waarop we gradient descent toepassen. Het doel in RL is om de returns te maximaliseren. We gebruiken dus de verwachte returnwaarde als proxy voor de loss. De verwachte returnwaarde wordt berekend als het product van de stapgewijze verwachte returns en de log‑kans van de stapgewijze acties. De onderstaande code berekent de loss:
def calculate_loss(stepwise_returns, log_prob_actions):
loss = -(stepwise_returns * log_prob_actions).sum()
return loss
Om de policy te updaten, voer je backpropagation uit ten opzichte van de verliesfunctie. De methode update_policy() hieronder roept de methode calculate_loss() aan. Vervolgens voert hij backpropagation uit op deze loss om de policy‑parameters (d.w.z. de modelgewichten van het policy‑netwerk) te updaten.
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()
Het updaten van de policy op basis van de gradiënt van de returns wordt het policy‑gradient‑methode genoemd.
De policy trainen
We hebben nu alle componenten om de policy te trainen en te evalueren. We implementeren de trainingslus zoals uitgelegd in de volgende stappen:
Voordat we beginnen, declareren we de hyperparameters, maken we een policy aan en creëren we een optimizer:
- Declareer de hyperparameters als Python‑constanten:
MAX_EPOCHSis het maximale aantal iteraties dat we willen draaien om de policy te trainen.DISCOUNT_FACTORbepaalt de relatieve betekenis van beloningen uit toekomstige tijdstappen. Een discontovoet van 1 betekent dat alle beloningen even belangrijk zijn, terwijl een waarde van 0 betekent dat alleen de beloning van de huidige tijdstap belangrijk is.N_TRIALSis het aantal episodes waarover we de returns middelen om de prestaties van de agent te evalueren. We vinden de training geslaagd als de gemiddelde return overN_TRIALSepisodes boven de drempel ligt.REWARD_THRESHOLD: Als de policy een return groter dan de drempel kan behalen, wordt deze als succesvol beschouwd.DROPOUTbepaalt het aandeel gewichten dat willekeurig op nul wordt gezet. De dropout‑functie zet willekeurig een fractie van de modelgewichten op nul. Dit vermindert de afhankelijkheid van specifieke neuronen en voorkomt overfitting, waardoor het netwerk robuuster wordt.LEARNING_RATEbepaalt hoeveel de policy‑parameters per stap mogen worden aangepast. De update van de parameters bij elke iteratie is het product van de gradiënt en de learning rate.- Definieer de policy als een instantie van de klasse
PolicyNetwork(eerder geïmplementeerd). - Maak een optimizer aan met het Adam‑algoritme en de learning rate.
Om de policy te trainen, voeren we de trainingsstappen iteratief uit totdat de gemiddelde return (over N_TRIALS) groter is dan de beloningsdrempel:
- Voer voor elke episode eenmaal de forward pass uit. Verzamel de log‑kans van acties, de stapgewijze returns en de totale return van die episode. Accumuleer de episodische returns in een array.
- Bereken de loss met de log‑kansen en de stapgewijze returns. Voer de backpropagation uit op de loss. Gebruik de optimizer om de policy‑parameters te updaten.
- Controleer of de gemiddelde return over
N_TRIALSde beloningsdrempel overschrijdt.
De onderstaande code implementeert deze stappen:
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
Roep ten slotte de functie main() aan om de policy te trainen:
main()
Gebruik deze DataLab‑werkmap om bovenstaand algoritme direct uit te voeren en de CartPole‑omgeving met RL op te lossen.
Geavanceerde technieken in Gymnasium
Nu we hebben laten zien hoe je een RL‑algoritme implementeert, bespreken we enkele geavanceerde technieken die in de praktijk vaak worden gebruikt.
Gebruikmaken van kant‑en‑klare architecturen
RL‑algoritmen from scratch implementeren is een lang en lastig proces, zeker voor complexe omgevingen en state‑of‑the‑art policies.
Een praktischer alternatief is het gebruik van software zoals Stable Baselines3. Dit bevat beproefde implementaties van RL‑algoritmen. Het omvat voorgetrainde agents, trainingsscripts, evaluatietools en modules om grafieken te plotten en video’s op te nemen.
Ray RLib is een andere populaire tool voor RL. RLib is ontworpen als een schaalbare oplossing, waardoor het makkelijk is om RL‑algoritmen op multi‑GPU‑systemen te implementeren. Het ondersteunt ook multi‑agent RL, wat nieuwe mogelijkheden opent zoals:
- Onafhankelijk multi‑agent‑leren: Elke agent beschouwt andere agents als onderdeel van de omgeving.
- Collaboratieve multi‑agent‑training: Een groep agents deelt dezelfde policy‑ en value‑functies en leert parallel van elkaars ervaringen.
- Adversarial training: Agents (of groepen agents) concurreren met elkaar in competitieve, game‑achtige omgevingen.
Met zowel RLib als Stable Baselines3 kun je omgevingen uit OpenAI Gymnasium importeren en gebruiken.
Aangepaste omgevingen
De bij Gymnasium geleverde omgevingen zijn geschikt om nieuwe RL‑strategieën te testen en policies te trainen. Voor de meeste praktische toepassingen moet je echter een omgeving maken en gebruiken die het probleem dat je wilt oplossen nauwkeurig weerspiegelt. Je kunt Gymnasium gebruiken om een aangepaste omgeving te creëren. Het voordeel van aangepaste Gymnasium‑omgevingen is dat veel externe tools zoals RLib en Stable Baselines3 al zijn geconfigureerd om met de Gymnasium‑API‑structuur te werken.
Om een aangepaste omgeving in Gymnasium te maken, moet je definiëren:
- De observatieruimte.
- De terminale voorwaarden.
- De set acties waaruit de agent kan kiezen.
- Hoe je de omgeving initialiseert (wanneer de functie
reset()wordt aangeroepen). - Hoe de omgeving de volgende toestand bepaalt gegeven de acties van de agent (wanneer de functie
step()wordt aangeroepen).
Leer meer in de Gymnasium gids voor het maken van aangepaste omgevingen.
Best practices voor het gebruik van Gymnasium
Experimenteer met verschillende omgevingen
De code in deze tutorial liet zien hoe je het policy‑gradient‑algoritme implementeert in de CartPole‑omgeving. Dit is een eenvoudige omgeving met een discrete actieruimte. Om RL beter te begrijpen, raden we je aan hetzelfde policy‑gradient‑algoritme (en andere algoritmen, zoals PPO) toe te passen in andere omgevingen.
De Pendulum‑omgeving heeft bijvoorbeeld een continue actieruimte. Deze bestaat uit één invoer die wordt weergegeven als een continue variabele – het (magnitude en de richting van het) koppel dat op de slinger wordt toegepast in een gegeven toestand. Dit koppel kan elke waarde aannemen tussen −2 en +2.
Experimenteren met verschillende algoritmen in uiteenlopende omgevingen helpt je om verschillende soorten RL‑oplossingen en hun uitdagingen beter te begrijpen.
Monitor de trainingsvoortgang
RL‑omgevingen bestaan vaak uit robots, slingers, bergauto’s, videogames, enz. Het visualiseren van de acties van de agent binnen de omgeving geeft een betere intuïtieve kijk op de prestaties van de policy.
In Gymnasium visualiseert de methode env.render() de interacties van de agent met de omgeving. Deze toont grafisch de huidige toestand van de omgeving — game‑schermen, de positie van de slinger of cart pole, enz. Visuele feedback van de acties van de agent en de reacties van de omgeving helpt om de prestaties en voortgang van de agent tijdens de training te monitoren.
Er zijn vier render‑modi: “human”, “rgb_array”, “ansi” en “rgb_array_list”. Gebruik de render‑modus “human” om de prestaties van de agent te visualiseren. De render‑modus wordt gespecificeerd wanneer de omgeving wordt geïnitialiseerd. Bijvoorbeeld:
env = gym.make(‘CartPole-v1’, render_mode=’human’)
Om de rendering uit te voeren, roep je de methode .render() aan na elke actie die door de agent wordt uitgevoerd (via het aanroepen van de methode .step()). De pseudocode hieronder illustreert hoe je dit doet:
while not done:
…
step, reward, terminated, truncated, info = env.step(action.item())
env.render()
…
Veelvoorkomende fouten oplossen
Gymnasium maakt het makkelijk om te interfacen met complexe RL‑omgevingen. Het is echter continu bijgewerkte software met veel afhankelijkheden. Het is daarom belangrijk om op een paar veelvoorkomende fouttypen te letten.
Versieconflicten
- Gymnasium‑versieconflict: Farama’s Gymnasium‑pakket is vanaf versie 0.26.2 geforkt van OpenAI’s Gym. Er zijn enkele breaking changes geweest tussen oudere Gym‑versies en nieuwe versies van Gymnasium. Veel publiek beschikbare implementaties zijn gebaseerd op de oudere Gym‑releases en werken mogelijk niet direct met de nieuwste release. In zulke gevallen is het noodzakelijk om ofwel terug te gaan naar een oudere versie of de code aan te passen voor de nieuwere release.
- Omgevingsversieconflict: Veel Gymnasium‑omgevingen hebben verschillende versies. Zo zijn er twee CartPole‑omgevingen –
CartPole-v1enCartPole-v0. Hoewel het gedrag van de omgeving in beide versies hetzelfde is, kunnen sommige parameters, zoals de lengte van de episode, de beloningsdrempel, enz., verschillen. Een policy die op de ene versie is getraind, presteert mogelijk minder goed op een andere versie van dezelfde omgeving. Je moet de trainingsparameters bijwerken en de policy voor elke omgevingsversie opnieuw trainen. - Versieconflict van afhankelijkheden: Gymnasium is afhankelijk van pakketten zoals NumPy en PyTorch. Vanaf december 2024 zijn de nieuwste versies van deze afhankelijkheden
numpy 2.1.3entorch 2.5.1. Gymnasium werkt echter het best mettorch 1.13.0ennumpy 1.23.3. Je kunt problemen tegenkomen als je Gymnasium installeert in een omgeving waarin deze afhankelijkheden al vooraf zijn geïnstalleerd. We raden aan om Gymnasium te installeren en te gebruiken in een schone Conda‑omgeving.
Convergentieproblemen
- Hyperparameters: Net als andere machine learning‑algoritmen zijn RL‑policies gevoelig voor hyperparameters zoals learning rate, discontovoet, enz. We raden aan om te experimenteren en hyperparameters handmatig te tunen of met geautomatiseerde technieken zoals grid search en random search.
- Exploratie versus exploitatie: Voor sommige policy‑klassen (zoals PPO) hanteert de agent een tweesporenaanpak: de omgeving verkennen om nieuwe paden te ontdekken en een hebzuchtige aanpak (greedy) om de beloningen te maximaliseren op basis van de tot nu toe bekende paden. Als hij te veel exploreert, convergeert de policy niet. Omgekeerd probeert hij nooit het optimale pad als hij niet genoeg exploreert. Het is dus essentieel om de juiste balans te vinden tussen exploratie en exploitatie. Het is ook gebruikelijk om in eerdere episodes exploratie te prioriteren en in latere episodes exploitatie tijdens de training.
Trainingsinstabiliteit
- Grote learning rates: Als de learning rate te hoog is, ondergaan de policy‑parameters grote updates per stap. Dit kan ertoe leiden dat het optimum wordt gemist. Een veelgebruikte oplossing is om de learning rate geleidelijk te verlagen, zodat updates kleiner en stabieler worden naarmate de training convergeert.
- Overmatige exploratie: Te veel willekeur (entropie) in actieselectie voorkomt convergentie en leidt tot grote variaties in de verliesfunctie tussen opeenvolgende stappen. Voor een stabiel en convergent trainingsproces moet je exploratie balanceren met exploitatie.
- Verkeerde algoritmekeuze: Eenvoudige algoritmen zoals policy gradient kunnen tot instabiele training leiden in complexe omgevingen met grote actie‑ en toestandsruimtes. In dergelijke gevallen raden we robuustere algoritmen aan, zoals PPO en Trust Region Policy Optimization (TRPO). Deze algoritmen vermijden grote policy‑updates per stap en kunnen stabieler zijn.
- Willekeur: RL‑algoritmen zijn berucht gevoelig voor initiële toestanden en de willekeur die inherent is aan actieselectie. Als een trainingsrun instabiel is, kan die soms worden gestabiliseerd met een andere random seed of door de policy opnieuw te initialiseren.
Conclusie
In deze tutorial hebben we de basisprincipes van RL verkend, Gymnasium besproken als softwarepakket met een schone API om met verschillende RL‑omgevingen te interfacen, en laten zien hoe je een Python‑programma schrijft om een eenvoudig RL‑algoritme te implementeren en toe te passen in een Gymnasium‑omgeving.
Na het begrijpen van de basis in deze tutorial raad ik aan om Gymnasium‑omgevingen te gebruiken om RL‑concepten toe te passen op praktische problemen zoals optimalisatie van taxiroutes en simulaties van aandelenhandel.
FAQs
Wat is de rol van Gymnasium in reinforcement learning?
Gymnasium wordt geleverd met veel kant‑en‑klare omgevingen voor het testen en ontwikkelen van RL‑algoritmen. Het standaardiseert de interface voor deze omgevingen en voor nieuwe aangepaste omgevingen. Dit maakt het eenvoudiger om RL‑algoritmen te implementeren en te evalueren.
Ben je bij OpenAI Gymnasium beperkt tot de ingebouwde omgevingen?
Nee. Naast meer dan 60 ingebouwde omgevingen kun je met Gymnasium nieuwe omgevingen maken door hun toestand‑ en actieruimtes te declareren en te definiëren hoe de omgeving op verschillende acties reageert.
Wat is het verschil tussen Gym en Gymnasium?
Kortom, Gymnasium, onderhouden door de Farama Foundation, is de nieuwe en verbeterde versie van Gym, die niet langer door OpenAI wordt onderhouden. Gymnasium zou moeten werken als een drop‑in‑vervanging voor Gym 0.26.2.
Wat is het verschil tussen policy‑gebaseerde en value‑gebaseerde RL‑methoden?
Bij policy‑gebaseerde methoden, zoals policy gradients, past de agent de policy‑parameters direct aan om te vinden welke policy tot de maximale verwachte opbrengst leidt.
Bij value‑gebaseerde methoden wordt de agent getraind op de waardefunctie. Het leren van de optimale waardefunctie helpt om de optimale policy af te leiden.
Is handmatig algoritmen coderen de beste en enige manier om RL‑problemen op te lossen?
Code from scratch schrijven is de beste manier om verschillende RL‑algoritmen te begrijpen. Voor productiegebruik zijn er tools zoals Stable Baselines3, RLib en CleanRL. Deze tools bevatten kant‑en‑klare deployments van veelvoorkomende RL‑algoritmen, die je moet configureren en fijnafstellen afhankelijk van de omgeving.

