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.

  1. 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.

  2. 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 :

 

θt+1=θt+αθlogπθ(st,at)δt\theta_{t+1} = \theta_t + \alpha \nabla_{\theta} \log \pi_{\theta}(s_t, a_t) \delta_t

Où :

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.