OpenAI Gym (devenu Gymnasium)
OpenAI Gym est la librairie Python qui a défini l’API standard pour les environnements de reinforcement learning. Créée par OpenAI en 2016, elle est maintenue depuis 2022 par la Farama Foundation sous le nom Gymnasium, et reste la brique fondamentale sur laquelle repose l’ensemble de l’écosystème RL.
Gym n’est pas un algorithme d’apprentissage. Ce n’est pas non plus un simulateur physique. C’est une interface : un contrat qui définit comment un agent communique avec un environnement. Trois méthodes suffisent : reset() pour initialiser un épisode, step(action) pour agir et recevoir la récompense, et render() pour visualiser. Cette simplicité a fait son succès universel.
Plus de 18 millions de téléchargements depuis la sortie de Gymnasium en novembre 2023, plus d’un million par mois en 2025, et cité dans plus de 4 500 publications scientifiques : c’est de loin la librairie RL la plus utilisée au monde. Quasiment toutes les implémentations d’algorithmes RL (Stable-Baselines3, RLlib, CleanRL) supposent cette interface par défaut.
- Nom actuel
- Gymnasium (fork maintenu de OpenAI Gym)
- Mainteneur
- Farama Foundation (depuis 2022)
- Version stable
- Gymnasium v1.1.x v1.0 GA
- Licence
- MIT
- Python
- 3.10, 3.11, 3.12, 3.13
- Installation
pip install gymnasium- URL
- gymnasium.farama.org
De Gym à Gymnasium : une histoire en trois actes
Acte 1 : la création par OpenAI (2016)
OpenAI Gym a été publié en avril 2016 par OpenAI, quelques mois après la fondation de l’entreprise. L’objectif était de fournir un benchmark standardisé pour comparer les algorithmes de RL. Avant Gym, chaque chercheur implémentait ses propres environnements avec ses propres interfaces, rendant la reproduction des résultats quasi impossible.
Gym a résolu ce problème en proposant une API minimaliste (reset/step/render), un ensemble d’environnements de référence (CartPole, MountainCar, Atari, MuJoCo), et un mécanisme de versioning strict (chaque environnement porte un suffixe comme -v0, -v1) pour garantir la reproductibilité.
Le succès a été immédiat. En quelques mois, Gym est devenu le standard de facto du RL. Quand DeepMind, Berkeley ou Stanford publiaient un nouvel algorithme, c’est sur les environnements Gym qu’ils le testaient.
Acte 2 : l’abandon progressif (2020-2021)
Gym n’a jamais été une priorité commerciale pour OpenAI. Après la période initiale de développement actif, les ressources allouées ont diminué progressivement. Fin 2020, la librairie était essentiellement non maintenue : les bugs s’accumulaient, les pull requests restaient sans réponse, et l’API n’évoluait plus.
Début 2021, OpenAI a transféré le contrôle du dépôt GitHub à une équipe externe qui maintenait déjà PettingZoo (la version multi-agents de Gym). Cette équipe a réalisé plus de développement en quelques mois que pendant les cinq années précédentes.
Acte 3 : Gymnasium et la Farama Foundation (2022-présent)
En octobre 2022, la Farama Foundation a officiellement annoncé Gymnasium, un fork maintenu de Gym. L’objectif : héberger l’API standard du RL dans une entité neutre et pérenne, plutôt que dans une entreprise dont le coeur de métier est ailleurs.
La migration est triviale : remplacer import gym par import gymnasium as gym. Gymnasium 0.26.2 était identique à Gym 0.26.2. Depuis, l’équipe a publié des dizaines de versions avec des améliorations significatives, culminant avec la sortie de Gymnasium v1.0 (GA), qui stabilise définitivement l’API centrale (Env, Space, VectorEnv). OpenAI n’a plus mis à jour Gym depuis octobre 2022.
pip install gym. Le paquet gym sur PyPI n’est plus maintenu et contient des bugs non corrigés. Utilisez pip install gymnasium. Si vous dépendez de code legacy qui utilise l’ancien Gym, la librairie Shimmy (Farama) fournit des wrappers de compatibilité pour convertir les environnements Gym v21 et v26 en Gymnasium.
L’API Gymnasium en détail
La boucle fondamentale
L’API de Gymnasium modélise l’interaction agent-environnement sous forme d’une boucle simple. L’environnement est un objet Python avec deux méthodes principales :
import gymnasium as gym
# Créer un environnement
env = gym.make("CartPole-v1", render_mode="human")
# Boucle d'interaction standard
observation, info = env.reset(seed=42)
for _ in range(1000):
action = env.action_space.sample() # Agent aléatoire
observation, reward, terminated, truncated, info = env.step(action)
if terminated or truncated:
observation, info = env.reset()
env.close()
Chaque appel à step(action) retourne cinq valeurs :
observation : ce que l’agent perçoit de l’environnement (position, vitesse, pixels, etc.).
reward : la récompense numérique pour cette action.
terminated : True si l’épisode est terminé naturellement (le poteau est tombé, l’agent a atteint le but).
truncated : True si l’épisode est interrompu artificiellement (limite de temps atteinte).
info : un dictionnaire avec des métadonnées supplémentaires.
terminated et truncated est l’un des changements les plus importants de Gymnasium par rapport à l’ancien Gym (qui n’avait qu’un seul booléen done). La différence est cruciale pour le calcul correct de la valeur bootstrap en RL : quand l’épisode est tronqué (truncated), l’agent doit estimer la valeur future car la tâche n’est pas vraiment finie. Quand il est terminé (terminated), la valeur future est zéro. Confondre les deux provoque des bugs subtils dans l’entraînement.
Les espaces (Spaces)
Chaque environnement déclare deux espaces : observation_space (ce que l’agent peut voir) et action_space (ce que l’agent peut faire). Gymnasium fournit plusieurs types d’espaces :
Discrete(n) : n choix entiers (0, 1, …, n-1). Utilisé pour les actions discrètes (gauche/droite, actions dans un jeu).
Box(low, high, shape) : vecteur continu borné. Utilisé pour les observations numériques (positions, vitesses) et les actions continues (couple moteur, angle de direction).
MultiBinary(n) : vecteur de n bits. Utile quand plusieurs actions binaires sont simultanées.
MultiDiscrete([n1, n2, ...]) : plusieurs variables discrètes indépendantes.
Dict({...}) et Tuple((...,)) : espaces composites pour des observations structurées (ex. : image + vecteur de capteurs).
Les espaces servent à la validation (vérifier qu’une action est légale), à l’échantillonnage (action_space.sample() pour les politiques aléatoires), et au dimensionnement automatique des réseaux de neurones dans les librairies RL.
Les wrappers
Les wrappers sont des couches qui modifient le comportement d’un environnement sans toucher à son code source. C’est le pattern « décorateur » appliqué au RL. Gymnasium fournit des dizaines de wrappers prêts à l’emploi :
import gymnasium as gym
from gymnasium.wrappers import (
TimeLimit,
ClipReward,
GrayscaleObservation,
ResizeObservation,
RecordVideo,
NormalizeObservation,
NormalizeReward,
)
env = gym.make("ALE/Breakout-v5")
env = GrayscaleObservation(env) # Image en niveaux de gris
env = ResizeObservation(env, shape=(84, 84)) # Redimensionner à 84x84
env = ClipReward(env, min_reward=-1, max_reward=1) # Clipper la récompense
env = RecordVideo(env, "videos/") # Enregistrer des vidéos
Les wrappers les plus utilisés incluent NormalizeObservation et NormalizeReward (normalisation running pour stabiliser l’entraînement), TimeLimit (tronquer les épisodes trop longs), FrameStack (empiler plusieurs frames pour les jeux Atari), et RecordEpisodeStatistics (logger les métriques d’épisode).
Environnements vectorisés
Pour accélérer l’entraînement, Gymnasium permet d’exécuter plusieurs instances d’un environnement en parallèle via l’API vectorisée :
import gymnasium as gym
# Créer 8 environnements en parallèle
envs = gym.make_vec("CartPole-v1", num_envs=8, vectorization_mode="async")
observations, infos = envs.reset()
for _ in range(1000):
actions = envs.action_space.sample() # 8 actions simultanées
observations, rewards, terminateds, truncateds, infos = envs.step(actions)
envs.close()
Gymnasium v1.0 a introduit make_vec() avec trois modes de vectorisation : "sync" (séquentiel, simple et fiable), "async" (multiprocessing, plus rapide), et un mode personnalisé ("vector_entry_point") pour les environnements qui implémentent leur propre parallélisation native.
La v1.1 a ajouté le support de trois modes d’autoreset (next-step, same-step, disabled) pour contrôler comment les sous-environnements sont réinitialisés quand ils terminent un épisode, un détail technique qui affecte le calcul correct des retours en RL.
Les familles d’environnements
Classic Control
Les environnements de contrôle classique sont les « Hello World » du RL. Ils sont légers (pas de dépendance externe lourde), rapides (milliers d’épisodes par seconde), et illustrent les concepts fondamentaux. Les plus utilisés :
CartPole-v1 : un chariot se déplace horizontalement pour équilibrer un pendule inversé. Espace d’observation : position/vitesse du chariot + angle/vitesse angulaire du pendule (4 dimensions continues). Espace d’action : pousser à gauche ou à droite (discret, 2 choix). Objectif : maintenir le pendule droit le plus longtemps possible. Récompense : +1 par pas de temps. Épisode terminé si le pendule dépasse 12° ou le chariot sort du cadre.
MountainCar-v0 : une voiture dans une vallée doit prendre assez d’élan pour atteindre le sommet. Illustre le problème des récompenses sparse (la seule récompense est d’atteindre le haut) et la nécessité de reculer pour mieux sauter (l’action « recule » semble contre-productive mais est nécessaire).
LunarLander-v3 : piloter un module lunaire pour atterrir en douceur sur une plateforme. Plus complexe, avec un espace d’action continu ou discret et des récompenses denses (bonus pour approche douce, pénalité pour crash). Nécessite la librairie Box2D (pip install "gymnasium[box2d]").
Atari (ALE)
L’Atari Learning Environment intègre plus de 50 jeux Atari 2600 dans Gymnasium. C’est le benchmark historique du deep RL, depuis le papier fondateur de DQN (Mnih et al., 2015) qui a montré qu’un réseau de neurones pouvait apprendre à jouer à Pong, Breakout et Space Invaders à partir des pixels bruts.
Installation : pip install "gymnasium[atari,accept-rom-license]". L’espace d’observation est une image 210×160 RGB (ou les 128 bytes de RAM Atari). L’espace d’action dépend du jeu (typiquement 4 à 18 actions discrètes).
Les wrappers standards pour Atari incluent le frameskipping (répéter la même action sur 4 frames), le grayscaling, le resize à 84×84, et le stacking de 4 frames consécutives pour donner une notion de mouvement à l’agent.
MuJoCo
Les environnements MuJoCo sont le benchmark standard pour le RL en contrôle continu. Ils simulent des robots articulés avec des dynamiques réalistes : Ant (fourmi quadrupède), HalfCheetah (guépard bipède), Humanoid (humanoïde complet), Walker2d (marcheur bipède), Hopper (sauteur monopode).
Installation : pip install "gymnasium[mujoco]" (MuJoCo est inclus, gratuit depuis 2022). L’espace d’observation contient les positions et vitesses articulaires. L’espace d’action est continu (couples moteurs). Ces environnements sont le terrain de jeu des algorithmes comme PPO, SAC, et TD3.
Environnements tiers
L’écosystème Gymnasium s’étend bien au-delà des environnements intégrés. Des centaines d’environnements tiers respectent l’API Gymnasium :
Isaac Lab (NVIDIA) : robotique haute fidélité avec simulation GPU. MiniGrid (Farama) : gridworlds procéduraux pour le RL multi-tâches. Highway-env : conduite autonome simplifiée. Minigrid/BabyAI : suivi d’instructions en langage naturel. Procgen : jeux procéduraux pour tester la généralisation. dm_control (DeepMind) : suite de contrôle continu basée sur MuJoCo (compatible via Shimmy).
L’écosystème Farama
La Farama Foundation maintient un ensemble cohérent de librairies autour de Gymnasium :
| Librairie | Fonction | Installation |
|---|---|---|
| Gymnasium | API standard, environnements single-agent | pip install gymnasium |
| PettingZoo | API multi-agents (coopératif, compétitif, mixte) | pip install pettingzoo |
| Gymnasium-Robotics | Envs de manipulation robotique (Fetch, Shadow Hand) | pip install gymnasium-robotics |
| MiniGrid | Gridworlds procéduraux minimalistes | pip install minigrid |
| Shimmy | Wrappers de compatibilité (Gym v21/v26, dm_control, etc.) | pip install shimmy |
| MO-Gymnasium | Environnements multi-objectifs | pip install mo-gymnasium |
Intégration avec les frameworks RL
Stable-Baselines3
Stable-Baselines3 (SB3) est la librairie RL la plus utilisée pour l’entraînement de politiques. Elle prend nativement les environnements Gymnasium :
from stable_baselines3 import PPO
from stable_baselines3.common.env_util import make_vec_env
from stable_baselines3.common.evaluation import evaluate_policy
# Créer 4 environnements vectorisés
env = make_vec_env("CartPole-v1", n_envs=4)
# Entraîner un agent PPO
model = PPO("MlpPolicy", env, verbose=1)
model.learn(total_timesteps=100_000)
# Évaluer
mean_reward, std_reward = evaluate_policy(model, env, n_eval_episodes=10)
print(f"Reward moyen : {mean_reward:.2f} ± {std_reward:.2f}")
# Sauvegarder et charger
model.save("ppo_cartpole")
loaded_model = PPO.load("ppo_cartpole")
SB3 supporte PPO, A2C, DQN, SAC, TD3, et d’autres algorithmes, tous compatibles avec n’importe quel environnement Gymnasium.
RLlib (Ray)
RLlib est le framework RL distribué de référence pour les déploiements à grande échelle. Il peut entraîner des agents sur des clusters de machines avec des dizaines de GPU. L’intégration Gymnasium est automatique :
from ray.rllib.algorithms.ppo import PPOConfig
config = (
PPOConfig()
.environment("CartPole-v1")
.training(lr=0.0003, train_batch_size=4000)
.env_runners(num_env_runners=4)
)
algo = config.build()
result = algo.train()
print(f"Reward moyen : {result['env_runners']['episode_reward_mean']:.2f}")
CleanRL
CleanRL adopte une philosophie différente : chaque algorithme est un fichier Python unique et lisible, sans abstraction opaque. C’est l’outil idéal pour l’apprentissage et la compréhension des algorithmes RL. Tous les scripts utilisent Gymnasium nativement.
Créer un environnement personnalisé
La force de Gymnasium est qu’il est trivial de créer son propre environnement compatible avec tout l’écosystème RL :
import numpy as np
import gymnasium as gym
from gymnasium import spaces
class TradingEnv(gym.Env):
"""Environnement de trading simplifié."""
metadata = {"render_modes": ["human"]}
def __init__(self, prices, initial_balance=10000):
super().__init__()
self.prices = prices
self.initial_balance = initial_balance
# Actions : 0=hold, 1=buy, 2=sell
self.action_space = spaces.Discrete(3)
# Observation : [balance_norm, position, price_norm, returns_5j]
self.observation_space = spaces.Box(
low=-np.inf, high=np.inf, shape=(4,), dtype=np.float32
)
def reset(self, seed=None, options=None):
super().reset(seed=seed)
self.balance = self.initial_balance
self.position = 0 # Nombre d'actions détenues
self.current_step = 5 # Commence après 5 jours (pour le calcul des returns)
return self._get_obs(), {}
def _get_obs(self):
price = self.prices[self.current_step]
returns_5j = (price - self.prices[self.current_step - 5]) / self.prices[self.current_step - 5]
portfolio_value = self.balance + self.position * price
return np.array([
self.balance / self.initial_balance,
self.position,
price / self.prices[0],
returns_5j,
], dtype=np.float32)
def step(self, action):
price = self.prices[self.current_step]
if action == 1 and self.balance >= price: # Buy
self.position += 1
self.balance -= price
elif action == 2 and self.position > 0: # Sell
self.position -= 1
self.balance += price
self.current_step += 1
terminated = self.current_step >= len(self.prices) - 1
portfolio = self.balance + self.position * self.prices[self.current_step]
reward = (portfolio - self.initial_balance) / self.initial_balance
return self._get_obs(), reward, terminated, False, {"portfolio": portfolio}
# Utilisation
prices = np.cumsum(np.random.randn(252) * 2 + 0.05) + 100
env = TradingEnv(prices)
obs, info = env.reset()
for _ in range(200):
action = env.action_space.sample()
obs, reward, terminated, truncated, info = env.step(action)
if terminated:
break
print(f"Valeur finale du portfolio : {info['portfolio']:.2f}€")
Cet environnement est immédiatement utilisable avec SB3, RLlib, ou n’importe quel algorithme RL compatible Gymnasium. C’est la puissance de l’interface standard : vous définissez votre problème une seule fois, puis vous testez tous les algorithmes que vous voulez.
gym.make("MonEnv-v0"), enregistrez-le : gym.register(id="TradingEnv-v0", entry_point="mon_module:TradingEnv"). Incrémentez le numéro de version à chaque changement qui affecte les résultats d’entraînement.
Migration de Gym vers Gymnasium
Si vous maintenez du code basé sur l’ancien OpenAI Gym, la migration est directe dans la plupart des cas :
Étape 1 : Remplacer import gym par import gymnasium as gym.
Étape 2 : Mettre à jour le déballage de step() : l’ancien obs, reward, done, info = env.step(action) devient obs, reward, terminated, truncated, info = env.step(action). Remplacer if done: par if terminated or truncated:.
Étape 3 : Mettre à jour reset() : l’ancien obs = env.reset() devient obs, info = env.reset().
Étape 4 : Le render_mode se spécifie à la création (gym.make("Env-v0", render_mode="human")) et non plus via un appel séparé à render().
Pour les environnements tiers qui n’ont pas été migrés, Shimmy fournit des wrappers de compatibilité : env = gym.make("GymV26Environment-v0", env_id="OldEnv-v1").
Bonnes pratiques
Reproductibilité : toujours passer un seed à reset() et à action_space.seed() pour des résultats reproductibles. Les environnements Gymnasium utilisent des générateurs NumPy internes qui sont correctement seedés.
Versioning : ne jamais comparer des résultats obtenus sur des versions différentes d’un environnement. CartPole-v0 et CartPole-v1 ont des paramètres différents (durée d’épisode, seuil de récompense). Un agent entraîné sur l’un peut échouer sur l’autre.
Normalisation : pour les algorithmes de policy gradient, normaliser les observations et les récompenses (via les wrappers NormalizeObservation et NormalizeReward) améliore significativement la stabilité et la vitesse de convergence.
Vectorisation : pour les algorithmes on-policy comme PPO et A2C, utiliser des environnements vectorisés est presque obligatoire. Le nombre d’environnements parallèles (typiquement 4 à 64) est un hyperparamètre important qui affecte la variance de l’estimation du gradient.
Questions fréquentes sur OpenAI Gym / Gymnasium
Quelle est la différence entre OpenAI Gym et Gymnasium ?
Gymnasium est le successeur maintenu d’OpenAI Gym. C’est un fork créé par la Farama Foundation en octobre 2022, après qu’OpenAI a cessé de maintenir Gym. L’API de base est la même (reset/step/render), mais Gymnasium apporte des correctifs, de nouvelles fonctionnalités (distinction terminated/truncated, environnements vectorisés améliorés, wrappers modernisés) et un développement actif. En pratique, utilisez toujours Gymnasium (pip install gymnasium), jamais Gym.
Quel environnement utiliser pour débuter en RL ?
CartPole-v1 est le point d’entrée universel. Il est simple (4 observations, 2 actions), rapide (aucune dépendance externe), et résolvable par des algorithmes basiques en quelques minutes. Ensuite, LunarLander-v3 ajoute de la complexité (8 observations, 4 actions, récompenses denses). Pour passer au contrôle continu, HalfCheetah-v5 (MuJoCo) est le benchmark standard. Pour la perception visuelle, les jeux Atari (Breakout, Pong) restent incontournables.
Comment utiliser Gymnasium avec des GPU ?
Gymnasium lui-même tourne sur CPU. L’accélération GPU intervient à deux niveaux. Premier niveau : les algorithmes RL (PPO, DQN, SAC) utilisent PyTorch ou JAX sur GPU pour l’entraînement des réseaux de neurones, via des librairies comme Stable-Baselines3 ou CleanRL. Second niveau : pour la simulation physique GPU (milliers d’environnements en parallèle), Isaac Lab (NVIDIA) fournit des environnements compatibles Gymnasium qui tournent entièrement sur GPU via PhysX ou Newton.
Gymnasium fonctionne-t-il avec les LLM et les agents IA ?
L’API Gymnasium est conçue pour le RL classique (boucle step/reset avec récompenses numériques), mais elle s’adapte aux agents IA modernes. Des projets comme WebArena et OSWorld définissent des environnements Gymnasium-compatibles pour les agents qui interagissent avec des navigateurs web ou des systèmes d’exploitation. L’espace d’observation peut contenir du texte ou des screenshots, et l’espace d’action peut être des commandes en langage naturel. L’interface reste la même : reset, step, reward.
Gymnasium est-il adapté à la production ou uniquement à la recherche ?
Gymnasium est avant tout un standard de recherche et de développement. Pour la production, l’environnement Gymnasium sert généralement d’interface d’entraînement : vous entraînez votre agent en simulation via l’API Gymnasium, puis vous déployez la politique apprise (le réseau de neurones) dans le système réel sans Gymnasium. Des plateformes comme HUD et Isaac Sim fournissent des environnements Gymnasium-compatibles qui se rapprochent davantage des conditions de production. L’API elle-même est suffisamment légère pour être intégrée dans des pipelines industriels.