Policy Gradient : Guide Complet — Optimisation Directe de la Politique
Résumé
Le Policy Gradient est une famille d’algorithmes d’apprentissage par renforcement qui optimise directement la politique d’un agent, sans passer par l’estimation intermédiaire d’une fonction de valeur. Contrairement aux méthodes basées sur la valeur comme le Q-learning, le Policy Gradient ajuste les paramètres θ d’une politique paramétrée π(a|s ; θ) afin de maximiser l’espérance du retour cumulé. Cette approche offre des avantages majeurs : elle fonctionne naturellement avec des espaces d’actions continus, évite les discontinuités liées à l’opérateur max, et converge vers des politiques stochastiques optimales. Cet article présente le théorème fondamental du gradient de politique, l’algorithme REINFORCE, les techniques de réduction de variance comme la baseline et l’avantage, et propose une implémentation complète en Python avec PyTorch sur l’environnement CartPole.
Principe Mathématique du Policy Gradient
Politique paramétrée
Au cœur du Policy Gradient se trouve l’idée de représenter la politique comme une fonction paramétrée :
$$\pi(a | s ; \theta) = P(a_t = a | s_t = s; \theta)$$
où θ désigne l’ensemble des paramètres apprenables (typiquement les poids d’un réseau de neurones). La politique π assigne une probabilité à chaque action a étant donné un état s. Le but est de trouver les paramètres θ* qui maximisent une fonction objectif J(θ), généralement définie comme l’espérance du retour cumulé sous la politique π_θ.
Le théorème du gradient de politique
Le résultat central du Policy Gradient est le théorème du gradient de politique (Policy Gradient Theorem), démontré par Sutton et collaborateurs en 2000. Ce théorème établit que le gradient de la fonction objectif J(θ) peut s’écrire sous la forme suivante :
$$\nabla J(\theta) = \mathbb{E}{\tau \sim \pi\theta} \left[ \sum_{t=0}^{T} \nabla_\theta \log \pi_\theta(a_t | s_t) \cdot G_t \right]$$
où G_t représente le retour cumulé (return) à partir de l’instant t :
$$G_t = \sum_{k=t}^{T} \gamma^{k-t} r_k$$
avec γ ∈ [0, 1] le facteur d’actualisation et r_k la récompense obtenue à l’étape k. Ce théorème est remarquable car il ne nécessite pas de connaître la dynamique de l’environnement P(s’ | s, a) ni la distribution des états d. Le gradient s’exprime uniquement en termes de la politique π_θ et des récompenses observées.
L’intuition est élégante : si une action a_t a conduit à un retour G_t élevé, on renforce la probabilité de choisir cette action dans l’état s_t (le terme ∇θ log πθ(a_t | s_t) pointe dans la direction qui augmente π_θ(a_t | s_t)). Inversement, si le retour est faible, la probabilité diminue naturellement.
L’algorithme REINFORCE
REINFORCE (Williams, 1992) est l’algorithme historique de Policy Gradient, également appelé algorithme de Monte Carlo par gradient de politique. Sa règle de mise à jour est directe :
$$\theta \leftarrow \theta + \alpha \cdot \nabla_\theta \log \pi_\theta(a_t | s_t) \cdot G_t$$
où α est le taux d’apprentissage. L’algorithme fonctionne de la manière suivante :
- Générer un épisode complet en suivant la politique courante π_θ.
- Calculer les retours cumulés G_t pour chaque pas de temps de l’épisode.
- Calculer le gradient pour chaque pas : ∇_θ log π_θ(a_t | s_t) · G_t.
- Mettre à jour les paramètres θ en accumulant les gradients de tout l’épisode.
REINFORCE est un algorithme de type « Monte Carlo » car il nécessite un épisode complet avant de pouvoir effectuer une mise à jour. Cela le distingue des méthodes temporelles comme le Q-learning, qui mettent à jour à chaque pas.
La baseline : réduction de la variance
Un problème majeur de REINFORCE est sa variance élevée. Comme le retour G_t peut fluctuer considérablement d’un épisode à l’autre, les mises à jour sont bruyantes et l’apprentissage devient lent. La solution classique consiste à soustraire une baseline b(s) au retour :
$$\nabla J(\theta) = \mathbb{E}{\tau} \left[ \sum \nabla_\theta \log \pi_\theta(a_t | s_t) \cdot (G_t – b(s_t)) \right]$$}^{T
Cette opération ne biaise pas le gradient (l’espérance reste inchangée) mais peut considérablement réduire sa variance. Le choix le plus courant pour la baseline est la fonction de valeur d’état V(s), qui représente le retour moyen attendu depuis l’état s. Quand la baseline est bien choisie, le terme (G_t − V(s_t)) devient un estimateur de l’avantage A(s_t, a_t) = Q(s_t, a_t) − V(s_t), mesurant si l’action choisie était meilleure ou pire que la moyenne.
D’autres baselines sont possibles : une constante (la récompense moyenne), une valeur de référence mobile, ou même le retour d’un autre réseau de neurones. Le choix dépend du contexte et du compromis biais-variance recherché.
Intuition : Apprendre Directement « Quoi Faire »
Pour bien comprendre la différence fondamentale entre le Policy Gradient et les méthodes basées sur la valeur, imaginez deux musiciens qui apprennent à improviser.
Le premier musicien (analogue au Q-learning) commence par construire mentalement un tableau immense : pour chaque situation musicale (l’état) et chaque note possible (l’action), il estime le « score » que cette note obtiendrait. Quand vient le moment de jouer, il consulte ce tableau et choisit la note au score le plus élevé. Cette approche fonctionne, mais elle est rigide : si deux notes ont des scores presque identiques, un petit changement peut faire basculer brutalement le choix d’une note à l’autre. De plus, dans un espace continu (un glissando, par exemple), le nombre de « notes » est infini et le tableau devient ingérable.
Le deuxième musicien (analogue au Policy Gradient) n’a pas de tableau. Il apprend directement une distribution de probabilité sur les actions possibles. Quand une séquence de notes produit un résultat satisfaisant (un accord harmonieux, l’approbation du public), il renforce les probabilités qui ont conduit à ce résultat. Quand ça sonne faux, il les diminue progressivement. C’est un apprentissage par le feeling, guidé par la récompense finale plutôt que par une évaluation intermédiaire de chaque action individuelle.
Contrairement au Q-learning qui évalue d’abord les actions puis choisit, le Policy Gradient apprend directement « quoi faire » — comme un musicien qui improvise sans réfléchir à chaque note, guidé par le feeling du résultat.
Cette différence fondamentale explique pourquoi le Policy Gradient excelle dans les espaces d’actions continus (où le Q-learning ne peut pas simplement « prendre le max »), pourquoi il converge vers des politiques stochastiques optimales (essentielles dans les environnements où la randomisation est stratégiquement avantageuse), et pourquoi il est la base des algorithmes modernes comme PPO et SAC.
Implémentation Python avec PyTorch
Voici une implémentation complète de REINFORCE sur l’environnement CartPole-v1 d’OpenAI Gym, utilisant PyTorch comme framework de calcul.
Installation des dépendances
pip install torch gymnasium numpy matplotlib
Code complet : REINFORCE sur CartPole
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.distributions import Categorical
import gymnasium as gym
import matplotlib.pyplot as plt
import numpy as np
class PolicyNetwork(nn.Module):
"""
Réseau de politique pour REINFORCE.
Prend un état en entrée et retourne une distribution de probabilités
sur l'espace d'actions discrètes.
"""
def __init__(self, state_dim: int, action_dim: int, hidden_size: int = 128):
super(PolicyNetwork, self).__init__()
self.fc1 = nn.Linear(state_dim, hidden_size)
self.fc2 = nn.Linear(hidden_size, hidden_size)
self.fc3 = nn.Linear(hidden_size, action_dim)
def forward(self, state: torch.Tensor) -> torch.Tensor:
"""Retourne les logits pour chaque action."""
x = F.relu(self.fc1(state))
x = F.relu(self.fc2(x))
logits = self.fc3(x)
return logits
def select_action(self, state: torch.Tensor):
"""
Sélectionne une action selon la politique courante.
Retourne l'action, le log-probabilité associée, et l'entropie.
"""
logits = self.forward(state)
dist = Categorical(logits=logits)
action = dist.sample()
log_prob = dist.log_prob(action)
entropy = dist.entropy()
return action.item(), log_prob, entropy
def compute_returns(rewards: list, gamma: float) -> torch.Tensor:
"""
Calcule les retours cumulés actualisés pour un épisode.
G_t = r_t + gamma * r_{t+1} + gamma^2 * r_{t+2} + ...
"""
returns = []
R = 0.0
for reward in reversed(rewards):
R = reward + gamma * R
returns.insert(0, R)
return torch.tensor(returns, dtype=torch.float32)
def reinforce(
env_name: str = "CartPole-v1",
learning_rate: float = 1e-2,
gamma: float = 0.99,
n_episodes: int = 1000,
hidden_size: int = 128,
seed: int = 42
):
"""
Algorithme REINFORCE avec PyTorch.
Args:
env_name: Nom de l'environnement Gymnasium.
learning_rate: Taux d'apprentissage (alpha).
gamma: Facteur d'actualisation.
n_episodes: Nombre total d'épisodes d'entraînement.
hidden_size: Taille des couches cachées du réseau.
seed: Graine aléatoire pour la reproductibilité.
"""
# Initialisation
torch.manual_seed(seed)
env = gym.make(env_name)
state_dim = env.observation_space.shape[0]
action_dim = env.action_space.n
policy = PolicyNetwork(state_dim, action_dim, hidden_size)
optimizer = optim.Adam(policy.parameters(), lr=learning_rate)
rewards_history = []
running_avg = []
for episode in range(1, n_episodes + 1):
state, _ = env.reset(seed=seed + episode)
log_probs = []
rewards = []
entropies = []
done = False
total_reward = 0.0
# === Phase 1 : Collecte de la trajectoire complète ===
while not done:
state_tensor = torch.FloatTensor(state).unsqueeze(0)
action, log_prob, entropy = policy.select_action(state_tensor)
state, reward, terminated, truncated, _ = env.step(action)
done = terminated or truncated
log_probs.append(log_prob)
rewards.append(reward)
entropies.append(entropy)
total_reward += reward
# === Phase 2 : Calcul des retours ===
returns = compute_returns(rewards, gamma)
# Normalisation des retours (réduction de la variance)
if len(returns) > 1:
returns = (returns - returns.mean()) / (returns.std() + 1e-8)
# === Phase 3 : Mise à jour des paramètres ===
# Perte négative car on fait de la descente de gradient
policy_loss = []
for log_prob, ret in zip(log_probs, returns):
policy_loss.append(-log_prob * ret)
# Ajout d'un terme d'entropie pour encourager l'exploration
bonus_entropie = -0.01 * sum(entropies)
loss = torch.stack(policy_loss).sum() + bonus_entropie
optimizer.zero_grad()
loss.backward()
optimizer.step()
# Suivi
rewards_history.append(total_reward)
if len(rewards_history) >= 100:
avg = sum(rewards_history[-100:]) / 100
running_avg.append(avg)
if episode % 50 == 0:
print(f"Épisode {episode:4d} | Récompense: {total_reward:6.1f} | "
f"Moy. 100 derniers: {avg:.1f} | Perte: {loss.item():.4f}")
# Critère d'arrêt anticipé
if len(running_avg) > 0 and running_avg[-1] >= 490:
print(f"\nConvergence atteinte à l'épisode {episode} ! "
f"Moyenne sur 100 épisodes: {running_avg[-1]:.1f}")
break
env.close()
return rewards_history, running_avg
if __name__ == "__main__":
print("=" * 60)
print("REINFORCE sur CartPole-v1 — Policy Gradient (Monte Carlo)")
print("=" * 60)
hist, avg = reinforce(
learning_rate=0.01,
gamma=0.99,
n_episodes=1000,
hidden_size=128,
seed=42
)
# Visualisation
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(hist, alpha=0.3, color="gray", label="Récompense par épisode")
plt.xlabel("Épisode")
plt.ylabel("Récompense totale")
plt.title("Progression de l'apprentissage")
plt.legend()
plt.grid(True, alpha=0.3)
plt.subplot(1, 2, 2)
plt.plot(avg, color="blue", linewidth=2, label="Moyenne mobile (100 épisodes)")
plt.axhline(y=495, color="green", linestyle="--", alpha=0.5, label="Seuil de convergence")
plt.xlabel("Épisode")
plt.ylabel("Récompense moyenne")
plt.title("Convergence")
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("reinforce_cartpole_results.png", dpi=150)
print("\nRésultats sauvegardés dans 'reinforce_cartpole_results.png'")
Explication détaillée du code
Architecture du réseau : Le PolicyNetwork reçoit un vecteur d’état de dimension 4 (position du chariot, vitesse, angle du poteau, vitesse angulaire) et retourne des logits pour 2 actions (pousser à gauche ou à droite). La fonction select_action utilise Categorical pour échantillonner une action selon la distribution de probabilité, ce qui assure l’exploration naturelle pendant l’entraînement.
Collecte de trajectoire : REINFORCE est un algorithme « épisode-complet ». Contrairement au DQN qui apprend à chaque transition, REINFORCE accumule toutes les log-probabilités et récompenses pendant l’épisode entier avant d’effectuer une mise à jour. Cette caractéristique est à la fois sa force (estimation non biaisée du gradient) et sa faiblesse (variance élevée, apprentissage plus lent en début d’entraînement).
Normalisation des retours : Avant la rétropropagation, on normalise les retours en soustrayant la moyenne et en divisant par l’écart-type. Cette opération agit comme une baseline adaptative et réduit significativement la variance des gradients, ce qui stabilise l’apprentissage.
Terme d’entropie : Le bonus d’entropie (−0.01 × H(π)) encourage la politique à rester suffisamment exploratoire, en évitant qu’elle ne s’effondre trop vite vers une action déterministe. C’est une forme de régularisation très courante dans les algorithmes de Policy Gradient modernes.
Hyperparamètres
Le choix des hyperparamètres est crucial pour la performance du Policy Gradient. Voici les principaux :
| Hyperparamètre | Valeur typique | Rôle |
|---|---|---|
learning_rate |
1e-3 à 1e-2 | Contrôle l’ampleur de chaque mise à jour. Un taux trop élevé provoque des oscillations ; trop faible, la convergence est excessivement lente. |
gamma (γ) |
0.95 à 0.99 | Facteur d’actualisation des récompenses futures. Proche de 1, l’agent prend en compte les conséquences à long terme ; proche de 0, il devient myope. |
n_episodes |
500 à 2000 | Nombre total d’épisodes d’entraînement. REINFORCE nécessite généralement plus d’épisodes que DQN car chaque mise à jour utilise un seul épisode. |
hidden_size |
64 à 256 | Taille des couches cachées du réseau de politique. Un réseau plus large peut capturer des politiques plus complexes mais risque le surapprentissage. |
Conseils de réglage
- Commencez petit : Avec CartPole,
hidden_size=64etlearning_rate=0.01fonctionnent remarquablement bien. Ne surdimensionnez pas le réseau inutilement. - Surveillez l’entropie : Si l’entropie chute trop vite (la politique devient déterministe prématurément), augmentez le coefficient d’entropie ou réduisez le taux d’apprentissage.
- Normalisez les retours : Sans normalisation, REINFORCE est très sensible aux récompenses extrêmes. La normalisation (z-score) est le moyen le plus simple de stabiliser l’apprentissage.
- Augmentez gamma progressivement : Si l’agent peine à apprendre des comportements à long terme, augmentez γ par paliers (0.95 → 0.99) au fur et à mesure de l’entraînement.
Avantages et Limites du Policy Gradient
Avantages
- Espaces d’actions continus : Contrairement au Q-learning qui nécessite le calcul d’un maximum sur toutes les actions (impossible dans un espace continu), le Policy Gradient fonctionne naturellement avec des distributions continues (par exemple, une gaussienne multivariée pour des actions à valeurs réelles).
- Politiques stochastiques optimales : Le Policy Gradient peut représenter et converger vers des politiques stochastiques, ce qui est essentiel dans les environnements partiellement observables (POMDP) où la randomisation est stratégiquement nécessaire.
- Pas de discontinuité du max : Le Q-learning souffre de discontinuités quand l’action optimale change brusquement. Le Policy Gradient évolue de manière continue dans l’espace des probabilités.
- Compatibilité avec les réseaux profonds : Le Policy Gradient se combine naturellement avec des réseaux de neurones profonds, permettant de traiter des observations complexes comme des images ou du texte.
Limites
- Variance élevée : Les gradients de REINFORCE sont intrinsèquement bruyants car ils dépendent du retour complet d’un épisode, qui peut varier considérablement. Cela rend la convergence lente et instable sans techniques de réduction de variance.
- Convergence vers des optima locaux : La fonction objectif J(θ) est non convexe, et les algorithmes de gradient peuvent converger vers des optima locaux sous-optimaux, surtout avec des politiques mal initialisées.
- Échantillonnage inefficace : Chaque mise à jour de REINFORCE ne bénéficie que d’un seul épisode. Comparé aux méthodes « off-policy » comme DQN qui réutilisent les transitions via un replay buffer, le Policy Gradient « on-policy » gaspille beaucoup de données.
- Sensibilité aux hyperparamètres : Le taux d’apprentissage est particulièrement critique. Un pas trop grand peut détruire une politique déjà performante, tandis qu’un pas trop petit rend l’apprentissage interminable.
Ces limitations ont motivé le développement d’algorithmes plus sophistiqués comme PPO (Proximal Policy Optimization), A3C (Asynchronous Advantage Actor-Critic), et SAC (Soft Actor-Critic), qui combinent les avantages du Policy Gradient avec des mécanismes de stabilisation avancés.
4 Cas d’Usage du Policy Gradient
1. Robotique et contrôle moteur
Le contrôle de robots dans des espaces continus est l’un des cas d’usage les plus classiques du Policy Gradient. Un bras robotique possédant 7 articulations nécessite un vecteur de 7 valeurs réelles en sortie (angles ou couples). Les méthodes basées sur la valeur ne peuvent pas gérer cet espace continu de manière efficace, tandis qu’un Policy Gradient avec une distribution gaussienne en sortie modélise directement les commandes continues. Des travaux comme ceux de Levine et al. (2016) ont montré que des politiques apprises par gradient de politique permettent à des robots d’attraper des objets, d’ouvrir des portes, ou de réaliser des tâches de manipulation complexes en apprenant directement à partir des données capteurs.
2. Jeux vidéo et agents autonomes
Les agents jouant à des jeux vidéo complexes (StarCraft, Dota 2, Atari) utilisent fréquemment des variantes du Policy Gradient. L’exemple le plus célèbre est AlphaGo et ses successeurs, qui combinent un réseau de politique (sélectionnant les coups probables) avec un réseau de valeur (estimant les chances de victoire). Dans les environnements de jeu, l’espace d’actions est souvent immense et la politique stochastique permet une exploration plus riche que les approches déterministes. L’algorithme PPO, dérivé du Policy Gradient, a été utilisé pour entraîner des agents Dota 5 capables de battre des joueurs professionnels humains.
3. Finance algorithmique et trading automatisé
En finance, les décisions de trading impliquent des montants continus (combien acheter/vendre) et des timings précis (quand entrer/sortir d’une position). Le Policy Gradient, avec ses politiques stochastiques et sa capacité à optimiser directement des fonctions de récompense complexes (ratio de Sharpe, drawdown maximum, rendement cumulé), est particulièrement adapté à ces problèmes. Contrairement aux approches supervisées classiques qui prédisent simplement la direction du marché, un agent de Policy Gradient apprend une stratégie complète d’exécution, intégrant la gestion du risque directement dans sa fonction objectif.
4. Optimisation de recommandation et publicité ciblée
Les systèmes de recommandation modernes (Netflix, YouTube, TikTok) optimisent en temps réel la politique de sélection de contenu pour maximiser l’engagement utilisateur. Le Policy Gradient permet de modéliser cette politique de manière continue : au lieu de classifier simplement si un utilisateur aimera un contenu, l’algorithme apprend un mélange personnalisé de genres, durées, sources et formats. La politique évolue au fil du temps en fonction des retours implicites (temps de visionnage, partages, abonnements), ce qui correspond exactement au paradigme récompense-retour du Policy Gradient. Les plateformes publicitaires utilisent des approches similaires pour optimiser les enchères en temps réel (RTB) et maximiser le retour sur investissement des campagnes.
Voir Aussi
- Implémentation de l’Algorithme de Cramer et Calcul de Déterminant en Python
- Optimisez Votre Code Python avec SOP et POS : Guide Complet pour les Débutants

