Actor-Critic Methods
Les méthodes Actor-Critic sont une classe d’algorithmes d’apprentissage par renforcement qui combinent les approches basées sur la politique (Actor) et sur la valeur (Critic). Ces méthodes utilisent un acteur pour déterminer la politique (quelle action prendre) et un critique pour évaluer cette politique (quelle est la qualité de l’action prise). Cette séparation permet d’améliorer l’efficacité de l’apprentissage.
-
Actor : Le rôle de l’acteur est de proposer une politique (fonction qui mappe un état donné à une action). L’acteur met à jour la politique en fonction des retours du critique.
-
Critic : Le rôle du critique est d’évaluer la performance de l’acteur en calculant la valeur de l’état actuel ou l’avantage de l’action prise (souvent en utilisant une fonction de valeur V(s) ou une fonction d’avantage A(s,a).
Formules :
L’algorithme Actor-Critic met à jour la politique en utilisant le gradient de la politique avec un terme d’avantage :
Où :
-
est le taux d’apprentissage.
-
est le terme d’avantage, où
est la récompense obtenue à l’instant et est la fonction de valeur de l’état.
Fonctions :
-
Actor-Critic Methods (exemple)
Voici un exemple d'un agent Actor-Critic dans l'environnement CartPole-v1 d'OpenAI Gym en utilisant TensorFlow.
Importation :
import numpy as np import gym import tensorflow as tf from tensorflow.keras import layers
Exemple de code :
import gymnasium as gym import numpy as np import tensorflow as tf from tensorflow.keras import layers env = gym.make('CartPole-v1') state_size = env.observation_space.shape[0] action_size = env.action_space.n # Hyperparamètres learning_rate = 0.001 gamma = 0.99 episodes = 500 # Modèle Actor-Critic # Sortie actor: probas sur actions (policy) # Sortie critic: valeur d'état (state value) inputs = layers.Input(shape=(state_size,)) common = layers.Dense(128, activation='relu')(inputs) actor = layers.Dense(action_size, activation='softmax')(common) critic = layers.Dense(1)(common) model = tf.keras.Model(inputs=inputs, outputs=[actor, critic]) optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate) def choose_action(state): state = state.reshape([1, state_size]) prob = model(state)[0].numpy()[0] return np.random.choice(action_size, p=prob) for episode in range(episodes): state, _ = env.reset() done = False total_reward = 0 states = [] actions = [] rewards = [] dones = [] while not done: action = choose_action(state) next_state, reward, terminated, truncated, _ = env.step(action) done = terminated or truncated states.append(state) actions.append(action) rewards.append(reward) dones.append(done) state = next_state total_reward += reward # Convertir en array numpy states = np.array(states) actions = np.array(actions) rewards = np.array(rewards, dtype=np.float32) dones = np.array(dones, dtype=np.float32) # Calcul des valeurs cibles et avantages values = model(states)[1].numpy().flatten() next_value = 0 if dones[-1] else model(state.reshape(1, -1))[1].numpy()[0,0] returns = np.zeros_like(rewards) advantages = np.zeros_like(rewards) running_return = next_value running_advantage = 0 for t in reversed(range(len(rewards))): running_return = rewards[t] + gamma * running_return * (1 - dones[t]) returns[t] = running_return td_error = rewards[t] + gamma * (values[t+1] if t + 1 < len(rewards) else next_value) * (1 - dones[t]) - values[t] running_advantage = td_error + gamma * 0.95 * running_advantage * (1 - dones[t]) advantages[t] = running_advantage returns = returns.reshape(-1, 1) advantages = advantages.reshape(-1, 1) # Mise à jour du modèle with tf.GradientTape() as tape: actor_logits, critic_values = model(states) critic_values = tf.squeeze(critic_values, axis=1) # Loss critic: MSE entre returns et valeurs loss_critic = tf.keras.losses.MSE(returns, tf.expand_dims(critic_values, 1)) # Loss actor: policy gradient pondéré par l'avantage action_masks = tf.one_hot(actions, action_size) log_probs = tf.reduce_sum(action_masks * tf.math.log(actor_logits + 1e-8), axis=1, keepdims=True) loss_actor = -tf.reduce_mean(log_probs * advantages) loss = loss_actor + loss_critic grads = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(grads, model.trainable_variables)) loss_scalar = tf.reduce_mean(loss) print(f"Episode {episode+1}: Total Reward = {total_reward:.2f}, Loss = {loss_scalar.numpy():.4f}")
Explication du code :
1. Initialisation de l’environnement CartPole
- Environnement : `CartPole-v1` de Gymnasium. - Taille de l’état (`state_size`) : 4. - Nombre d’actions (`action_size`) : 2.2. Modèle Actor-Critic
- Entrée : vecteur état de dimension `state_size`. - Couche commune dense : 128 neurones, activation `relu`. - Sortie actor : couche dense avec `action_size` neurones, activation `softmax` (distribution de probabilités sur les actions). - Sortie critic : couche dense avec 1 neurone, estimation de la valeur d’état (state value). - Optimiseur : Adam avec un taux d’apprentissage `learning_rate = 0.001`.3. Politique stochastique d’action
- L’action est échantillonnée selon la distribution de probabilités fournie par la sortie actor (softmax). - Cette politique permet une exploration naturelle de l’espace d’actions.4. Collecte des données par épisode
- Stockage des états, actions, récompenses et indicateurs `done` pendant un épisode. - L’épisode se termine quand `done = True` (pole tombe ou timeout).5. Calcul des retours et avantages (returns et advantages)
- Calcul des valeurs d’état (`values`) via le critic pour tous les états. - Estimation de la valeur du prochain état (`next_value`) si l’épisode n’est pas terminé. - Calcul des retours cumulés (returns) en remontant dans le temps : \[ G_t = r_t + \gamma G_{t+1} (1 - done_t) \] - Calcul des avantages (advantages) selon la formule TD-error avec un facteur d’actualisation partiel sur les avantages (lambda = 0.95) : \[ A_t = \delta_t + \gamma \lambda A_{t+1} (1 - done_t) \] avec \[ \delta_t = r_t + \gamma V(s_{t+1})(1 - done_t) - V(s_t) \]6. Mise à jour du modèle
- Loss critic : erreur quadratique moyenne (MSE) entre retours (`returns`) et valeurs estimées par le critic. - Loss actor : loss de policy gradient pondérée par les avantages. - Loss totale : somme des deux pertes. - Calcul des gradients et application via l’optimiseur Adam.7. Suivi de l’apprentissage
- Affichage du score total (récompense cumulée) et de la perte (loss) à chaque épisode.