Deep Q-Network (DQN) : Guide complet — Q-Learning Profond
Résumé — Le Deep Q-Network (DQN), introduit par DeepMind en 2015, est un algorithme d’apprentissage par renforcement qui remplace la table Q du Q-learning classique par un réseau de neurones profond. Cette innovation permet de gérer des espaces d’états massifs (images, capteurs continus) impossibles à représenter dans un tableau discret. Le DQN a atteint des performances surhumaines sur 49 jeux Atari en apprenant directement à partir des pixels bruts, marquant une révolution dans le domaine du reinforcement learning.
Principe mathématique
1. Approximation de la fonction Q par un réseau de neurones
Dans le Q-learning classique, une table stocke Q(s, a) pour chaque paire (état, action). Mais si l’état est une image 210×160 RGB, il y a 256^(210×160×3) états possibles — une table est impossible.
Le DQN utilise un réseau de neurones comme approximateur :
Q(s, a; w) ≈ Q*(s, a)
où w sont les poids du réseau. Le réseau prend l’état s en entrée et produit une valeur Q pour chaque action disponible en sortie.
2. Fonction de loss
L’objectif est de minimiser l’erreur entre la Q-value prédite et la cible de Bellman :
L(w) = E[(r + γ · max_a’ Q(s’, a’; w-) – Q(s, a; w))²]
Où :
– r : récompense immédiate
– γ : facteur d’actualisation (discount factor, généralement 0.99)
– s’ : prochain état
– w- : poids du target network (copie gelée)
– Q(s, a; w) : Q-value prédite par le réseau principal
3. Target Network
Le problème fondamental du Q-learning avec approximation non linéaire est l’instabilité : la cible Q dépend des mêmes poids que l’on met à jour, créant une boucle de rétroaction négative (comme entraîner un réseau sur des données qui changent à chaque step).
La solution : utiliser un target network — une copie des poids gelée qui est mise à jour périodiquement (toutes les C itérations) :
w- ← w (toutes les C itérations)
Cela stabilise la cible pendant C étapes, permettant à l’apprentissage de converger.
4. Experience Replay
Le second problème est la corrélation entre échantillons successifs : les transitions (s, a, r, s’) sont hautement corrélées car elles proviennent d’une trajectoire continue.
L’experience replay stocke les transitions dans un buffer de taille fixe et échantillonne aléatoirement (mini-batch) pour l’entraînement :
- À chaque step, stocker (s, a, r, s’, done) dans le buffer
- Quand le buffer contient suffisamment de samples, tirer un mini-batch aléatoire
- Calculer la loss et mettre à jour les poids
Cela brise les corrélations temporelles et réutilise les expériences passées (plus efficace).
5. Variantes avancées
Double DQN (2016) : Réduit la sur-estimation des Q-values en utilisant le réseau principal pour sélectionner l’action et le target network pour l’évaluer :
Q_target = r + γ · Q(s’, argmax_a’ Q(s’, a’; w); w-)
Dueling DQN (2016) : Sépare l’estimation de la valeur de l’état V(s) et de l’avantage de l’action A(s, a) :
Q(s, a) = V(s) + A(s, a) – mean(A(s, ·))
Cette architecture apprend plus efficacement dans les états où le choix d’action n’a pas d’importance.
Prioritized Experience Replay : Sample les transitions avec une erreur TD élevée plus fréquemment, car elles contiennent plus d’information à apprendre.
Intuition
Imaginez un joueur de jeux vidéo qui apprend à jouer à Space Invaders sans connaître les règles.
Le DQN fait trois choses :
- Il regarde l’écran : chaque image (frame) est prétraitée (redimensionnée à 84×84, empilée sur 4 frames pour capturer le mouvement) et passée dans un CNN qui en extrait les caracteristiques clés (position des aliens, du vaisseau, des balles).
- Il décide quoi faire : le réseau produit une Q-value pour chaque action possible (gauche, droite, tirer). Il choisit soit l’action avec le meilleur Q, soit une action aléatoire (exploration).
- Il apprend de ses erreurs : chaque action produit une récompense (+1 pour tuer un alien, -1 pour mourir, 0 sinon). Le réseau ajuste ses prédictions pour qu’elles correspondent à la récompense immédiate plus la meilleure prédiction future.
L’experience replay, c’est sa mémoire : au lieu d’oublier chaque partie, il stocke les moments clés (première mort, pattern d’aliens dangereux, stratégie gagnante) et les revit aléatoirement pendant l’entraînement. C’est comme le cerveau humain qui consolidé les souvenirs pendant le sommeil en rejouant les expériences de la journée.
Le target network, c’est sa référence stable : au lieu de se corriger par rapport à ses propres prédictions qui changent en permanence, il utilise une version plus ancienne de lui-même comme point de référence. C’est comme un étudiant qui compare ses progressions à un examen de référence passé le mois dernier plutôt qu’à ses propres estimations changeantes.
Implémentation Python
1. DQN sur CartPole avec TensorFlow/Keras
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import gymnasium as gym
from collections import deque
import random
# Hyperparamètres
GAMMA = 0.99
EPSILON = 1.0
EPSILON_MIN = 0.01
EPSILON_DECAY = 0.995
LEARNING_RATE = 0.001
BUFFER_SIZE = 10000
BATCH_SIZE = 64
TARGET_UPDATE_FREQ = 100
N_EPISODES = 500
# Environment
env = gym.make("CartPole-v1")
state_dim = env.observation_space.shape[0] # 4
action_dim = env.action_space.n # 2
# Replay buffer
buffer = deque(maxlen=BUFFER_SIZE)
# Réseau principal
def build_model():
model = keras.Sequential([
layers.Dense(64, activation="relu", input_shape=(state_dim,)),
layers.Dense(64, activation="relu"),
layers.Dense(action_dim, activation="linear")
])
model.compile(optimizer=keras.optimizers.Adam(learning_rate=LEARNING_RATE),
loss="mse")
return model
q_network = build_model()
target_network = build_model()
target_network.set_weights(q_network.get_weights())
# Fonction pour choisir une action (epsilon-greedy)
def choose_action(state, epsilon):
if random.random() < epsilon:
return env.action_space.sample() # exploration
q_values = q_network.predict(np.array([state]), verbose=0)
return np.argmax(q_values[0]) # exploitation
# Entraînement
scores = []
step_count = 0
for episode in range(N_EPISODES):
state, _ = env.reset()
done = False
total_reward = 0
while not done:
action = choose_action(state, epsilon)
next_state, reward, terminated, truncated, _ = env.step(action)
done = terminated or truncated
# Stocker dans le buffer
buffer.append((state, action, reward, next_state, done))
state = next_state
total_reward += reward
step_count += 1
# Entraînement si le buffer est assez plein
if len(buffer) >= BATCH_SIZE:
# Sample aléatoire
batch = random.sample(buffer, BATCH_SIZE)
states = np.array([b[0] for b in batch])
actions = np.array([b[1] for b in batch])
rewards = np.array([b[2] for b in batch])
next_states = np.array([b[3] for b in batch])
dones = np.array([b[4] for b in batch])
# Calculer les cibles
q_next = target_network.predict(next_states, verbose=0)
q_values = q_network.predict(states, verbose=0)
for i in range(BATCH_SIZE):
target = rewards[i]
if not dones[i]:
target += GAMMA * np.max(q_next[i])
q_values[i][actions[i]] = target
q_network.fit(states, q_values, epochs=1, verbose=0)
# Mettre à jour le target network périodiquement
if step_count % TARGET_UPDATE_FREQ == 0:
target_network.set_weights(q_network.get_weights())
# Decay epsilon
epsilon = max(EPSILON_MIN, epsilon * EPSILON_DECAY)
scores.append(total_reward)
if episode % 50 == 0:
print(f"Episode {episode} | Score: {total_reward} | "
f"Epsilon: {epsilon:.3f}")
print(f"Entraînement terminé. Score moyen dernier 100: "
f"{np.mean(scores[-100:]):.1f}")
2. Double DQN (modification minimale)
# Double DQN : séparer sélection et évaluation
def compute_double_dqn_targets(batch):
next_states = np.array([b[3] for b in batch])
rewards = np.array([b[2] for b in batch])
dones = np.array([b[4] for b in batch])
# Le réseau principal sélectionne la meilleure action
q_next_main = q_network.predict(next_states, verbose=0)
best_actions = np.argmax(q_next_main, axis=1)
# Le target network évalue cette action
q_next_target = target_network.predict(next_states, verbose=0)
best_q_values = q_next_target[np.arange(len(batch)), best_actions]
targets = rewards + GAMMA * best_q_values * (1 - dones)
return targets
Hyperparamètres
| Hyperparamètre | Valeur typique | Description |
|---|---|---|
| learning_rate | 0.0001-0.001 | Taux d’apprentissage de l’optimizer Adam |
| gamma | 0.95-0.99 | Facteur d’actualisation (plus = plus de vision long terme) |
| batch_size | 32-128 | Taille du mini-batch pour l’experience replay |
| buffer_size | 10 000-1 000 000 | Taille maximale du replay buffer |
| epsilon_start | 1.0 | Exploration initiale (100% aléatoire) |
| epsilon_min | 0.01-0.1 | Exploration minimale après decay |
| epsilon_decay | 0.99-0.999 | Vitesse de réduction de l’exploration |
| target_update_freq | 100-10 000 | Fréquence de copie q_network → target_network |
Avantages du DQN
- Gestion des espaces d’états continus : Contrairement au Q-learning tabulaire, le DQN gère des états de dimension quelconque (images, capteurs)
- Apprentissage from scratch : Pas besoin de features manuelles, le réseau apprend à extraire les bonnes representations
- Provené : Le DQN de DeepMind a surpassé les humains sur la majorité des jeux Atari en 2015
- Base de l’écosystème RL profond : Toutes les avancées modernes (A3C, PPO, SAC) partent des concepts introduits par le DQN
Limites du DQN
- Sur-estimation des Q-values : Le max operator tend à sur-estimer les valeurs (partiellement résolu par Double DQN)
- Sensible aux hyperparamètres : Le tuning nécessite de l’expérience et beaucoup d’essais
- Sample inefficient : Requiert des millions d’interactions avec l’environnement pour converger
- Discret uniquement : Le DQN classique ne gère que les espaces d’actions discrets. Pour les actions continues, il faut des algorithmes différents (DDPG, SAC, TD3)
4 cas d’usage concrets
1. Jeux Atari et jeux vidéo
Le cas historique : DeepMind a entraîné un seul algorithme DQN sur 49 jeux Atari différents (Pong, Breakout, Space Invaders) en apprenant uniquement à partir des pixels bruts et du score. Le même algorithme a atteint des performances superhumaines sur la majorité des jeux.
2. Trading algorithmique
Un DQN peut apprendre des stratégies de trading en interagissant avec un simulateur de marché. Les états contiennent les indicateurs techniques (RSI, MACD, volumes), les actions sont acheter/vendre/attendre, et les récompenses sont les profits réalisés. Le DQN apprend à maximiser le rendement tout en gérant le risque.
3. Optimisation de data centers
Google a utilisé du reinforcement learning profond pour optimiser le refroidissement de ses data centers. Un DQN apprend à ajuster les paramètres de climatisation (température, débit d’air) pour minimiser la consommation énergétique tout en maintenant les serveurs à températion sécurisée, réduisant la facture de 40%.
4. Navigation de robots autonomes
Un robot mobile utilise un DQN pour apprendre à naviguer dans un environnement inconnu. Les états viennent des capteurs LiDAR/caméra, les actions sont les commandes de mouvement, et les récompenses pénalisent les collisions et récompensent la progression vers la cible. L’apprentissage en simulation permet des millions d’essais sans risque matériel.
Conclusion
Le Deep Q-Network est le pont entre le reinforcement learning classique et le deep learning moderne. En remplaçant la table Q par un réseau de neurones et en introduisant l’experience replay et le target network, il a résolu les deux principaux obstacles de l’apprentissage par renforcement profond : la malédiction de la dimensionalité et l’instabilité de l’entraînement.
Bien que des algorithmes plus récents comme PPO et SAC aient surpassé le DQN dans de nombreux benchmarks, il reste un point de départ éducatif essentiel et une solution efficace pour les environnements à actions discrètes.
Voir aussi
- Calcul des Sommes des Carrés des Diviseurs Unitaires en Python : Guide Complet et Code Optimisé
- Question d’Entretien: Conversion de Nombres Romains en Entier avec Python

