Cadre de base de l'apprentissage par renforcement

Imaginez que vous enseignez à un chiot à apprendre la commande "assis". Vous ne lui diriez pas directement comment chaque muscle doit bouger dans le mouvement pour s'asseoir ; à la place, vous feriez ceci :

  1. Vous donnez la commande "assis".
  2. Le chiot essaie une action (il peut s'asseoir, se coucher ou tourner en rond).
  3. S'il s'assoit, vous lui donnez immédiatement une friandise en récompense.
  4. S’il se trompe, vous ne donnez aucune récompense, ou vous donnez un léger signal de « ce n’est pas ça ».
  5. Après de nombreuses tentatives, le chiot comprend peu à peu : après avoir entendu « assis », exécuter l’action de s’asseoir peut rapporter une friandise. Il apprend donc l’ordre.

L’apprentissage par renforcementconsiste à laisser un ordinateur (ou un agent) apprendre, comme ce chiot, comment prendre une série de décisions pour atteindre un objectif à long terme en interagissant avec l’environnement et en se fondant sur les récompenses ou punitions reçues.

Comparé àl’apprentissage superviséfamilier (un « enseignant » avec des réponses standard) et àl’apprentissage non supervisé(recherche de la structure interne des données), il est fondamentalement différent. L’apprentissage par renforcement estun apprentissage par l’expérience, et son cœur estl’essai et l’erreuretla récompense différée。


Éléments essentiels de l’apprentissage par renforcement

Pour formaliser ce processus d’apprentissage, nous introduisons plusieurs concepts clés qui constituent ensemble le cadre de base de l’apprentissage par renforcement.

Agent et environnement

C’est la relation interactive la plus élémentaire de l’apprentissage par renforcement.

  • Agent :Il est le sujet de l’apprentissage, l’entité qui prend les décisions. Dans l’exemple ci-dessus, le chiot est l’agent. Dans un ordinateur, il peut s’agir d’un algorithme, d’un programme ou d’un robot.
  • Environnement :Il est le monde extérieur dans lequel l’agent existe et avec lequel il interagit. Pour le chiot, l’environnement, c’est vous, les friandises, le sol et toutes les choses extérieures. L’environnement reçoit les actions de l’agent et fournit de nouveaux états et récompenses.

Leur relation forme une boucle continue :l’agent observe l’environnement -> effectue une action -> l’environnement renvoie un nouvel état et une récompense -> l’agent observe à nouveau...

État, Action et Récompense

Ce sont trois éléments d'information clés décrivant chaque interaction.

  • État :À un moment donné, une description complète de la situation de l'environnement. Par exemple, dans l'exemple d'entraînement du chiot, l'état peut inclure : le chiot est debout, vous avez une friandise dans la main, et vous venez de dire « sit ». L'état est la base des décisions de l'agent.
  • Action :Les choix que l'agent peut faire dans un certain état. Pour le chiot, l'ensemble d'actions pourrait être {sit, lie down, stand, spin...}.
  • Récompense :Un signal scalaire que l'environnement renvoie à l'agent après que l'agent a effectué une action. Il définitce qui est bon et ce qui est mauvais. La récompense est la seule boussole pour l'apprentissage de l'agent. Donner une friandise au chiot est une récompense positive (+1) ; dire « ce n'est pas bien » peut être considéré comme une légère récompense négative (-0.1).

Politique

Une politiqueest le cerveau ou la règle de comportement de l'agent. Elle définit quelle action l'agent doit entreprendre dans tout état donné.

Une politique peut être une simple fonction de table de correspondance, ou un réseau de neurones profond complexe. L'objectif ultime de l'apprentissage par renforcement est de trouver unepolitique optimale, telle que larécompense cumulative à long terme obtenue par l'agent depuis l'environnement soit maximisée。

  • .Exemple : une politique simple pourrait être : si l'état est « entendre la commande sit », alors choisir l'action sit avec une probabilité de 90% et choisir d'autres actions avec une probabilité de 10%.

Fonction de valeur

Les récompenses indiquent à l'agentle bien ou le mal immédiat de l'actionactuelle, mais l'agent doit se soucier davantage desretoursà long terme.Une fonction de valeurest l'outil utilisé pour mesurer ce retour à long terme.

Elle répond à la question : en partant de l'état actuel et en suivant une certaine politique jusqu'au bout, combien de récompense totale puis-jeespérerobtenir ?

  • Fonction de valeur d'état V(s): mesure la valeur à long terme de suivre la politique actuelle dans l'étatss.
  • Fonction de valeur d'action Q(s, a): mesure, dans l'étatss,après avoir exécuté une action spécifiqueaa, la valeur à long terme de suivre ensuite la politique actuelle. Elle est plus couramment utilisée que la fonction de valeur d'état car elle peut directement guider la sélection des actions.

Pourquoi avons-nous besoin d'une fonction de valeur ?Imaginez une partie d'échecs. Capturer un pion adverse donne une petite récompense immédiate, mais cela peut mener à être maté dix coups plus tard et à recevoir une énorme récompense négative. Par le calcul et l'estimation, la fonction de valeur peut aider l'agent à éviter ce genre de comportement qui convoite de petits gains et perd toute la partie.


Processus d'interaction central : processus de décision markovien

Les problèmes d'apprentissage par renforcement sont généralement modélisés comme unprocessus de décision markovien (MDP). Ce nom semble complexe, mais ce n'est en fait qu'un cadre standard qui organise les éléments mentionnés ci-dessus sous forme mathématique et décrit l'interaction entre l'agent et l'environnement.

L'idée centrale du MDP est :L'état suivant et la récompense dépendent uniquement de l'état actuel et de l'action actuelle entreprise, et sont indépendants de l'historique précédent(c'est-à-dire la propriété de Markov).

Un cycle complet d'interaction MDP se déroule comme suit :

  1. Au pas de tempstt, l'environnement se trouve dans l'étatS_t。
  2. S_t. L'agent observe cet état.
  3. L'agent, selon sa politiqueππ, sélectionne une actionA_t。
  4. A_t. L'environnement reçoit cette action.
  5. L'environnement, selon ses règles dynamiques internes, effectue une transition vers l'état suivantS_{t+1}S_{t+1}, et produit une récompense scalaireR_{t+1}R_{t+1}, qui est renvoyée à l'agent.
  6. Le pas de temps avance (t = t+1t = t+1), et une nouvelle boucle commence.

L'objectif de l'agent est, en expérimentant continuellement cette boucle, d'apprendre une politiqueπ*π, telle qu'en partant de n'importe quel état initial, lavaleur attendue de la récompense cumulée (c.-à-d., le retour) soit maximisée。


Un exemple de code simple : Monde en grille

Utilisons un exemple classique de monde en grille pour rendre ces concepts concrets. Supposons qu'il existe une grille 4x4. L'agent part du point de départSS, avec pour objectif d'atteindre le point terminalGT. Atteindre un obstacle#X signifie un échec, et chaque étape a une petite pénalité (pour encourager à atteindre la fin le plus tôt possible).

S . . .
. # . .
. . # .
. . . G
  • État: les coordonnées de chaque cellule de la grille, telles que (0,0), (0,1)... (3,3). Il y a 16 états au total.
  • Action: {up, down, left, right}.
  • Récompense:
    • : Atteindre T : +10G: +10
    • Toucher X#ou sortir des limites : -5
    • Autres déplacements normaux : -0.1 (encourage des chemins efficaces)
  • Politique: Nous devons apprendre une table qui enregistre, dans chaque état (cellule de grille), quelle direction prendre.

Ci-dessous se trouve une démonstration de pseudo-code extrêmement simplifiée de Q-learning (un algorithme classique d'apprentissage par renforcement), utilisée pour apprendre le chemin optimal dans ce monde en grille.

Exemple

import numpy as np
import random
from typing import Dict, List, Tuple

# ====================== 1. Simulation de l'environnement (monde en grille) ======================
class GridWorldEnv:
    """Un environnement de grille simple pour démontrer Q-Learning"""
    def __init__(self, grid_size: Tuple[int, int] = (5, 5),
                 start_pos: Tuple[int, int] = (0, 0),
                 goal_pos: Tuple[int, int] = (4, 4),
                 obstacle_pos: List[Tuple[int, int]] = [(1, 1), (2, 2), (3, 1)]):
        self.grid_size = grid_size
        self.start_pos = start_pos
        self.goal_pos = goal_pos
        self.obstacle_pos = obstacle_pos
        self.current_pos = start_pos
       
        # Définitions des actions : 0-haut, 1-bas, 2-gauche, 3-droite
        self.actions = ['up', 'down', 'left', 'right']
        self.num_actions = len(self.actions)
       
    def reset(self) -> int:
        """Réinitialiser l'environnement et renvoyer l'index de l'état initial"""
        self.current_pos = self.start_pos
        return self.pos_to_state(self.current_pos)
   
    def pos_to_state(self, pos: Tuple[int, int]) -> int:
        """Convertir une position de coordonnées en index d'état"""
        return pos[0] * self.grid_size[1] + pos[1]
   
    def state_to_pos(self, state: int) -> Tuple[int, int]:
        """Convertir l'index d'état en position de coordonnées"""
        return (state // self.grid_size[1], state % self.grid_size[1])
   
    def random_action(self) -> int:
        """Choisir aléatoirement une action (exploration)"""
        return random.randint(0, self.num_actions - 1)
   
    def action_to_direction(self, action: int) -> str:
        """Convertir l'indice d'action en nom de direction"""
        return self.actions[action]
   
    def step(self, action: int) -> Tuple[int, float, bool]:
        """
Exécuter l'action, renvoyer (next_state, reward, done)
Point d'optimisation : corriger le bug où la récompense d'obstacle ne peut pas être déclenchée, simplifier la logique de décision
        """

        x, y = self.current_pos
       
        # Mettre à jour la position en fonction de l'action
        if action == 0:  # haut
            x = max(0, x - 1)
        elif action == 1:  # bas
            x = min(self.grid_size[0] - 1, x + 1)
        elif action == 2:  # gauche
            y = max(0, y - 1)
        elif action == 3:  # droite
            y = min(self.grid_size[1] - 1, y + 1)
       
        # Vérifier si un obstacle est heurté (correction principale : d'abord enregistrer si l'obstacle est heurté, puis gérer la position)
        new_pos = (x, y)
        hit_obstacle = False  # Marquer si un obstacle est heurté
        if new_pos in self.obstacle_pos:
            hit_obstacle = True  # Enregistrer l'état de collision avec un obstacle
            new_pos = self.current_pos  # Collision avec un obstacle, position inchangée
       
        self.current_pos = new_pos
        next_state = self.pos_to_state(new_pos)
       
        # Calculer la récompense (d'après hit_obstacle enregistré à l'avance, corriger la contradiction dans la logique d'origine)
        if new_pos == self.goal_pos:
            reward = 100.0  # Objectif atteint, récompense importante
            done = True
        elif hit_obstacle:  # D'après l'indicateur, et non le new_pos modifié
            reward = -50.0  # Collision avec un obstacle, pénalité
            done = False
        else:
            reward = -1.0  # Petite pénalité pour chaque étape, encourageant à atteindre l'objectif rapidement
            done = False
       
        return next_state, reward, done

# ====================== 2. Programme principal Q-Learning ======================
if __name__ == "__main__":
    # Optimisation 1: Fixer la graine aléatoire pour garantir des résultats d'expérience reproductibles
    random_seed = 42
    random.seed(random_seed)
    np.random.seed(random_seed)
   
    # Initialiser l'environnement
    env = GridWorldEnv(
        grid_size=(5, 5),          # grille 5x5
        start_pos=(0, 0),          # point de départ
        goal_pos=(4, 4),           # point d'arrivée
        obstacle_pos=[(1,1), (2,2), (3,1)]  # positions des obstacles
    )
   
    # Calculer le nombre d'états
    num_states = env.grid_size[0] * env.grid_size[1]
    num_actions = env.num_actions
   
    # Initialiser la table Q (fonction action-valeur) avec la forme [num_states, num_actions]
    Q_table = np.zeros([num_states, num_actions])
   
    # Définir les hyperparamètres
    learning_rate = 0.1       # taux d'apprentissage
    discount_factor = 0.9     # facteur d'actualisation
    epsilon = 0.1             # taux d'exploration
    total_episodes = 1000     # nombre d'épisodes d'entraînement
   
    # Processus d'entraînement
    for episode in range(total_episodes):
        state = env.reset()    # Réinitialiser l'environnement au point de départ, obtenir l'état initial S
        done = False           # Indique si cet épisode se termine
        total_reward = 0       # Enregistre la récompense totale pour cet épisode
       
        while not done:
            # 1. Politique ε-greedy pour la sélection des actions
            if random.uniform(0, 1) < epsilon:
                action = env.random_action()  # Exploration : choisir aléatoirement une action
            else:
                # Exploitation : choisir l'action ayant la valeur Q la plus élevée, gérer les égalités
                q_values = Q_table[state]
                max_q = np.max(q_values)
                best_actions = np.where(q_values == max_q)[0]
                action = random.choice(best_actions)  # Choisir aléatoirement une action en cas d'égalité
           
            # 2. Exécuter l'action et interagir avec l'environnement
            next_state, reward, done = env.step(action)
            total_reward += reward
           
            # 3. Mettre à jour la table Q (cœur : formule du Q-Learning)
            # Q(S, A) = Q(S, A) + α * [ R + γ * max(Q(S', a')) - Q(S, A) ]
            old_value = Q_table[state, action]
            next_max = np.max(Q_table[next_state])  # Valeur Q maximale de l'état suivant
           
            # Calculer la valeur Q cible
            target = reward + discount_factor * next_max
            # Mettre à jour la valeur Q
            new_value = old_value + learning_rate * (target - old_value)
            Q_table[state, action] = new_value
           
            # 4. Passer à l'état suivant
            state = next_state
       
        # Afficher la progression de l'entraînement toutes les 100 épisodes
        if (episode + 1) % 100 == 0:
            print(f"Épisode {episode + 1}/{total_episodes}, Récompense totale : {total_reward:.1f}")
   
    # ====================== 3. Extraire la politique optimale (format d'affichage optimisé, plus intuitif) ======================
    policy: Dict[int, str] = {}
    print("\n=== Politique optimale après apprentissage (disposition en grille) ===")
   
    # Optimisation 2 : Afficher sous forme de grille pour visualiser intuitivement la politique de toute la grille
    grid_rows, grid_cols = env.grid_size
    for row in range(grid_rows):
        row_str = []
        for col in range(grid_cols):
            pos = (row, col)
            state = env.pos_to_state(pos)
            if pos in env.obstacle_pos:
                row_str.append(" Obstacle ")
            elif pos == env.obstacle_pos:
                row_str.append(" ")
            elif pos == env.start:
                # Marquer aussi le départ et son
                best_action_idx = np.argmax(Q_table[state])
                best_action = env.action_to_direction(best_action_idx)
                row_str.append(f" Départ({best_action})")
            else:
                best_action_idx = np.argmax(Q_table[state])
                best_action = env.action_to_direction(best_action_idx)
                policy[state] = best_action
                row_str.append(f" {best_action} ")
        print("|".join(row_str))
   
    # ====================== 4. Test de la politique optimale ======================
    print("\n=== Test de la politique optimale ===")
    state = env.reset()
    done = False
    steps = 0
    path = [env.state_to_pos(state)]
   
    while not done and steps < 50:  # Maximum 50 étapes pour éviter les boucles infinies
        best_action_idx = np.argmax(Q_table[state])
        next_state, reward, done = env.step(best_action_idx)
        current_pos = env.state_to_pos(next_state)
        path.append(current_pos)
        state = next_state
        steps += 1
   
    print(f"Chemin: {path}")
    print(f"Étapes pour atteindre l'objectif : {steps}")
    print(f"Objectif atteint : {env.current_pos == env.goal_pos}")

Explication de code:

  • Q_tableest la fonction centrale de valeur d'action, avec une forme[number of states, number of actions](dans l'exemple, 25×4, correspondant aux 25 états de la grille 5×5 et aux 4 actions haut/bas/gauche/droite).Q_table[s, a]Désigne, pour l'états(l'indice de la position dans la grille), la valeur à long terme de l'exécution de l'actiona(0-3 correspondent à haut/bas/gauche/droite), toutes initialement à 0, mises à jour étape par étape au fil de l'entraînement.
  • env.step(action)Simule la logique d'interaction centrale du processus de décision markovien (MDP) : après avoir saisi un indice d'action, il met d'abord à jour la position de l'agent dans la grille (si un obstacle est heurté, la position reste inchangée), puis renvoie un triplet :(next_state, reward, done)——next_stateest l'indice du nouvel état,rewardest la récompense différenciée (objectif +100, obstacle -50, chaque étape -1),doneindique si l'objectif a été atteint (fin de cet épisode).
  • La formule de mise à jour centrale du Q-LearningQ(S,A) = Q(S,A) + α * [R + γ * max(Q(S', a')) - Q(S,A)]est décomposé et implémenté dans le code : on récupère d'abord la valeur Q actuelleold_value, puis calculer la valeur Q maximale de l'état suivantnext_max, puis calculer la valeur cibletarget = 奖励 + 折扣因子 × 下一状态最大Q值, et enfin utiliser le taux d'apprentissageαpour combiner l'ancienne valeur et la valeur cible, obtenir la valeur Q mise à jour, et ainsi corriger itérativement la valeur d'action.
  • epsilon(taux d'exploration) équilibre « exploitation » et « exploration » via la politique ε-greedy : avecepsilonprobabilité, choisir aléatoirement une action (explorer l'inconnu) ; avec1-epsilonprobabilité, choisir l'action avec la plus grande valeur Q dans l'état courant (exploiter l'optimum connu). Le code gère aussi le cas d'égalité des valeurs Q : si plusieurs actions ont la même valeur Q, l'une est choisie aléatoirement, évitant le verrouillage de politique causé par un choix fixe unique.
  • Le code implémente en outre une correspondance bidirectionnelle entre les états et les positions de la grille (pos_to_state/state_to_pos), la conversion entre les actions et les noms de direction (action_to_direction), ainsi que l'extraction et le test de la politique après l'entraînement : parcourir tous les états, prendre l'action avec la plus grande valeur Q dans chaque état comme politique optimale, et vérifier le chemin et le nombre d'étapes du point de départ au point d'arrivée selon cette politique.
Sortie :
Episode 100/1000, Total Reward: 93.0
Episode 200/1000, Total Reward: 90.0
Episode 300/1000, Total Reward: 92.0
Episode 400/1000, Total Reward: 90.0
Episode 500/1000, Total Reward: 93.0
Episode 600/1000, Total Reward: 93.0
Episode 700/1000, Total Reward: 91.0
Episode 800/1000, Total Reward: 93.0
Episode 900/1000, Total Reward: 93.0
Episode 1000/1000, Total Reward: 93.0

=== 学习完成后的最优策略 ===
位置 (0, 0): 最优动作 = right
位置 (0, 1): 最优动作 = right
位置 (0, 2): 最优动作 = down
位置 (0, 3): 最优动作 = down
位置 (0, 4): 最优动作 = down
位置 (1, 0): 最优动作 = up
位置 (1, 1): 最优动作 = 障碍物
位置 (1, 2): 最优动作 = right
位置 (1, 3): 最优动作 = down
位置 (1, 4): 最优动作 = left
位置 (2, 0): 最优动作 = down
位置 (2, 1): 最优动作 = down
位置 (2, 2): 最优动作 = 障碍物
位置 (2, 3): 最优动作 = down
位置 (2, 4): 最优动作 = down
位置 (3, 0): 最优动作 = down
位置 (3, 1): 最优动作 = 障碍物
位置 (3, 2): 最优动作 = right
位置 (3, 3): 最优动作 = right
位置 (3, 4): 最优动作 = down
位置 (4, 0): 最优动作 = right
位置 (4, 1): 最优动作 = right
位置 (4, 2): 最优动作 = right
位置 (4, 3): 最优动作 = right
位置 (4, 4): 最优动作 = 终点

=== 测试最优策略 ===
路径: [(0, 0), (0, 1), (0, 2), (1, 2), (1, 3), (2, 3), (3, 3), (3, 4), (4, 4)]
到达终点步数: 8
是否到达终点: True

Résumé et réflexion pratique

Le cadre de base de l'apprentissage par renforcement peut être résumé ainsi :L'agent interagit avec l'environnement selon un processus de décision markovien et, en fonction des signaux de récompense obtenus, optimise continuellement sa politique (généralement en apprenant et en mettant à jour les fonctions de valeur), avec pour objectif ultime de maximiser la récompense cumulée à long terme.

Concept Analogie Rôle dans l'apprentissage par renforcement
Agent Chiot en apprentissage / IA jouant aux échecs Le sujet décisionnel qui exécute l'algorithme d'apprentissage
Environnement Dresseur / Règles de l'échiquier Système externe qui fournit les états et le retour de récompense
State Posture du chiot / Position sur l'échiquier Base d'informations actuelle permettant à l'agent de prendre des décisions
Action S'asseoir / Déplacer une pièce Choix que l'agent peut faire
Récompense Friandise / Résultat de victoire ou de défaite Signal immédiat évaluant la qualité d'une action ; la boussole de l'apprentissage
Politique La réponse à l'ordre que le chiot a apprise Règle de correspondance des états vers les actions ; l'objectif de l'apprentissage
Fonction de valeur Évaluation à long terme de la situation Évalue la valeur à long terme d'un état ou d'une action ; c'est la base de l'optimisation de la politique
Autres extensions