Introduction : Apprendre des Récompenses
Le Reinforcement Learning (RL) est un paradigme d'apprentissage fondamentalement différent du supervised et de l'unsupervised learning. Au lieu d'apprendre à partir de données étiquetées, un agent interagit avec un environnement, exécute des actions et reçoit des récompenses. L'objectif est d'apprendre une policy (stratégie) qui maximise la récompense cumulée dans le temps.
Des échecs (AlphaZero) à la robotique (manipulation d'objets), du trading algorithmique à la conduite autonome, le reinforcement learning est à la base de certaines des applications d'IA les plus impressionnantes. Dans cet article, nous explorerons les concepts fondamentaux, du Q-Learning classique aux algorithmes de deep RL modernes comme DQN et PPO.
Ce Que Vous Apprendrez
- Markov Decision Process (MDP) : état, action, récompense, transition
- Q-Learning : la table de valeurs action-état
- Deep Q-Network (DQN) : approximer Q avec des réseaux de neurones
- Policy Gradient : optimiser directement la policy
- Proximal Policy Optimization (PPO) : stabilité et performance
- Exploration vs exploitation : équilibrer découverte et utilisation
- Implémentation pratique avec Gymnasium (OpenAI)
Markov Decision Process (MDP)
Le framework formel du RL est le Markov Decision Process, défini par quatre composantes :
- États (S) : les situations possibles dans lesquelles l'agent peut se trouver (ex. position sur une grille, frame d'un jeu)
- Actions (A) : les mouvements disponibles dans chaque état (ex. haut, bas, gauche, droite)
- Récompenses (R) : le feedback numérique reçu après chaque action (ex. +1 pour gagner, -1 pour perdre)
- Transitions (P) : la probabilité de passer à un état suivant étant donné une action. La propriété de Markov établit que le futur ne dépend que de l'état actuel, pas de l'historique
L'agent cherche une policy optimale qui maximise la somme actualisée des récompenses futures. Le discount factor gamma (entre 0 et 1) équilibre récompenses immédiates vs futures : gamma proche de 0 rend l'agent myope, proche de 1 le rend prévoyant.
Q-Learning : Valeurs Action-État
Le Q-Learning est un algorithme off-policy qui apprend la fonction Q(s, a) : la valeur espérée de la récompense cumulée en choisissant l'action a dans l'état s et en suivant la policy optimale ensuite. La règle de mise à jour est :
Q(s, a) = Q(s, a) + alpha * [R + gamma * max_a'(Q(s', a')) - Q(s, a)]
import numpy as np
import gymnasium as gym
class QLearningAgent:
def __init__(self, n_states, n_actions, lr=0.1, gamma=0.99, epsilon=1.0):
self.q_table = np.zeros((n_states, n_actions))
self.lr = lr
self.gamma = gamma
self.epsilon = epsilon
self.epsilon_min = 0.01
self.epsilon_decay = 0.995
def choose_action(self, state):
"""Epsilon-greedy : explore avec prob epsilon, exploite sinon"""
if np.random.random() < self.epsilon:
return np.random.randint(self.q_table.shape[1])
return np.argmax(self.q_table[state])
def learn(self, state, action, reward, next_state, done):
"""Mise à jour de la Q-table"""
target = reward
if not done:
target += self.gamma * np.max(self.q_table[next_state])
self.q_table[state, action] += self.lr * (target - self.q_table[state, action])
self.epsilon = max(self.epsilon_min, self.epsilon * self.epsilon_decay)
# Entraînement sur FrozenLake
env = gym.make('FrozenLake-v1', is_slippery=False)
agent = QLearningAgent(n_states=16, n_actions=4)
for episode in range(5000):
state, _ = env.reset()
total_reward = 0
done = False
while not done:
action = agent.choose_action(state)
next_state, reward, terminated, truncated, _ = env.step(action)
done = terminated or truncated
agent.learn(state, action, reward, next_state, done)
state = next_state
total_reward += reward
if episode % 1000 == 0:
print(f"Épisode {episode}, Récompense: {total_reward}, "
f"Epsilon: {agent.epsilon:.3f}")
Exploration vs Exploitation
Le dilemme fondamental du RL : l'agent doit explorer (essayer de nouvelles actions pour découvrir de meilleures récompenses) et exploiter (utiliser les connaissances actuelles pour maximiser la récompense). La stratégie epsilon-greedy équilibre les deux aspects : avec probabilité epsilon, il choisit une action aléatoire, sinon la meilleure action connue. Epsilon diminue progressivement pendant l'entraînement.
Deep Q-Network (DQN)
Le Q-Learning avec tables ne fonctionne que pour des espaces d'états petits et discrets. Pour des environnements complexes (images, états continus), la Deep Q-Network (DQN) remplace la Q-table par un réseau de neurones qui approxime la fonction Q. Deux innovations clés stabilisent l'entraînement :
- Experience Replay : les transitions sont stockées dans un buffer et échantillonnées aléatoirement pour l'entraînement, brisant la corrélation temporelle entre échantillons consécutifs
- Target Network : une copie séparée du réseau, mise à jour périodiquement, calcule les Q-values cibles, stabilisant l'apprentissage
import torch
import torch.nn as nn
from collections import deque
import random
class DQN(nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
self.net = nn.Sequential(
nn.Linear(state_dim, 128),
nn.ReLU(),
nn.Linear(128, 128),
nn.ReLU(),
nn.Linear(128, action_dim)
)
def forward(self, x):
return self.net(x)
class DQNAgent:
def __init__(self, state_dim, action_dim, lr=1e-3, gamma=0.99):
self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
self.q_net = DQN(state_dim, action_dim).to(self.device)
self.target_net = DQN(state_dim, action_dim).to(self.device)
self.target_net.load_state_dict(self.q_net.state_dict())
self.optimizer = torch.optim.Adam(self.q_net.parameters(), lr=lr)
self.memory = deque(maxlen=100000)
self.gamma = gamma
self.batch_size = 64
def store(self, state, action, reward, next_state, done):
self.memory.append((state, action, reward, next_state, done))
def learn(self):
if len(self.memory) < self.batch_size:
return
batch = random.sample(self.memory, self.batch_size)
states, actions, rewards, next_states, dones = zip(*batch)
states = torch.FloatTensor(states).to(self.device)
actions = torch.LongTensor(actions).to(self.device)
rewards = torch.FloatTensor(rewards).to(self.device)
next_states = torch.FloatTensor(next_states).to(self.device)
dones = torch.FloatTensor(dones).to(self.device)
q_values = self.q_net(states).gather(1, actions.unsqueeze(1))
with torch.no_grad():
next_q = self.target_net(next_states).max(1)[0]
targets = rewards + (1 - dones) * self.gamma * next_q
loss = nn.functional.mse_loss(q_values.squeeze(), targets)
self.optimizer.zero_grad()
loss.backward()
self.optimizer.step()
def update_target(self):
self.target_net.load_state_dict(self.q_net.state_dict())
Policy Gradient et Actor-Critic
Les méthodes Policy Gradient optimisent directement la policy sans passer par la fonction Q. Le théorème du policy gradient établit que le gradient de la récompense espérée par rapport aux paramètres de la policy est proportionnel à la récompense pondérée par la log-probabilité des actions.
Actor-Critic
L'architecture Actor-Critic combine les deux approches : l'Actor (policy network) choisit les actions, le Critic (value network) estime la qualité de l'état actuel. Le Critic réduit la variance des mises à jour de l'Actor, rendant l'entraînement plus stable.
PPO : Le Standard Industriel
Proximal Policy Optimization (PPO), développé par OpenAI, est l'algorithme de RL le plus utilisé en pratique. Son innovation clé est l'objectif clipé : il limite de combien la nouvelle policy peut s'éloigner de l'ancienne à chaque mise à jour, prévenant des changements trop drastiques qui déstabiliseraient l'entraînement.
PPO est à la base de nombreux succès : InstructGPT et RLHF (alignement des LLM), OpenAI Five (Dota 2), entraînement d'agents robotiques et bien d'autres.
Prochaines Étapes de la Série
- Dans le prochain article, nous explorerons le Transfer Learning Avancé avec BERT, GPT et Hugging Face
- Nous verrons le fine-tuning, le prompt engineering et le RAG (Retrieval-Augmented Generation)
- Nous comparerons les modèles open-source : Llama, Mistral, Falcon







