# Dependances pre-provisionnees (stable-baselines3[extra] gymnasium moviepy) : voir RL/requirements.txt ; imports ci-dessous.
# Filtrer les UserWarning de stable_baselines3 (GPU advisory + Monitor wrapper) qui fuitaient le chemin site-packages du worker.
import warnings
warnings.filterwarnings("ignore", message=r"You are trying to run.*on the GPU.*")
warnings.filterwarnings("ignore", message=r"Evaluation environment is not wrapped.*")
import os
import numpy as np
import gymnasium as gym
from stable_baselines3 import PPO, A2C, SAC, TD3
from stable_baselines3.common.vec_env import DummyVecEnv, SubprocVecEnv
from stable_baselines3.common.evaluation import evaluate_policy
from stable_baselines3.common.monitor import MonitorNavigation : Index | << RL-1 Intro | RL-3 HER >> # Notebook 2 – Wrappers Gym, Sauvegarde/Chargement, Multiprocessing, Callbacks et Environnements Personnalisés
Serie : Reinforcement Learning | Notebook : 2/13 | Duree estimee : 35-40 min
Ce notebook propose un survol des fonctionnalités avancées de la librairie Stable Baselines3 : 1. Utilisation de wrappers Gym (limitation du nombre d’étapes, normalisation des actions, etc.) 2. Sauvegarde et chargement de modèles 3. Multiprocessing et environnements vectorisés 4. Callbacks : enregistrement automatique, traçage en temps réel, etc. 5. Création d’un environnement Gym personnalisé
Nous utilisons un environnement sous Windows, donc nous évitons certaines dépendances (xvfb, freeglut3-dev) et nous n’utilisons pas de commandes apt-get.
Installation et imports essentiels
Dans un environnement Python classique, on installera Stable Baselines3 (et les dépendances gym) via :
pip install stable-baselines3[extra]
ou bien :
%pip install "stable-baselines3[extra]>=2.0.0a4"
si vous utilisez un notebook.
Ensuite, on importe les principales classes dont on aura besoin.
1) Wrappers Gym
Les Gym wrappers permettent d’ajouter des transformations aux environnements (limiter la durée d’un épisode, normaliser les actions, etc.). Ci-dessous un exemple très condensé :
Autres wrappers utiles
- Monitor: Enregistre automatiquement la récompense et la durée de chaque épisode, ce qui facilite l’analyse.
- ClipAction: S’assure que l’action est bien bornée à [low, high].
- FlattenObservation: Convertit une observation complexe (dict, tuple, etc.) en un simple vecteur Numpy.
Exemple :
import gymnasium as gym
from stable_baselines3.common.monitor import Monitor
env = gym.make('CartPole-v1')
env = Monitor(env) # suivi auto des rewards, durées d’épisodesimport gymnasium as gym
from gymnasium import spaces
class LimitEpisodeSteps(gym.Wrapper):
def __init__(self, env, max_steps=100):
super().__init__(env)
self.max_steps = max_steps
self.current_step = 0
def reset(self, **kwargs):
self.current_step = 0
return self.env.reset(**kwargs)
def step(self, action):
obs, reward, terminated, truncated, info = self.env.step(action)
self.current_step += 1
if self.current_step >= self.max_steps:
truncated = True
return obs, reward, terminated, truncated, info
# Exemple d'utilisation :
base_env = gym.make("CartPole-v1", render_mode="rgb_array")
wrapped_env = LimitEpisodeSteps(base_env, max_steps=50)
obs, _ = wrapped_env.reset()
done = False
while not done:
action = wrapped_env.action_space.sample()
obs, reward, terminated, truncated, _ = wrapped_env.step(action)
done = terminated or truncated
print("Classe LimitEpisodeSteps definie : limite les episodes a N etapes")Classe LimitEpisodeSteps definie : limite les episodes a N etapes
Lecture du wrapper — ce que LimitEpisodeSteps change vraiment. La sortie Classe LimitEpisodeSteps definie : limite les episodes a N etapes acte la definition ; la source precise le mecanisme. Le wrapper est instancie avec max_steps=50 sur un CartPole-v1 qui autorise 500 pas : la boucle de demonstration (actions aleatoires) est coupee a 50. Le geste cle est dans step() — quand le compteur interne atteint la limite, le wrapper force truncated = True et ne touche jamais terminated : fin par contrainte de temps, pas par fin de tache. C’est exactement la distinction terminated/truncated que la section 5, plus bas, formalisera pour les environnements personnalises ; ce wrapper la met en oeuvre de facon visible.
2) Sauvegarde et chargement de modèles
Chaque algorithme de Stable-Baselines3 dispose de méthodes .save(path) et .load(path). On peut ainsi conserver un modèle partiellement entraîné ou final, et le recharger pour continuer l’apprentissage ou faire de l’inférence.
# Entraînement basique sur CartPole
env = gym.make("CartPole-v1")
model = PPO("MlpPolicy", env, verbose=0)
model.learn(5000)
# Sauvegarde
model.save("ppo_cartpole")
del model # on supprime le modèle de la mémoire
# Rechargement
model = PPO.load("ppo_cartpole", env=env) # on précise l'env si on veut continuer
# Test rapide
mean_reward, std_reward = evaluate_policy(model, env, n_eval_episodes=10)
print(f"Reprise du modèle chargé : récompense moyenne={mean_reward:.2f}")Reprise du modèle chargé : récompense moyenne=210.00
Lecture chiffree — le round-trip sauvegarde/chargement. Reprise du modèle chargé : récompense moyenne=210.00. Les trois gestes de la source se lisent dans cet unique nombre : model.save("ppo_cartpole") ecrit les poids, del model vide la memoire, PPO.load("ppo_cartpole") reconstruit — le 210.00 ne peut donc PAS venir d’un modele residant en RAM, il sort du disque. Le niveau lui-meme se lit comme l’observation d’un run non seede : sur ce run, 5000 pas de PPO sur CartPole donnent une moyenne de 210 sur 10 episodes d’evaluation, environ 42 % du plafond de 500 — de quoi demontrer la reprise sur un modele encore loin du plafond ; la variabilite de ce niveau d’une execution a l’autre n’est pas mesurable sur un seul run, elle exigerait de repeter l’entrainement. L’encart Attention ci-dessous complete le contrat : .save() ne porte que les poids, et PPO n’a pas de replay buffer a sauvegarder, contrairement aux algos off-policy cites.
Attention
- model.save(path) enregistre uniquement les poids du réseau et l’architecture.
- Pour off-policy (DQN, SAC, TD3…), si vous voulez sauvegarder la replay buffer (mémoire d’expériences), il faut utiliser en plus model.save_replay_buffer(path_replay).
- Cela peut s’avérer lourd en mémoire : prenez garde à la taille de buffer_size et à l’espace disque.
3) Multiprocessing
Pour accélérer l’apprentissage ou pour avoir une meilleure exploration, on peut exécuter plusieurs environnements en parallèle. Cela se fait via DummyVecEnv (qui reste sur un seul process) ou SubprocVecEnv (plusieurs processus). Souvent, DummyVecEnv est plus rapide pour un petit nombre d’environnements, car la communication inter-processus coûte cher.
On définit une fonction make_env(env_id, rank, seed=0) qui crée un environnement, puis on construit un SubprocVecEnv (ou un DummyVecEnv) :
def make_env(env_id, rank, seed=0):
def _init():
env = gym.make(env_id)
env.reset(seed=seed + rank)
return env
return _init
from stable_baselines3.common.utils import set_random_seed
# Exemple : 4 environnements en parallèle
n_procs = 4
env_id = "CartPole-v1"
vec_env = SubprocVecEnv([make_env(env_id, i) for i in range(n_procs)])
model_mp = A2C("MlpPolicy", vec_env, verbose=0)
model_mp.learn(5000)
# Évaluation finale sur un seul env
test_env = gym.make(env_id)
mean_reward, _ = evaluate_policy(model_mp, test_env, n_eval_episodes=10)
print("Récompense moyenne sur 10 épisodes:", mean_reward)Récompense moyenne sur 10 épisodes: 465.1
Lecture chiffree — le score du multiprocessing, et une comparaison non controlee. Récompense moyenne sur 10 épisodes: 465.1, soit 93 % du plafond de 500 de CartPole-v1 — avec le meme budget total de 5000 pas que le PPO mono-environnement ci-dessus (210.00). Attention a ce que cet ecart peut et ne peut pas dire : la comparaison change PLUSIEURS choses a la fois — l’algorithme (A2C ici, PPO la) ET la structure (SubprocVecEnv avec n_procs = 4, les 5000 pas etant collectes au total sur 4 environnements, environ 1250 chacun). Un run contre un run, non seedes de bout en bout, n’isole ni ne hierarchise ces causes ; mesurer la variabilite de chaque configuration exigerait des repetitions sur plusieurs seeds. Le detail de source reste acquis : env.reset(seed=seed + rank) donne a chaque processus une graine differente (0, 1, 2, 3) — sans cela, les 4 environnements reproduiraient la meme experience depuis le meme etat initial.
4) Callbacks
Les callbacks permettent d’intervenir pendant l’entraînement (pour sauvegarder, tracer en temps réel, etc.). Ils héritent de BaseCallback. Quelques exemples :
Callbacks fournis par Stable-Baselines3
- EvalCallback: évalue régulièrement le modèle sur un environnement de test (distinct de l’env d’entraînement).
- CheckpointCallback: sauvegarde périodiquement le modèle.
- StopTrainingOnRewardThreshold: arrête l’apprentissage si une récompense cible est atteinte.
Tip : En combinant EvalCallback et CheckpointCallback, vous pouvez automatiquement enregistrer le “meilleur” modèle selon une métrique d’évaluation.
from stable_baselines3.common.callbacks import BaseCallback
class SimpleCallback(BaseCallback):
def __init__(self, verbose=0):
super().__init__(verbose)
self._called_once = False
def _on_step(self) -> bool:
if not self._called_once:
print("Callback: Première fois !")
self._called_once = True
return True
print("Callback: Deuxième fois, on arrête l'entraînement.")
return False # on interrompt l'apprentissage
# Exemple d'utilisation
model_cb = SAC("MlpPolicy", "Pendulum-v1", verbose=0)
model_cb.learn(total_timesteps=2000, callback=SimpleCallback())Callback: Première fois !
Callback: Deuxième fois, on arrête l'entraînement.
<stable_baselines3.sac.sac.SAC at 0x1cdad585160>
Lecture chiffree — le contrat du retour booleen. Deux lignes : Callback: Première fois ! puis Callback: Deuxième fois, on arrête l'entraînement. La source montre le mecanisme : _on_step() renvoie True au premier appel, False au second — et ce retour False est le signal d’interruption de learn(). Les 2000 pas demandes sont donc abandonnes au deuxieme appel, quasi immediatement. La ligne finale, l’affichage <stable_baselines3.sac.sac.SAC at 0x...>, est la valeur de retour de model_cb.learn(...) : l’entrainement ne s’est pas plante, il est rentre proprement avec le modele. C’est tout le contrat d’un callback SB3 : intervenir a chaque pas, decider de la suite.
Exemple de callback pour sauvegarder le meilleur modèle
On peut observer la récompense d’entraînement (monitor) et sauvegarder le modèle lorsqu’on obtient une récompense moyenne record. (Pour un usage plus robuste, on conseille d’utiliser un environnement d’évaluation séparé.)
import numpy as np
from stable_baselines3.common.results_plotter import load_results, ts2xy
class SaveOnBestTrainingRewardCallback(BaseCallback):
def __init__(self, check_freq, log_dir, verbose=1):
super().__init__(verbose)
self.check_freq = check_freq
self.log_dir = log_dir
self.save_path = os.path.join(log_dir, "best_model")
self.best_mean_reward = -np.inf
def _init_callback(self) -> None:
os.makedirs(self.save_path, exist_ok=True)
def _on_step(self) -> bool:
if self.n_calls % self.check_freq == 0:
x, y = ts2xy(load_results(self.log_dir), "timesteps")
if len(x) > 0:
mean_reward = np.mean(y[-100:])
if self.verbose > 0:
print(f"Timestep: {self.num_timesteps}")
print(
f"Meilleur reward: {self.best_mean_reward:.2f} | Derniers 100 épisodes: {mean_reward:.2f}"
)
if mean_reward > self.best_mean_reward:
self.best_mean_reward = mean_reward
if self.verbose > 0:
print("Nouveau meilleur modèle! Sauvegarde...")
self.model.save(self.save_path)
return True
# Exemple d'utilisation
log_dir = "./logs/" # dossier de logs
os.makedirs(log_dir, exist_ok=True)
env = gym.make("CartPole-v1")
env = Monitor(env, log_dir)
model_saver = A2C("MlpPolicy", env, verbose=0)
callback_saver = SaveOnBestTrainingRewardCallback(check_freq=1000, log_dir=log_dir)
model_saver.learn(total_timesteps=5000, callback=callback_saver)Timestep: 1000
Meilleur reward: -inf | Derniers 100 épisodes: 33.45
Nouveau meilleur modèle! Sauvegarde...
Timestep: 2000
Meilleur reward: 33.45 | Derniers 100 épisodes: 29.57
Timestep: 3000
Meilleur reward: 33.45 | Derniers 100 épisodes: 26.80
Timestep: 4000
Meilleur reward: 33.45 | Derniers 100 épisodes: 24.48
Timestep: 5000
Meilleur reward: 33.45 | Derniers 100 épisodes: 26.28
<stable_baselines3.a2c.a2c.A2C at 0x1cdb2d1fc50>
Lecture chiffree — le meilleur modele, au fil des checkpoints. Cinq lignes, une seule sauvegarde. Premier controle (Timestep: 1000) : Meilleur reward: -inf | Derniers 100 épisodes: 33.45 suivi de Nouveau meilleur modèle! Sauvegarde... — le -inf initial est battu, c’est l’unique save du run. Les quatre controles suivants affichent 29.57, 26.80, 24.48 puis 26.28 : jamais au-dessus de 33.45, donc jamais re-sauvegarde. Trois lectures. (1) Le cablage : le callback ne lit pas le modele mais les fichiers ecrits par Monitor(env, log_dir) — ts2xy(load_results(...)) reconstitue la courbe par timesteps, et check_freq=1000 cadre exactement les cinq controles d’un run de 5000 pas. (2) La metrique est la moyenne des (au plus) 100 derniers episodes journalises — bruyante en debut d’entrainement. (3) Le contrepoint : sur ce run non seede, l’A2C mono-environnement oscille entre 24 et 30 apres un premier checkpoint a 33.45, la ou le PPO de la section 2 (meme budget, meme structure mono-environnement) avait affiche 210.00 — une juxtaposition qui change aussi l’algorithme, donc non concluante par elle-meme. Et le “meilleur” 33.45 n’est que le premier point d’une serie decroissante sur ce run : dire s’il releve du bruit de la metrique ou d’une dynamique d’apprentissage instable, un run unique ne le peut pas — il faudrait repeter sur plusieurs seeds.
5) Créer un environnement Gym personnalisé
Enfin, voici un exemple minimal d’environnement Gym personnalisé. Il faut définir :
__init__: définitself.observation_spaceetself.action_space.
reset(): renvoie(obs, info)oùobs∈observation_space.
step(action): renvoie(obs, reward, terminated, truncated, info).
- Assurez-vous que
obsrespecte la forme indiquée parobservation_space.
Note : Dans Gym 0.26+ et Gymnasium, on a deux indicateurs de fin : terminated et truncated.
- terminated: la tâche est terminée parce qu’on est allé au bout (victoire/défaite).
- truncated: la tâche s’arrête par limite de temps ou autre contrainte.
from gymnasium import spaces
class MyCustomEnv(gym.Env):
def __init__(self, grid_size=5):
super().__init__()
self.grid_size = grid_size
# On définit l'action_space et l'observation_space
self.action_space = spaces.Discrete(2) # ex: 0 = gauche, 1 = droite
self.observation_space = spaces.Box(low=0, high=self.grid_size, shape=(1,), dtype=np.float32)
self.agent_pos = None
def reset(self, seed=None, options=None):
super().reset(seed=seed, options=options)
self.agent_pos = np.random.randint(low=0, high=self.grid_size)
return np.array([self.agent_pos], dtype=np.float32), {}
def step(self, action):
if action == 0: # gauche
self.agent_pos -= 1
else: # droite
self.agent_pos += 1
self.agent_pos = np.clip(self.agent_pos, 0, self.grid_size)
reward = 1.0 if self.agent_pos == 0 else 0.0 # ex : on favorise d'aller à 0
terminated = bool(self.agent_pos == 0)
truncated = False
info = {}
return np.array([self.agent_pos], dtype=np.float32), reward, terminated, truncated, info
def render(self):
pass # Optionnel
def close(self):
pass
# Validation
from stable_baselines3.common.env_checker import check_env
env_custom = MyCustomEnv()
check_env(env_custom, warn=True)
# Test rapide
model_custom = PPO("MlpPolicy", env_custom, verbose=0)
model_custom.learn(2000)
mean_reward, _ = evaluate_policy(model_custom, env_custom, n_eval_episodes=10)
print("Récompense moyenne :", mean_reward)Récompense moyenne : 1.0
Lecture chiffree — 1.0, score parfait sur l’environnement minimal. Récompense moyenne : 1.0 sur 10 episodes d’evaluation : chaque episode atteint la position 0. La source explique la facilite — recompense 1.0 et terminated partagent la meme condition (agent_pos == 0), deux actions seulement (gauche/droite), une grille de 5 positions : l’environnement est presque trivial, et c’est voulu. Ce que la cellule verifie n’est pas la difficulte mais la plomberie : check_env(env_custom, warn=True) n’a rien leve (aucune erreur affichee — espaces, signatures reset/step et types d’observation respectent le contrat Gymnasium), et le PPO de 2000 pas resout la tache. L’exercice 3, plus bas, demandera le vrai test : un GridWorld ou recompense et terminaison se decouplent.
Exercices
Les exercices suivants approfondissent les concepts de wrappers, callbacks et environnements personnalises abordes dans ce notebook.
Exercice 1 : Wrapper de normalisation des observations
Un wrapper permet de transformer les observations avant qu’elles ne soient vues par l’agent. L’objectif est d’implementer un wrapper qui normalise les observations en utilisant la moyenne et l’ecart type glissants (running mean/std).
Indice : Heritez de gym.Wrapper. Maintenez un buffer circulaire ou des accumulateurs pour running_mean et running_std. Normalisez l’observation dans step() et reset() en soustrayant la moyenne et divisant par l’ecart type (+ epsilon pour eviter la division par zero).
# Exercice 1 : Wrapper de normalisation des observations
# TODO etudiant : Implementez un wrapper qui normalise les observations (running mean/std)
# Indice : class NormalizeObsWrapper(gym.Wrapper):
# Indice : Utilisez np.mean() et np.std() sur un historique d'observations
# Etape 1 : Definir la classe avec __init__, reset et step
# Etape 2 : Accumuler les observations dans un buffer
# Etape 3 : Normaliser chaque observation avant de la retourner
# class NormalizeObsWrapper(gym.Wrapper):
# def __init__(self, env, buffer_size=1000):
# ...
# def _normalize(self, obs):
# ...
# def reset(self, **kwargs):
# ...
# def step(self, action):
# ...
print("Exercice a completer : wrapper de normalisation des observations")Exercice a completer : wrapper de normalisation des observations
Lecture du stub — exercice 1, normalisation des observations. La sortie Exercice a completer : wrapper de normalisation des observations pose le contrat. L’effet attendu : l’agent ne voit plus l’observation brute mais une observation centree-reduite, moyenne glissante soustraite, ecart type glissant (plus epsilon) au denominateur — l’epsilon gardant la division definie au demarrage, quand l’ecart type est encore nul. Ou cela mord : les reseaux de valeur de PPO/A2C apprennent plus vite sur des entrees d’echelles comparables ; la version production de ce pattern existe dans SB3 (VecNormalize, au niveau VecEnv, qui normalise aussi les recompenses). La question de validation, une fois la cellule completee : a budget de pas egal, moyenne et dispersion du CartPole normalise font-elles mieux que celles du CartPole brut — en repetant l’entrainement sur plusieurs seeds, un run unique ne suffisant pas a trancher ?
Exercice 2 : Callback d’arret premature (early stopping)
Il est souvent utile d’arreter l’entrainement automatiquement quand l’agent atteint un niveau de performance satisfaisant. L’objectif est de créer un callback qui arrete l’entrainement quand la recompense depasse un seuil pendant N evaluations consecutives.
Indice : Heritez de BaseCallback. Dans _on_step(), evaluez le modèle periodiquement (tous les check_freq pas). Si la recompense moyenne depasse reward_threshold pendant patience evaluations consecutives, retournez False pour arreter l’entrainement.
# Exercice 2 : Callback d'arret premature (early stopping)
# TODO etudiant : Creez un callback qui arrete l'entrainement quand reward > seuil pendant N evals
# Indice : class EarlyStoppingCallback(BaseCallback):
# Indice : Utilisez evaluate_policy dans _on_step pour verifier la performance
# Etape 1 : Definir __init__ avec reward_threshold, patience, check_freq, eval_env
# Etape 2 : Dans _on_step, evaluer periodiquement et compter les evaluations reussies
# Etape 3 : Retourner False si le compteur >= patience
# class EarlyStoppingCallback(BaseCallback):
# def __init__(self, eval_env, reward_threshold=400, patience=3, check_freq=1000, verbose=1):
# ...
# def _on_step(self) -> bool:
# ...
print("Exercice a completer : callback d'arret premature")Exercice a completer : callback d'arret premature
Lecture du stub — exercice 2, arret premature. Exercice a completer : callback d'arret premature : l’exercice assemble deux primitives deja demontrees plus haut. La detection est celle du callback de sauvegarde (controle periodique tous les check_freq pas, moyenne sur les derniers episodes) ; l’action est celle du SimpleCallback (renvoyer False pour couper learn()). La nouveaute est la patience : il faut le seuil depasse pendant N evaluations consecutives — N d’affilee, pas une seule — pour arreter. Le conseil donne plus haut s’applique : evaluer coute des episodes, d’ou l’environnement d’evaluation separe recommande en section 4.
Exercice 3 : Environnement GridWorld personnalise
Créez un environnement Gymnasium complet ou un agent doit atteindre une case objectif sur une grille 5x5. L’agent peut se deplacer dans 4 directions (haut, bas, gauche, droite). L’episode se termine quand l’agent atteint l’objectif ou depasse un nombre maximal de pas.
Indice : Definissez action_space = spaces.Discrete(4) (0=haut, 1=bas, 2=gauche, 3=droite) et observation_space = spaces.Box(low=0, high=4, shape=(2,), dtype=np.int32) pour la position (ligne, colonne). Recompense positive a l’objectif, petite penalite a chaque pas. Validez avec check_env.
# Exercice 3 : Environnement GridWorld personnalise
# TODO etudiant : Implementez un environnement 5x5 ou l'agent doit atteindre un objectif
# Indice : Definir __init__, reset, step, render
# Indice : action_space = spaces.Discrete(4) # 0=haut, 1=bas, 2=gauche, 3=droite
# Indice : observation_space = spaces.Box(low=0, high=4, shape=(2,), dtype=np.int32)
# Etape 1 : Definir la classe GridWorldEnv(gym.Env) avec __init__
# Etape 2 : Implementez reset() pour placer l'agent et l'objectif aleatoirement
# Etape 3 : Implementez step(action) avec gestion des murs et detection de l'objectif
# Etape 4 : Valider avec check_env et entrainer un agent PPO
# class GridWorldEnv(gym.Env):
# def __init__(self, grid_size=5, max_steps=50):
# ...
# def reset(self, seed=None, options=None):
# ...
# def step(self, action):
# ...
print("Exercice a completer : environnement GridWorld personnalise")Exercice a completer : environnement GridWorld personnalise
Lecture du stub — exercice 3, le GridWorld complet. Exercice a completer : environnement GridWorld personnalise. L’enonce fixe le squelette : action_space = spaces.Discrete(4) (haut/bas/gauche/droite), observation_space = spaces.Box(low=0, high=4, shape=(2,), dtype=np.int32) pour la position (ligne, colonne), recompense positive a l’objectif, petite penalite a chaque pas, admission par check_env. La decision de design qui n’est PAS dans l’enonce : quoi renvoyer quand l’agent atteint l’objectif (terminated) et quoi renvoyer a la limite de pas (truncated) — exactement la distinction que le wrapper LimitEpisodeSteps de la section 1 forcait a la main et que la section 5 a formalisee. La penalite par pas est ce qui decouple recompense et terminaison : contrairement au MyCustomEnv au score 1.0, finir ne suffira plus — finir VITE rapportera.
Conclusion
Dans ce second notebook, nous avons parcouru :
- L’usage de wrappers Gym pour modifier un environnement (limiter la durée, normaliser, etc.).
- Les fonctions de sauvegarde/chargement de modèles (
.save()/.load()). - Le multiprocessing via
SubprocVecEnvouDummyVecEnvpour accélérer (ou diversifier) l’apprentissage. - Les callbacks, permettant d’intervenir pendant l’entraînement (sauvegarde automatique du meilleur modèle, monitoring, etc.).
- La création d’un environnement Gym personnalisé, validé ensuite par la fonction
check_envet compatible avec tout algorithme Stable-Baselines3.
Vous pouvez maintenant adapter et combiner ces techniques pour vos propres projets d’Apprentissage par Renforcement !
Retour au sommaire : Index RL