cours
Démarrer avec TorchRL pour l'apprentissage par renforcement profond
L'apprentissage par renforcement (RL) est utilisé pour résoudre de nombreux problèmes complexes, qu'il s'agisse de la formation de voitures auto-conduites ou de la formation de grands modèles de langage (LLM) pour donner des réponses semblables à celles des humains.
Les agents RL sont entraînés à réagir en fonction du retour d'information humain, en utilisant l'apprentissage par renforcement à partir du retour d'information humain (RLHF). Bien que les frameworks basés sur Python comme Keras et Tensorflow soient utilisés dans les applications d'apprentissage profond des entreprises, la plupart des nouveaux projets sont désormais basés sur PyTorch et PyTorch Lightning.
TorchRL est une bibliothèque open-source permettant de construire des solutions RL à l'aide de PyTorch. Dans ce tutoriel, je vous montrerai comment configurer TorchRL, comprendre ses composants sous-jacents et l'utiliser pour construire un agent RL simple. Nous discuterons également de l'utilisation de TorchRL pour implémenter des versions pré-construites d'algorithmes RL tels que l'Optimisation de la Politique Proximale (PPO). Enfin, nous aborderons les principes de base de la journalisation et de la surveillance des agents RL.
Qu'est-ce que TorchRL et pourquoi l'utiliser ?
Les algorithmes RL sont souvent complexes. Vous devez créer le(s) agent(s), calculer les rendements et les pertes, définir les passes avant et arrière et évaluer les performances de l'agent.
TorchRL regroupe de nombreuses fonctions RL couramment utilisées dans des modules auxquels vous pouvez accéder directement. Cela facilite la mise en œuvre et l'expérimentation de divers algorithmes pour résoudre des problèmes pratiques. Il facilite également la création de nouveaux algorithmes, car les chercheurs ont accès au reste de l'écosystème RL sans avoir à le créer eux-mêmes.
TorchRL est livré avec de nombreux modules pré-intégrés qui rendent le développement de RL plus efficace. Par exemple :
- Environnements : TorchRL fournit une API normalisée permettant d'importer et d'utiliser des environnements RL provenant de diverses sources, notamment Gymnasium, Jumanji, RoboHive et d'autresre. Dans de nombreux cas, il est nécessaire de personnaliser la sortie de l'environnement pour répondre à des besoins de formation spécifiques. TorchRL comprend des modules pour diverses transformations de l'environnement à l'aide d'un seul appel de fonction avec les paramètres souhaités.
- Collecteurs de données et tampons de relecture : De nombreux algorithmes de formation RL impliquent la collecte de données sur les interactions de l'agent avec l'environnement - l'action de l'agent, la récompense qu'il a reçue et l'état suivant dans lequel il s'est retrouvé. TorchRL comprend des paquets avec les structures de données pour collecter et échantillonner ces informations.
- Fonctions objectives : La méthodologie de base d'un algorithme RL est mise en œuvre dans sa fonction objective. TorchRL intègre des algorithmes RL courants tels que DQN (Deep Q Networks), A2C (Advantage Actor-Critic), PPO, et bien d'autres encore, dans des modules préconstruits que vous pouvez directement invoquer et utiliser pour former l'agent.
Compte tenu des fonctionnalités susmentionnées, TorchRL s'est avéré utile pour rationaliser et simplifier la construction de solutions RL pour divers cas d'utilisation, tels que
- Robotique : Le robot doit être entraîné à naviguer avec succès dans un environnement complexe. Il est pénalisé s'il trébuche ou s'il ne parvient pas à naviguer. En utilisant des méthodes d'apprentissage RL, il apprend les bonnes actions à effectuer pour naviguer avec succès dans un environnement tel qu'une surface naturelle irrégulière.
- Jeu AI : Dans les jeux vidéo et les jeux de console, les joueurs informatisés doivent concevoir et improviser leurs mouvements en fonction des actions du joueur humain. RL, avec des récompenses et des pénalités, est utilisé pour entraîner ces joueurs à choisir les bons coups à jouer contre l'humain.
- Systèmes autonomes : Les voitures autonomes doivent naviguer de manière indépendante dans un environnement complexe (comme la circulation routière) et atteindre l'objectif (la destination) sans aucun accident. La RL est utilisée pour entraîner les systèmes autonomes à imiter le comportement d'un conducteur humain dans diverses conditions réelles.
Développer des applications d'IA
Configuration de TorchRL
Dans cette section, je vais vous montrer comment installer et démarrer avec TorchRL.
Conditions préalables
Vous avez besoin de quelques logiciels dépendants avant d'installer et d'utiliser TorchRL :
- PyTorch : TorchRL est basé sur PyTorch, vous en avez donc besoin comme prérequis.
- Gymnase : Vous navez besoin du paquet Gymnasium pour importer des environnements RL. Depuis janvier 2025, la dernière version de Gymnasium n'est pas compatible avec TorchRL, comme expliqué sur cette page Git Discussions. Installez donc l'ancienne version
0.29.1
. - PyGame : Il s'agit d'un paquet Python pour les jeux vidéo. TorchRL en a besoin pour simuler des environnements RL de type jeu, comme CartPole.
- TensorDict : L'utilisation d'une structure de données de type dictionnaire pour stocker les entrées et les sorties des réseaux neuronaux facilite le travail avec les tenseurs dans TorchRL. TensorDict est un conteneur de tenseurs qui stocke les tenseurs sous forme de paires clé-valeur.
Installez les paquets prérequis :
!pip install torch tensordict gymnasium==0.29.1 pygame
Installation de TorchRL
Installez TorchRL en utilisant pip
. Je recommande vivement d'installer ces paquets dans un environnement Conda si vous travaillez sur un ordinateur personnel ou un serveur.
!pip install torchrl
Vérification de l'installation
Après l'installation, vérifiez que TorchRL a bien été installé. Essayez d'importer torchrl
dans un shell (ou un notebook) Python. Utilisez la méthode check_env_specs()
pour vérifier qu'un environnement standard (tel que CartPole) correspond aux spécifications de torchrl
:
import torchrl
from torchrl.envs import GymEnv
from torchrl.envs.utils import check_env_specs
check_env_specs(GymEnv("CartPole-v1"))
La sortie doit indiquer que l'environnement a été créé avec succès et qu'il fonctionne avec TorchRL.
[torchrl][INFO] check_env_specs succeeded!
Composants clés de TorchRL
Avant de créer votre premier agent RL, examinons les principaux éléments constitutifs de TorchRL.
Environnements
TorchRL fournit une API uniforme pour s'interfacer avec différents environnements. Pour ce faire, les fonctionnalités spécifiques à l'environnement sont enveloppées dans un ensemble standard de classes et de fonctions d'enveloppement. Vous passez les paramètres appropriés au wrapper, et il fait correspondre en interne votre commande à l'appel de fonction correspondant à l'environnement spécifique. En particulier :
- TorchRL convertit les états de l'environnement (observations), les actions et les récompenses en objets tensoriels PyTorch, qui peuvent être directement utilisés par les modules qui mettent en œuvre les algorithmes RL.
- Il permet d'appliquer des étapes de prétraitement et de post-traitement, par exemple pour normaliser et mettre à l'échelle les tenseurs d'entrée ou pour présenter les tenseurs de sortie dans un format spécifique.
Par exemple, pour créer un environnement à partir de Gymnasium, utilisez le module GymEnv
:
env = GymEnv("CartPole-v1")
Transformations
Il est courant d'étendre l'environnement de base avec des fonctionnalités et des transformations supplémentaires que vous auriez dû mettre en œuvre vous-même. Par exemple, vous pouvez ajouter un module de compteur de pas à l'environnement au lieu de coder le compteur vous-même. Le compteur d'étapes comptabilise le nombre d'étapes de chaque épisode. Le module transformedEnv
y contribue :
from torchrl.envs import GymEnv, StepCounter, TransformedEnv
env = TransformedEnv(GymEnv("CartPole-v1"), StepCounter())
De même, la normalisation des tenseurs avant de les traiter est une étape de prétraitement courante. Une transformation de normalisation, utilisant le module ObservationNorm
, normalise les tenseurs. La documentation de la fonction TransformedEnv aborde différents types de transformations.
Vous pouvez également combiner plusieurs transformations à l'aide du paramètre compose()
:
base_env = GymEnv('CartPole-v1', device=device)
env = TransformedEnv(
base_env,
Compose(
ObservationNorm(in_keys=["observation"]),
StepCounter()
)
)
Agents et politiques
Dans le RL, l'agent décide de ses actions en utilisant la politique et en se basant sur l'état observé de l'environnement. L'objectif de l'agent est de maximiser les récompenses cumulées de l'environnement. Il reçoit des récompenses lorsqu'il choisit la bonne action (comme s'arrêter à un feu rouge).
Par exemple, dans une voiture auto-conduite, c'est l'agent qui conduit la voiture. Ses décisions (comme diriger la voiture dans une direction donnée) sont basées sur ses observations de l'état de l'environnement (trafic, position de la voiture, etc.) et sur sa politique (éviter les piétons et autres obstacles, s'arrêter aux feux rouges, etc.)
La politique la plus simple consiste à choisir une action au hasard. L'acteur choisit au hasard l'une des actions dans l'espace des actions possibles. Une politique aléatoire est parfois utilisée pour générer un ensemble initial de données d'interactions avant de commencer à former le modèle.
Utilisez le module RandomPolicy
pour créer une politique aléatoire. Cette politique aléatoire accepte un paramètre action_spec
qui spécifie l'espace d'action. Dans l'exemple ci-dessous, l'espace d'action est constitué de nombres (continus) compris entre -1 et +1. Ainsi, la politique aléatoire choisit une action représentée par un nombre aléatoire compris entre -1 et +1.
import torchrl
import torch
from tensordict import TensorDict
from torchrl.data.tensor_specs import Bounded
action_spec = Bounded(-torch.ones(1), torch.ones(1))
actor = torchrl.envs.utils.RandomPolicy(action_spec=action_spec)
td = actor(TensorDict({}, batch_size=[]))
print(td.get("action"))
Le résultat devrait être un tenseur, comme indiqué ci-dessous :
tensor([0.9258])
Vérifiez que la politique est bien aléatoire en relançant l'acteur :
td = actor(TensorDict({}, batch_size=[]))
print(td.get("action"))
Il devrait produire un tenseur aléatoire différent.
Si vous avez besoin d'une introduction aux concepts de l'apprentissage par renforcement, consultez le cursus Reinforcement Learning in Python sur DataCamp !
Créez votre premier agent RL avec TorchRL
Dans cette section, je vous montre comment implémenter un agent simple d'apprentissage par renforcement en utilisant TorchRL.
Avant de commencer, importez les paquets de logiciels prérequis dans Python :
time
pour mesurer le temps nécessaire à la formation de l'agent.GymEnv
,StepCounter
, etTransformedEnv
pour travailler dans des environnements de gymnase.MLP
pour créer un simple réseau neuronal MLP (perceptron multicouche).EGreedyModule
pour trouver un équilibre entre l'exploration de l'environnement et l'exploitation de la politique la plus connue.QValueModule
etDQNLoss
pour mettre en œuvre l'algorithme Deep Q-Learning.SoftUpdate
pour mettre à jour le réseau neuronal.SyncDataCollector
pour collecter des données sur les interactions de l'agent.ReplayBuffer
pour stocker les données issues des interactions de l'agent.Adam
pour la rétropropagation.matplotlib
pour afficher visuellement la progression de la formation.torchrl_logger
pour enregistrer la session de formation.
import time
import matplotlib.pyplot as plt
from torchrl.envs import GymEnv, StepCounter, TransformedEnv
from tensordict.nn import TensorDictModule as TensorDict, TensorDictSequential as Seq
from torchrl.modules import EGreedyModule, MLP, QValueModule
from torchrl.objectives import DQNLoss, SoftUpdate
from torchrl.collectors import SyncDataCollector
from torchrl.data import LazyTensorStorage, ReplayBuffer
from torch.optim import Adam
from torchrl._utils import logger as torchrl_logger
Étape 1 : Définir l'environnement
Dans cet exemple, nous résolvons l'environnement CartPole. Importez cet environnement à partir de Gymnasium, ainsi qu'un compteur de pas pour suivre le nombre d'étapes de l'entraînement :
env = TransformedEnv(GymEnv("CartPole-v1"), StepCounter())
Ensemencez les environnements Python et RL afin de reproduire des résultats similaires d'une session de formation à l'autre.
torch.manual_seed(0)
env = TransformedEnv(GymEnv("CartPole-v1"), StepCounter())
env.set_seed(0)
Définissez les paramètres et les hyperparamètres pour la formation :
INIT_RAND_STEPS
: Le nombre d'étapes pour lesquelles l'agent agit au hasard avant d'utiliser la politique. Ces premières étapes servent à collecter des données initiales pour commencer à former la politique.FRAMES_PER_BATCH
: Le nombre de points de données (un pour chaque interaction ou étape temporelle) dans un lot de formation.OPTIM_STEPS
: Nombre de pas pour lesquels il faut accumuler les pertes avant d'effectuer une passe en sens inverse.EPS_0
: La valeur initiale d'epsilon, le coefficient d'exploration.BUFFER_LEN
: La taille du tampon de relecture.ALPHA
: Le taux d'apprentissage.TARGET_UPDATE_EPS
: Le facteur de décroissance pour la mise à jour du réseau cible using le module soft-update.REPLAY_BUFFER_SAMPLE
: La taille de l'échantillon aléatoire à prélever dans le tampon de relecture à chaque itération d'apprentissage. Le tampon de relecture stocke les résultats des interactions de l'agent avec l'environnement à chaque étape.LOG_EVERY
: Le nombre d'étapes après lesquelles imprimer la progression de l'entraînement.MLP_SIZE
: La taille du réseau neuronal.
INIT_RAND_STEPS = 5000
FRAMES_PER_BATCH = 100
OPTIM_STEPS = 10
EPS_0 = 0.5
BUFFER_LEN = 100_000
ALPHA = 0.05
TARGET_UPDATE_EPS = 0.95
REPLAY_BUFFER_SAMPLE = 128
LOG_EVERY = 1000
MLP_SIZE = 64
Étape 2 : Créer la politique
Définissez un réseau neuronal simple pour mettre en œuvre la politique :
- Définissez le MLP (réseau neuronal). Compte tenu d'une observation, le MLP produit la valeur de l'action, ce qui revient à faire le travail de la fonction Q.
- Définissez un dictionnaire de tenseurs en utilisant le module
TensorDict
sur le MLP ci-dessus. Ce dictionnaire associe les observations de l'état de l'environnement (clés du dictionnaire) aux valeurs de probabilité d'action (valeurs du dictionnaire) correspondant à cet état. - Utilisez le module QValueModule pour implementer la fonction Q. Étant donné un tenseur contenant des valeurs d'action, il renvoie l'action correspondant à la valeur d'action la plus élevée. Il met en œuvre la stratégie gourmande (exploitation).
- Combinez (à l'aide dumodule TensorDictSequential) le dictionnaire tensoriel du MLP et le site
QValueModule
pour définir la politique.
value_mlp = MLP(out_features=env.action_spec.shape[-1], num_cells=[MLP_SIZE, MLP_SIZE])
value_net = TensorDict(value_mlp, in_keys=["observation"], out_keys=["action_value"])
policy = Seq(value_net, QValueModule(spec=env.action_spec))
- Définissez la fonction d'exploration à l'aide du module EGreedy, qui prend en entrée l'espace d'action de l'environnement, la longueur du tampon de relecture et le coefficient d'exploration, epsilon. Enchaînez (à l'aide du module TensorDictSequential ) cette fonction d'exploration avec la politique définie ci-dessus pour obtenir la politique finale :
exploration_module = EGreedyModule(
env.action_spec, annealing_num_steps=BUFFER_LEN, eps_init=EPS_0
)
policy_explore = Seq(policy, exploration_module)
Étape 3 : Former l'agent
La première étape de la formation de l'agent consiste à collecter les données relatives aux interactions de l'agent avec l'environnement. Utilisez le collecteur de données SyncDataCollector pour construire un collecteur qui exécute la politique et collecte les résultats des interactions de l'agent :
collector = SyncDataCollector(
env,
policy_explore,
frames_per_batch=FRAMES_PER_BATCH,
total_frames=-1,
init_random_frames=INIT_RAND_STEPS,
)
Créez un tampon de relecture pour stocker les résultats des interactions :
rb = ReplayBuffer(storage=LazyTensorStorage(BUFFER_LEN))
Vous devez également déclarer des modules spécifiques à la formation, tels que la fonction de perte (pour utiliser le calcul de perte basé sur le DQN), l'optimiseur (l'algorithme d'Adam traditionnel) et les fonctions d'actualisation (pour mettre à jour le réseau neuronal). Ils sont tous basés sur des modules TorchRL prédéfinis :
loss = DQNLoss(value_network=policy, action_space=env.action_spec, delay_value=True)
optim = Adam(loss.parameters(), lr=ALPHA)
updater = SoftUpdate(loss, eps=TARGET_UPDATE_EPS)
Initialiser les curseurs permettant de suivre le nombre total d'étapes et d'épisodes, les étapes réussies par épisode et le temps d'exécution :
total_count = 0
total_episodes = 0
t0 = time.time()
success_steps = []
La fonction d'apprentissage consiste en 2 boucles for
:
- La boucle supérieure exécute la politique et ajoute les résultats des interactions de l'agent au tampon de relecture.
- La boucle intérieure divise les échantillons d'apprentissage en lots. Il traite chaque lot comme suit :
- Choisissez un échantillon aléatoire dans la mémoire tampon de relecture.
- Calculez les pertes à l'aide de la fonction de perte.
- Lancez l'optimiseur et le programme de mise à jour.
- Mettez à jour les compteurs.
Chaque étape consiste à appeler des modules TorchRL préconstruits sans avoir à coder quoi que ce soit à partir de zéro. Le code ci-dessous montre comment mettre en œuvre ces étapes :
for i, data in enumerate(collector):
rb.extend(data)
max_length = rb[:]["next", "step_count"].max()
if len(rb) > INIT_RAND_STEPS:
for _ in range(OPTIM_STEPS):
sample = rb.sample(REPLAY_BUFFER_SAMPLE)
loss_vals = loss(sample)
loss_vals["loss"].backward()
optim.step()
optim.zero_grad()
# Update exploration factor
exploration_module.step(data.numel())
# Update target params
updater.step()
total_count += data.numel()
total_episodes += data["next", "done"].sum()
success_steps.append(max_length)
Étape 4 : Évaluer l'agent
La boucle de la section précédente entraîne continuellement la politique. Nous devons définir les critères d'évaluation des performances et décider à quel moment la formation doit être considérée comme réussie. Nous voulons également publier les progrès de la formation.
Nous imprimons la progression de la formation à intervalles réguliers à l'aide de l'enregistreur TorchRL :
if total_count > 0 and total_count % LOG_EVERY == 0:
torchrl_logger.info(f"Successful steps in the last episode: {max_length}, rb length {len(rb)}, Number of episodes: {total_episodes}")
Nous utilisons le nombre maximum d'étapes réalisées par l'agent dans le dernier épisode pour déterminer si la formation est réussie. L'environnement CartPole-v1 plafonne le nombre maximum d'étapes et la récompense totale par épisode à 500. Il est classique de considérer qu'une politique est couronnée de succès si elle permet de franchir plus de 475 étapes :
if max_length > 475:
print("TRAINING COMPLETE")
break
Les deux extraits de code ci-dessus doivent être ajoutés à la fin de la boucle d'apprentissage (présentée plus haut). L'extrait suivant montre la boucle d'apprentissage avec le code d'évaluation de l'agent :
for i, data in enumerate(collector):
# Write data in replay buffer
rb.extend(data)
max_length = rb[:]["next", "step_count"].max()
if len(rb) > INIT_RAND_STEPS:
for _ in range(OPTIM_STEPS):
sample = rb.sample(REPLAY_BUFFER_SAMPLE)
loss_vals = loss(sample)
loss_vals["loss"].backward()
optim.step()
optim.zero_grad()
# Update exploration factor
exploration_module.step(data.numel())
# Update target params
updater.step()
total_count += data.numel()
total_episodes += data["next", "done"].sum()
success_steps.append(max_length)
if total_count > 0 and total_count % LOG_EVERY == 0:
torchrl_logger.info(f"Successful steps in the last episode: {max_length}, rb length {len(rb)}, Number of episodes: {total_episodes}")
if max_length > 475:
print("TRAINING COMPLETE")
break
Enfin, après la formation et l'évaluation, imprimez la durée totale de la formation et tracez la progression de la formation :
t1 = time.time()
torchrl_logger.info(
f"solved after {total_count} steps, {total_episodes} episodes and in {t1-t0}s."
)
def plot_steps():
plt.plot(success_steps)
plt.title('Successful steps over training episodes')
plt.xlabel('Training episodes')
plt.ylabel('Steps')
plt.show()
plot_steps()
Vous pouvez trouver et exécuter le code complet pour mettre en œuvre le DQN en utilisant TorchRL dans ce classeur DataLab.
Dans cette section, nous avons construit et formé un agent RL à l'aide de l'algorithme DQN simple. Dans la section suivante, nous verrons comment utiliser les modules TorchRL préconstruits pour implémenter un algorithme plus complexe comme le PPO.
Explorer les algorithmes préconstruits dans TorchRL
Comme indiqué dans les sections précédentes, TorchRL est livré avec quelques algorithmes prédéfinis. Examinons-les et leur fonctionnement.
Algorithmes pris en charge
TorchRL comprend des modules préconstruits pour de nombreux algorithmes courants d'apprentissage par renforcement profond, tels que :
- Réseaux Q profonds (DQN)
- Gradient de politique déterministe profond (DDPG)
- Acteur-critique doux (SAC)
- Apprentissage aléatoire ensemblé à double Q (REDQ)
- CrossQ
- Apprentissage implicite du Q (IQL)
- Apprentissage continu (CQL)
- Apprentissage par imitation générative et contradictoire (GAIL)
- Transformateur de décision (DT)
- DDPG à double retard (TD3)
- Critique acteur-avantage (A2C)
- Optimisation de la politique proximale (PPO)
- REINFORCE
- et plus
Cela permet d'expérimenter efficacement différents types d'algorithmes et d'étudier les performances de chacun d'entre eux pour résoudre un problème donné.
Exemple : PPO dans TorchRL
L'optimisation de la politique proximale utilise une fonction objective de substitution écrêtée pour obtenir un processus de formation en douceur qui équilibre l'exploration et l'exploitation.
Dans cette section, je vais vous montrer comment utiliser le module PPO préconstruit dans TorchRL. Comme pour l'implémentation précédente, importez les modules prérequis. En plus des modules (tels que ReplayBuffer
, SyncDataCollector
, etc.) nécessaires pour l'implémentation précédente, vous avez besoin de quelques modules supplémentaires pour l'OPP :
- ProbabilisticActor, pour choisir une action de manière stochastique. Le choix stochastique de l'action (au lieu de toujours suivre la politique et de maximiser la récompense) facilite l'exploration de l'environnement et la découverte de chemins plus optimaux au cours de la formation.
- OneHotCategorical, pour générer un encodage à un instant du tenseur représentant les logarithmes des probabilités des actions.
- ValueOperator, pour construire un module TorchRL basé sur le réseau neuronal qui implémente la fonction de valeur.
- GAE, pour mettre en œuvre l'estimation de l'avantage généralisé. L'OPP utilise une fonction d'avantage comme substitut de la fonction de valeur. Le module de valeur (ci-dessus) est une entrée du GAE.
- ClipPPOLoss, pour construire la fonction objective écrêtée pour la mise en œuvre de l'OPP.
import torch
from torch import nn
from torchrl.envs import Compose, ObservationNorm, DoubleToFloat, StepCounter, TransformedEnv
from torchrl.envs.libs.gym import GymEnv
from torchrl.envs.utils import check_env_specs
from torchrl.modules import ProbabilisticActor, OneHotCategorical, ValueOperator
from torchrl.collectors import SyncDataCollector
from torchrl.data.replay_buffers import ReplayBuffer
from torchrl.data.replay_buffers.storages import LazyTensorStorage
from torchrl.data.replay_buffers.samplers import SamplerWithoutReplacement
from torchrl.objectives.value import GAE
from torchrl.objectives import ClipPPOLoss
from tensordict.nn import TensorDictModule
Déclarez les paramètres et les hyperparamètres pour la formation :
FRAMES_PER_BATCH
: Le nombre d'images (pas de temps) dans chaque lot de données résultant des interactions de l'agent avec l'environnement.SUB_BATCH_SIZE
: Le nombre de pas de temps dans chaque sous-lot. Dans la formation PPO, chaque lot est divisé en sous-lots.TOTAL_FRAMES
: Le nombre total de pas de temps pour lesquels la formation doit être exécutée.GAMMA
: Le facteur d'actualisation pour actualiser la valeur de la récompense à partir de pas de temps futurs.CLIP_EPSILON
: Cela définit la zone de confiance dans laquelle la politique peut être modifiée à chaque itération de formation ultérieure. Elle est mise en œuvre en écrêtant la politique actualisée de manière à ce que le rapport entre les nouvelles et les anciennes probabilités se situe dans une certaine limite.ALPHA
: Le taux d'apprentissage.ENTROPY_EPS
: Cet hyperparamètre contrôle le rapport entre l'exploration et l'exploitation.OPTIM_STEPS
: Le nombre de fois où l'optimiseur doit être exécuté sur chaque sous-lot de données.LOG_EVERY
: Nombre d'étapes après lesquelles la politique doit être évaluée et les récompenses imprimées.
FRAMES_PER_BATCH = 1024
TOTAL_FRAMES = 1048576
GAMMA = 0.99
LAMBDA = 0.95
CLIP_EPSILON = 0.2
ALPHA = 1e-4
ENTROPY_EPS = 5e-4
SUB_BATCH_SIZE = 64
OPTIM_STEPS = 8
LOG_EVERY = 16
Importez l'environnement de base CartPole depuis Gymnasium :
device="cpu"
base_env = GymEnv('CartPole-v1', device=device)
Déclarez l'environnement TorchRL en important l'environnement de base et en ajoutant des modules pour normaliser les tenseurs d'observation et compter le nombre d'étapes :
env = TransformedEnv(
base_env,
Compose(
ObservationNorm(in_keys=["observation"]),
DoubleToFloat(),
StepCounter()
)
)
Initialiser l'environnement et ensemencer les générateurs de nombres aléatoires :
env.transform[0].init_stats(1024)
torch.manual_seed(0)
env.set_seed(0)
check_env_specs(env)
Déclarez que l'acteur est un réseau neuronal avec 1 couche cachée et 16 poids. Il prend en entrée les observations de l'environnement et fournit en sortie la probabilité de chaque action dans l'espace d'action.
actor_net = nn.Sequential(
nn.Linear(env.observation_spec["observation"].shape[-1], 32, device=device),
nn.ReLU(),
nn.Linear(32, 32, device=device),
nn.ReLU(),
nn.Linear(32, env.action_spec.shape[-1], device=device),
nn.ReLU()
)
Créez un dictionnaire tensoriel (basé sur le réseau neuronal ci-dessus) avec des clés et des valeurs associant les états aux probabilités d'action.
actor_module = TensorDictModule(actor_net, in_keys=["observation"], out_keys=["logits"])
Pour l'apprentissage du PPO (et de nombreux autres algorithmes RL), vous ne choisissez pas toujours l'action qui conduit à la récompense la plus élevée à l'étape suivante. Le fait d'avoir un certain degré d'aléa dans le choix de l'action permet à l'agent d'explorer l'environnement et de découvrir de meilleurs chemins qui peuvent conduire à des rendements plus élevés à long terme. Créez un acteur probabiliste pour ce faire :
actor = ProbabilisticActor(
module = actor_module,
spec = env.action_spec,
in_keys = ["logits"],
distribution_class = OneHotCategorical,
return_log_prob = True
)
Créez le réseau pour mettre en œuvre la fonction de valeur. Ce réseau a 16 poids. Il prend en entrée l'état de l'environnement (observation) et produit la valeur attendue de cet état.
value_net = nn.Sequential(
nn.Linear(env.observation_spec["observation"].shape[-1], 16, device=device),
nn.ReLU(),
nn.Linear(16, 1, device=device),
nn.ReLU()
)
Créez un module TorchRL enveloppant la fonction de valeur (implémentée ci-dessus) à l'aide de ValueOperator()
. Ce module s'interface avec d'autres composants de TorchRL.
value_module = ValueOperator(
module = value_net,
in_keys = ["observation"]
)
Créez le tampon de relecture pour stocker les résultats des interactions de l'agent avec l'environnement :
replay_buffer = ReplayBuffer(
storage = LazyTensorStorage(max_size=FRAMES_PER_BATCH),
sampler = SamplerWithoutReplacement()
)
Créez un collecteur de données pour exécuter la politique sur l'environnement et recueillir les résultats des interactions de l'agent avec l'environnement à chaque pas de temps (trame) :
collector = SyncDataCollector(
env,
actor,
frames_per_batch = FRAMES_PER_BATCH,
total_frames = TOTAL_FRAMES,
split_trajs = True,
reset_at_each_iter = True,
device=device
)
Utilisez le module GAE
pour mettre en œuvre la fonction d'avantage pour l'OPP. La fonction d'avantage est basée sur la fonction de valeur.
advantage_module = GAE(
gamma = GAMMA,
lmbda = GAMMA,
value_network = value_module,
average_gae = True
)
Utilisez le module intégré ClipPPOLoss
pour mettre en œuvre la fonction de perte conformément à l'algorithme PPO :
loss_module = ClipPPOLoss(
actor_network = actor,
critic_network = value_module,
clip_epsilon = CLIP_EPSILON,
entropy_bonus = bool(ENTROPY_EPS),
entropy_coef = ENTROPY_EPS
)
Déclarez l'optimiseur Adam :
optim = torch.optim.Adam(loss_module.parameters(), lr=ALPHA)
Créez un planificateur pour réduire progressivement le taux d'apprentissage au fur et à mesure que la formation progresse :
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optim, TOTAL_FRAMES // FRAMES_PER_BATCH)
Construisez la boucle de formation en utilisant les composants créés ci-dessus. La fonction de formation consiste en trois boucles for
:
- La boucle extérieure parcourt les données recueillies lors des interactions de l'agent avec l'environnement. Le paramètre
TOTAL_FRAMES
détermine le nombre de pas de temps nécessaires à l'exécution de l'agent . - La boucle centrale effectue les opérations suivantes :
- Il exécute la boucle intérieure pendant un nombre fixe d'itérations (généralement entre 5 et 10), défini par l' hyperparamètre
OPTIM_STEPS
. - Il met à jour le taux d'apprentissage après chaque itération de formation.
- Il calcule également la valeur de la fonction d'avantage pour chaque pas de temps.
- Évaluez périodiquement la politique et imprimez les récompenses.
- La boucle la plus proche exécute la boucle d'apprentissage :
- Échantillonnez un lot de données d'entraînement à partir de la mémoire tampon de relecture.
- Calculez la perte à l'aide du module de perte.
- Exécutez la rétro-propagation sur la perte.
- Utilisez l'optimiseur pour effectuer la descente de gradient.
Le code ci-dessous met en œuvre la boucle d'apprentissage :
for i, tensordict_data in enumerate(collector):
for _ in range(OPTIM_STEPS):
advantage_module(tensordict_data)
replay_buffer.extend(tensordict_data.reshape(-1).cpu())
for _ in range(FRAMES_PER_BATCH // SUB_BATCH_SIZE):
data = replay_buffer.sample(SUB_BATCH_SIZE)
loss = loss_module(data.to(device))
loss_value = loss["loss_objective"] + loss["loss_critic"] + loss["loss_entropy"]
loss_value.backward()
optim.step()
optim.zero_grad()
scheduler.step()
if i % LOG_EVERY == 0:
with torch.no_grad():
rollout = env.rollout(FRAMES_PER_BATCH, actor)
reward_eval = rollout["next","reward"].sum()
#print(rollout["next","reward"].sum())
print(reward_eval)
rewards.append(reward_eval)
del rollout
Ce classeur DataLab contient le code (comme indiqué ci-dessus) pour former un agent RL à l'aide de l'algorithme PPO de TorchRL. Utilisez-le comme point de départ pour affiner les paramètres et améliorer les performances de l'agent.
Personnalisation des algorithmes
TorchRL a une conception modulaire qui permet de personnaliser les solutions RL. Le cadre prend en charge l'interface entre les différents composants. Pour tester et comparer leurs performances, vous pouvez brancher et jouer des environnements, des politiques différentes, des tampons de relecture et des algorithmes RL. Grâce à cette modularité :
- Vous pouvez remplacer différents composants sans avoir à réécrire de grandes parties du programme.
- Les composants individuels peuvent également être modifiés indépendamment pour créer des solutions personnalisées.
- Vous pouvez expérimenter différents modules et construire une solution optimisée.
Voici quelques exemples de personnalisation dans TorchRL :
- Les boucles d'entraînement peuvent être personnalisées avec des programmateurs de taux d'apprentissage, des enregistreurs et des mesures personnalisées.
- Différentes longueurs de tampons de relecture peuvent être utilisées pour ajuster la durée de l'entraînement.
- L'environnement peut être personnalisé pour inclure des fonctions de mise à l'échelle et de normalisation, des compteurs d'étapes, etc.
Visualisation et débogage de la formation RL
Les sections précédentes ont montré comment utiliser les modules TorchRL pour former des agents RL. Dans cette section, nous examinons les moyens de suivre et de visualiser la progression de la formation.
Suivi des progrès de la formation
Il est utile d'enregistrer diverses mesures pendant le processus de formation pour en suivre les progrès. Des logiciels tels que TensorBoard permettent d'enregistrer directement les résultats au cours du processus d'apprentissage. Par exemple, le SummaryWriter de TensorBoard vous permet de l'appeler dans la boucle d'apprentissage pour enregistrer les mesures. Le pseudo-code suivant montre comment procéder :
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter(log_dir="training_logs")
for _ in training_data (): # training loop
loss = …
loss.backprop()
writer.add_scalar(“Loss - “, loss.item(), step)
…
writer.close()
Une fois la formation et l'enregistrement terminés, vous pouvez tracer et visualiser les résultats. Par exemple, utilisez la commande tensorboard
pour visualiser la progression de l'entraînement .
tensorboard --logdir=”training_logs”
Débogage avec TorchRL
Le débogage est essentiel pour vérifier l'interaction de l'agent avec l'environnement. Dans un premier temps, vous devez vérifier l'espace d'action et l'espace d'observation. La documentation de l'environnement doit inclure les spécifications de l'environnement. Par exemple, la documentation de CartPole indique que :
- L'espace d'action comprend deux valeurs discrètes : 0 (pour pousser le chariot à gauche) et 1 (pour pousser le chariot à droite).
- L'espace d'observation a 4 valeurs :
- Position du chariot, avec une valeur comprise entre
- -4,8 et +4,8.
- Vitesse du chariot, avec n'importe quelle valeur en nombre réel
- Angle du pôle, avec une valeur comprise entre -24° et +24°.
- Vitesse angulaire du pôle, avec n'importe quelle valeur en nombre réel
Inspectez les espaces d'observation et d'action pour vérifier qu'ils correspondent aux valeurs attendues. Par exemple :
print("Observation space: ", env.observation_spec)
print("Action space: ", env.action_spec)
En outre, vous pouvez tirer des échantillons aléatoires des espaces d'observation et d'action et vérifier leurs valeurs :
print("Sample Observation:", base_env.observation_spec.sample().get("observation"))
print("Sample Action:", base_env.action_spec.sample())
Le résultat ressemble à l'exemple ci-dessous :
Sample Observation: tensor([-4.5960e+00, 3.4028e+38, 2.2261e-02, 3.4028e+38])
Sample Action: tensor([1, 0])
Notez que les 4 valeurs d'état se situent dans les fourchettes spécifiées précédemment. Répétez les commandes ci-dessus plusieurs fois et remarquez que les différentes valeurs de sortie (échantillonnées au hasard) se situent dans les fourchettes spécifiées.
Les deux commandes ci-dessus sont basées sur l'environnement de base, directement importé de Gymnasium. Dans la pratique, nous utilisons l'environnement transformé, qui applique des transformations, comme la normalisation, aux valeurs tensorielles d'origine. Ainsi, lorsque vous utilisez l'environnement TorchRL transformé pour tirer un échantillon d'observations, leurs valeurs peuvent ne plus se situer dans le même intervalle que dans l'environnement Gymnasium d'origine.
Par exemple, tirez un échantillon de l'environnement transformé :
print("Sample Observation:", env.observation_spec.sample().get("observation"))
Le résultat ressemble à :
Sample Observation: tensor([-57.5869, nan, 4.5276, nan])
Notez que les valeurs de la position du chariot et de l'angle du pôle sont en dehors des plages. Cela est dû au fait que les valeurs des tenseurs ont été normalisées. En outre, la vitesse du chariot et la vitesse angulaire du poteau ont des valeurs nan
parce que l'agent n'a pas encore commencé à interagir avec l'environnement .
Visualisation de la performance des agents
Outre le traçage de la progression de la formation, il peut être utile de rendre l'environnement et d'observer visuellement les interactions de l'agent. Cela peut donner des indications sur les performances de l'agent.
La façon la plus pragmatique de visualiser l'environnement est de rendre une vidéo. Vous avez besoin de quelques paquets supplémentaires :
torchvision
pour travailler avec des fichiers multimédiasav
pour envelopper le paquetageffmpeg
afin qu'il puisse s'interfacer avec PyTorch .
pip install torchvision
pip install av==12.0.0
Après avoir terminé la formation, suivez les étapes préparatoires suivantes pour rendre la vidéo :
- Déclarez le chemin (relatif) pour stocker la vidéo.
- Initialiser l'enregistreur pour stocker les résultats des interactions de l'agent au format CSV.
- Initialiser l'enregistreur vidéo afin d'utiliser les journaux CSV pour générer une vidéo.
- Transformer l'environnement TorchRL pour y inclure l'enregistreur vidéo.
…
# training loop
# for _ in …
…
…
from torchrl.record import CSVLogger, VideoRecorder
path = "./training_loop"
logger = CSVLogger(exp_name="dqn", log_dir=path, video_format="mp4")
video_recorder = VideoRecorder(logger, tag="video")
record_env = TransformedEnv(
GymEnv("CartPole-v1", from_pixels=True, pixels_only=False), video_recorder
)
Exécutez la politique (entraînée) sur l'environnement et transférez les rendus dans le fichier vidéo :
record_env.rollout(max_steps=1000, policy=policy)
video_recorder.dump()
Après avoir lancé le programme, vous trouverez la vidéo dans le répertoire (./training_loop
dans l'extrait ci-dessus) que vous avez défini précédemment. Notez à l'adresseque le manuel de DataLab pour la mise en œuvre de DQN à l'aide de TorchRL n'inclut pas le code pour créer la vidéo parce qu'il est difficile d'exporter des fichiers vidéo avec un bloc-notes en ligne. Exécutez le programme (et ajoutez les étapes ci-dessus) sur un ordinateur local ou un serveur pour enregistrer des vidéos.
Meilleures pratiques pour l'utilisation de TorchRL
Enfin, abordons quelques bonnes pratiques. Voici mes recommandations.
Commencez par des environnements simples
Malgré la facilité de développement offerte par TorchRL, la formation des agents RL pour qu'ils soient performants dans des environnements complexes reste un défi. Ainsi, avant d'essayer de résoudre des problèmes difficiles, il est essentiel de résoudre des environnements simples comme CartPole.
La modularité de TorchRL permet d'expérimenter différents algorithmes et paramètres. Avant d'utiliser les algorithmes alternatifs et les options de personnalisation dans la pratique, il est nécessaire de mieux comprendre leur fonctionnement. Il est préférable de le faire dans un environnement simple, où les effets des changements individuels sont faciles à observer visuellement.
Expérimenter les hyperparamètres
Les performances d'apprentissage des modèles RL sont sensibles à divers hyperparamètres, tels que le taux d'apprentissage, le taux d'exploration, le taux d'actualisation et d'autres hyperparamètres spécifiques à l'algorithme, comme le ratio d'écrêtage pour le PPO. Par exemple, un taux d'apprentissage trop élevé rend la formation instable, tandis qu'un taux d'apprentissage trop faible met trop de temps à converger.
De même, un taux d'exploration très élevé empêche la formation de converger, tandis qu'un taux d'exploration trop faible peut empêcher l'agent de découvrir le chemin optimal.
Il n'existe pas de formule pour déterminer les bonnes valeurs d'hyperparamètres. Il existe des lignes directrices et des valeurs recommandées pour les environnements standard, mais elles ne s'appliquent pas nécessairement à tous les problèmes. Il est donc nécessaire d'expérimenter différentes méthodes, telles que la recherche par grille ou la recherche aléatoire, afin de déterminer les meilleures valeurs pour les hyperparamètres.
Il est également possible d'utiliser des bibliothèques automatisées telles que Weights & Biases Sweeps ou Optuna pour tester lesperformances de l'apprentissage à travers différentes combinaisons d'hyperparamètres .
Exploiter les algorithmes prédéfinis
Comme vous l'avez vu dans les exemples précédents, l'utilisation des modules préconstruits de TorchRL permet d'économiser un effort de développement considérable. L'autre solution consiste à créer toutes les fonctionnalités à partir de zéro, ce qui prendrait beaucoup plus de temps et d'argent pour les développer et les tester.
Comme de nombreux développeurs utilisent les modules de TorchRL, ceux-ci bénéficient également d'avoir été testés dans différents scénarios. Vous pouvez donc vous attendre à ce qu'ils soient plus exempts de bogues qu'un module conçu sur mesure. Par conséquent, pour la plupart des cas d'utilisation standard, il est fortement conseillé d'utiliser des modules préconstruits.
Conclusion
Dans cet article, nous avons couvert les concepts de base de TorchRL, un cadre basé sur PyTorch pour implémenter des algorithmes RL. Nous avons également vu des exemples pratiques d'utilisation de TorchRL pour mettre en œuvre des solutions plus simples comme le Deep Q-Learning et des algorithmes plus complexes comme le PPO.
Dans une prochaine étape, vous pouvez utiliser ces programmes comme base pour expérimenter d'autres environnements et algorithmes.
Si vous souhaitez approfondir votre compréhension des principes fondamentaux de l 'apprentissage par renforcement et des applications pratiques, consultez Reinforcement Learning with Gymnasium in Python pour obtenir une expérience plus pratique des environnements basés sur Python.
Concepts d'intelligence artificielle (IA) en Python
Arun est un ancien fondateur de startup qui aime construire de nouvelles choses. Il étudie actuellement les fondements techniques et mathématiques de l'intelligence artificielle. Il aime partager ce qu'il a appris, alors il écrit à ce sujet.
En plus de DataCamp, vous pouvez lire ses publications sur Medium, Airbyte et Vultr.
Apprenez-en plus sur l'apprentissage par renforcement avec ces cours !
cours
Apprentissage par renforcement à partir du feedback humain (RLHF)
cours