Apprentissage par renforcement
Processus décisionnel Markovien (MDP)
En machine learning, on considère qu'il existe trois catégories d'apprentissages :
- L'apprentissage supervisé : Comme dans le cas des réseaux de neurones, la machine doit apprendre les relations
qu'il
existe entre des entrées $x$ et des sorties $y$. Des exemples exprimant ces relations lui sont fournies par un oracle.
- L'apprentissage non-supervisé : La machine doit apprendre seule la structure dans un paquet de données qui lui est
fourni. Il n'y a pas d'oracle. C'est le Graal de l'apprentissage automatique.
-
L'apprentissage par renforcement : Une machine prend une suite décisions (apprentissage sequentiel)
et expérimente un environnement. Un oracle lui
donne un faible retour sur ses actions.
L'apprentissage par renforcement introduit trois problématiques :
- Apprentissage par Essais-Erreurs : La machine est obligée d'agir pour apprendre;
- Dilemme Exploration vs Exploitation : A quel moment croit-on avoir trouvé la stratégie gagnante
(la séquence d'actions) qui mène au meilleur retour de l'oracle ? Comment savoir si l'on doit encore explorer ?
- Récompenses Retardées : Les fruits d'une action peuvent être retardés... Comment sacrifier des gains à court
terme pour privilégier des gains à long terme ?
L'apprentissage par renforcement peut être utilisé dans des simulations ou des jeux (robot dans un labyrinthe, échecs, Go, ...)
mais
aussi dans des situations humaines très concrètes (exploration spatiale, secours dans les décombres, comportement en milieu
hostile, ...).
Pacman est dans un environnement hostile, il y a des fantômes, des récompenses intermédiaires
(manger les monstres, les points) et une récompense ultime (finir le niveau)
Pour modéliser un problème dans une configuration de renforcement, on utilise les processus décisionnels markoviens (Markov Decision Process, MDP).
Un MDP est un quadruplet $\{ S, A, T, R \}$ définissant :
- $S$ l'espace des états ;
- $A$ l'espace des actions ;
- $T$ est l'axe temporel ;
- $R$ une fonction de récompense ;
$P$ l'espace des transitions
Le but de l'agent est de maximiser sa récompense, nous pouvons définir la récompense cumulée comme suit :
$$R_t = r_{t+1} + r_{t+2} + ... + r_T = \sum_{i = t + 1}^{T} r_i$$
Le gain est le début de la vision à long terme : supposez que vous soyez dans un labyrinthe à un instant $t$ et que 5
actions plus tard vous trouviez la sortie et recevez alors la récompense de $1$. Il faut récompenser l'état $t$ qui a fait partie de
la séquence de la victoire. Il serait donc injuste de lui donner $0$ comme récompense, mais aussi sur-évalué de lui donner 1 (comme le
dernier coup qui a donné la victoire). On peut alors définir un gain cumulé pondéré :
$$R_t = r_{t+1} + \gamma \; r_{t+2} + \gamma^2 \; r_{t+3} + ... + \gamma^{T-t+1} \; r_T = \sum_{k = 0}^{\inf} \gamma^k \; r_{t+k+1}$$
Pour maximiser nos gains cumulés pondérés, on doit trouver la stratégie (ou politique) $\pi$.
Définition : La politique ou stratégie $\pi_t$ de l'agent à l'instant $t$ est une
application de $S$ dans A qui définit le comportement de l'apprenant (mapping entre situation et
action). La politique ou stratégie optimale $\pi^*$ pour un MDP donné est une politique qui maximise le gain.
Pour trouver une bonne politique, il faut disposer d’une fonction d'évaluation locale du gain à
long terme espéré :
$$V^\pi(s) = \mathbb{E}^\pi [\sum_{k=0}^\infty \gamma^k r_{t+k+1} | s_t = s]$$
où $V^\pi(s)$ peut être défini comme le gain moyen espéré en partant de $s$ et en suivant la
politique $\pi$. Elle est appelée fonction de valeur. Le but est donc de maximiser cette fonction de valeur.
Principe : Principe d'optimalité de Bellman (1955) : une sous-trajectoire d'une trajectoire optimale est
elle-même optimale pour la fonction d'objectif restreinte aux
trajectoires ayant pour origine celle de cette sous-trajectoire.
Ce principe permet une méthode de résolution ascendante, qui détermine une solution optimale pour un problème à partir des solutions de tous les sous-problèmes.
Selon le principe d'optimalité ci-dessus, nous pouvons réécrire la fonction de valeur optimale :
$$V^*(s)=\max _{a \in A}\left(R(s, a) + \gamma \; V^*\left(s^{\prime}\right)\right)\tag{1}$$
c'est-à-dire que dans l'état $s$, on trouve l'action $a$ qui maximise le gain courant et les futurs gains dans $s^{\prime}$ (qui eux aussi sont optimaux). On en extrait la politique optimale $\pi^*$ :
$$\pi^*(s)=\text{arg max} _{a}\left(R(s, a) + \gamma \; V^*\left(s^{\prime}\right)\right)\tag{2}$$
Seulement, la réalité n'est pas un monde parfait : elle est chaotique et complexe. Lorsqu'un robot prend une action $a$ dans l'état $s$,
qui peut garantir qu'il arrivera réellement dans un état $s^\prime$ bien déterminé ? Cependant, on peut donner un degré de confiance avec
lequel on pense que le robot arrivera dans $s^\prime$. Nous définissons une matrice de transition $P\left(s, a, s^{\prime}\right)$ qui
dicte la probabilité d'atterrir dans l'état $s^\prime$ après avoir pris l'action $a$ dans l'état $s$. La fonction de valeur optimale devient :
$$
V^*(s)=\max _{a \in A}\left(R(s, a) + \gamma \sum_{s^{\prime}} P\left(s, a, s^{\prime}\right) V^*\left(s^{\prime}\right)\right) \tag{3}
$$
Propriété : Propriété de Markov : la distribution conditionnelle de probabilité des états futurs, étant donnés les états passés et l'état présent, ne dépend en fait que de l'état présent et non pas des états passés (absence de « mémoire »). Un processus qui possède cette propriété est appelé processus de Markov. Nous voyons effectivement qu'aucune information passée n'intervient dans l'équation 3.
Programmation dynamique : Itération de la valeur
Pour trouver cette fonction de valeur optimale, et donc la politique optimale, nous allons utiliser l'algorithme d'itération de la valeur :
Algorithme d'itération de la valeur
Initialiser $V_0$
$n \leftarrow 0$
Tant que $||V_{n+1} - V|| > \epsilon $ faire
Pour $s \in S$ faire
$V_{n+1}(s)=\max _{a}\left(R(s, a) + \gamma \sum_{s^{\prime}} P\left(s, a, s^{\prime}\right) V_{n}\left(s^{\prime}\right)\right)$
Fin pour
$n \leftarrow n+1$
Fin tant que
Pour $s \in S$ faire
$\pi^*(s)=\text{arg max} _{a}\left(R(s, a) + \gamma \; V^*\left(s^{\prime}\right)\right)$
Fin pour
Retourner $V_n, \pi$
L'algorithme itère l'équation (3) jusqu'à convergence, c'est-à-dire quand plus aucune mise à jour de fonction de la valeur n'est supérieure au seuil $\epsilon$.
Exercice : Nous allons résoudre l'exercice classique du Gridworld. L'environnement se repésente comme suit :
Un déplacement engendre une reward de -1 et arriver dans un état terminal, en gris, donne une reward de 0 et termine l'épisode. Pour maximiser sa récompense, il faut donc arriver au plus vite dans un état terminal.
--2019-08-14 07:54:32-- https://jbdel.github.io/teaching /nn/ressources/rl/lib/envs/gridworld.py
Resolving jbdel.github.io (jbdel.github.io)... 185.199.111.153, 185.199.109.153, 185.199.110.153, ...
Connecting to jbdel.github.io (jbdel.github.io)|185.199.111.153|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 3850 (3.8K) [application/octet-stream]
Saving to: ‘gridworld.py’
gridworld.py 100%[===================>] 3.76K --.-KB/s in 0s
2019-08-14 07:54:32 (97.2 MB/s) - ‘gridworld.py’ saved [3850/3850]
T o o o
o o o o
o o o o
x o o T
Le grid contient deux états terminaux : un à la case 0, et un à la case 15. Le "x" indique la position de l'agent, mais ne sera pas utilisé pour cet exercice.
Le grid est codé de telle manière que l'on reçoit une
récompense de 0 si on arrive dans un terminal et qu'on y réalise n'importe quelle action. L'épisode est alors terminé. Chaque autre action donne une récompense de -1. Le gridworld dispose d'une matrice $P$ qui prend en entrée un état $s$ (une case du grid) et une action $a$ et retourne les différentes valeurs associées à cet état-action.
[(1.0, 0, 0.0, True)]
[(1.0, 9, -1.0, False)]
Ici, env.P[13][0] comprend les valeurs de l'état-action suivant : "être à la case 13 et aller vers le haut". La reward est de -1.0, la probabilité de passer dans la case 9 est de 1 et l'épisode n'est pas terminé (is_done vaut "False"). De même pour env.P[0][2], l'état-action est le suivant : "être dans l'état terminal et aller vers le bas". La reward est de 0.0 et l'épisode est terminé (is_done vaut "True"). En vous basant sur l'algorithme d'itération de valeur, complétez le code ci-dessous. Vous devriez obtenir exactement les mêmes valeurs que celles imprimées.
Reshaped Grid Policy (0=up, 1=right, 2=down, 3=left):
[[0 3 3 2]
[0 0 0 2]
[0 0 1 2]
[0 1 1 0]]
Value Function:
[ 0. -1. -1.99 -2.9701 -1. -1.99 -2.9701 -1.99 -1.99
-2.9701 -1.99 -1. -2.9701 -1.99 -1. 0. ]
Reshaped Grid Value Function:
[[ 0. -1. -1.99 -2.9701]
[-1. -1.99 -2.9701 -1.99 ]
[-1.99 -2.9701 -1.99 -1. ]
[-2.9701 -1.99 -1. 0. ]]
Cet algorithme itératif n'est possible que lorsque l'environnement est connu. Ici, la fonction de transition et de récompense vous était directement accessible. Nous ne pouvons pas encore proprement parler d'apprentissage par renforcement où l'agent apprend par essai-erreur. D'ailleurs, vous n'avez pas utilisé l'agent dans l'exercice du labyrinthe pour trouver la politique optimale : vous avez simplement itéré sur les états.
Algorithme model-free : Q-learning
Nous comprenons que la fonction $V^*$ donne la valeur optimale d'un état selon la politique $\pi^*$. Cette valeur découle d'une agrégation
des retours de récompenses sur chaque possibilité d'actions dans l'état $s$. Un des sous-problèmes est donc de se préoccuper de la valeur
d'une action particulière dans un état. Pour ce faire, on introduit la fonction action-état $Q$ :
$$Q^\pi(s, a) = \mathbb{E}^\pi \{\sum_{k=0}^\infty \gamma^k r_{t+k+1} | s_t = s, a_t=a\}$$
qui correspond au retour espéré pour l'état $s$ en prenant l'action $a$, puis en suivant la politique $\pi$. Selon le principe d'optimalité, on peut réécrire $Q$ de cette manière :
$$Q(s, a)= R(s, a) + \gamma \sum_{s^{\prime}}\left(P\left(s, a, s^{\prime}\right) V\left(s^{\prime}\right)\right) \tag{4} $$
L'équation (4) est simplement l'équation (3) pour un $a$ explicite (on enlève donc juste le $\max$). Avec l'équation (3) et (4), on peut réécrire $V^{*}$ :
$$V^{*}(s)= \max_{a \in A} Q^*(s,a) \tag{5}$$
Et remplacer directement $V^*$ dans $Q^*(s, a)$:
$$Q^*(s, a)=R(s, a) + \gamma \sum_{s^{\prime}}\left(P\left(s, a, s^{\prime}\right) \max _{a^{\prime}} Q^*\left(s^{\prime},
a^{\prime}\right)\right)\tag{6}$$
Grâce à cette dernière equation (6), l'agent dispose désormais d'une fonction où l'action est explicite. Il peut désormais expérimenter un environnement en interagissant avec celui-ci.
Il est possible d'apprendre $Q$ par échantillonnage (traditionnellement appelée Méthode de Monte-Carlo):
- Choix aléatoire d'un état $s \in S$
- Choix aléatoire d'un état $a \in a$ (exploration)
- Suivre la stratégie $\pi$ et observer la récompense $r$
- Faire cela une infinité de fois et moyenner $Q^\pi(s, a) = \mathbb{E}^\pi \{r_t\}$
- Améliorer la politique $\pi(s)=\text{arg max} _{a}Q^{\pi}(s, a)$
Problème : il faut attendre la fin de l’interaction pour améliorer la politique. En fonction de la complexité du modèle que l'on essaie d'apprendre, trouver une bonne politique peut prendre trop de temps.
En 1988, Richard Sutton (considéré comme le père de l'apprentissage par renforcement) propose une nouvelle classe de méthodes appliquées à l'exploration "model-free" appelée "apprentissage par différence temporelle" (ou temporal difference learning). Il définit son concept comme suit :
Suppose you wish to predict the weather for Saturday, and you have some model that predicts Saturday's weather, given the weather of each day in the week. In the standard case, you would wait until Saturday and then adjust all your models. However, when it is, for example, Friday, you should have a pretty good idea of what the weather would be on Saturday – and thus be able to change, say, Saturday's model before Saturday arrives.
(from https://web.archive.org/web/20170808062001/http://www.incompleteideas.net/sutton/papers/sutton-88-with-erratum.pdf)
L'intuition est la suivante : il est possible de mettre à jour un modèle prédictif en cours de route (car les prédictions proches de la dernière prédiction sont plus précises et donnent déjà un retour sur les prédictions précédentes), plutôt que d'attendre le retour ou la récompense finale avant pour mettre à jour l'entièreté du modèle. Prenez un autre exemple : un coach sportif. En début de saison, il affine la stratégie de son équipe en fonction des résultats de la saison précédente, des transferts, des conditions météorologiques, de la santé de ses joueurs, etc. Ses trois premiers matchs sont une catastrophe : son équipe essuie trois défaites. Attendra-t-il la fin de la saison pour effectuer des révisions dans sa stratégie ?
La Q-learning est un algorithme de différence temporelle et peut se décrire comme suit :
$$Q^{new}(s_{t},a_{t}) \leftarrow \underbrace{Q(s_{t},a_{t})}_{\text{old value}} + \underbrace{\alpha}_{\text{learning rate}} \cdot \overbrace{ \bigg( \underbrace{r_{t}}_{\text{récompense}} + \underbrace{\gamma}_{\text{discount factor}} \cdot \underbrace{\max_{a}Q(s_{t+1}, a)}_{\text{estimation valeur optimale}} - Q(s_{t},a_{t}) \bigg)}^{\text{difference temporelle}} $$
Voici le pseudo-code associé :
Algorithme Q-learning
Pour $n \leftarrow 0$ jusqu'à $N_{\text{tot}}$ faire
$s \leftarrow $ ChoixEtat
Jusqu'à FinEpisode
$a \leftarrow$ ChoixAction$(s)$
$s^{\prime}, r \leftarrow$ Simuler$(s, a)$
$\delta \leftarrow r + \gamma \cdot \max_b Q(s^{\prime}, b)-Q(s,a)$
$Q(s,a) \leftarrow Q(s,a) + \alpha \cdot \delta$
$s \leftarrow s^{\prime}$
Fin Jusqu'à
$n \leftarrow n+1$
Fin pour
Retourner $Q_{N_{\text{tot}}}$
Exercice : Nous allons résoudre l'exercice classique de la promenade le long de la falaise. L'environnement se représente comme suit :
Un déplacement engendre une reward de -1 et tomber de la falaise une reward de -100. Il y a donc un chemin optimal le long de la falaise qui donne une reward de -13 et un chemin plus "safe" qui donne une reward de -17. Nous allons réaliser en Q-learning deux versions de l'exercice. Pour la première, les conditions météorologiques sont parfaites : on doit converger vers le chemin optimal. Pour la seconde, des rafales de vent sont présentes : pour chaque action, il y a 20% de chances que celles-ci soit ignorées et nous somme déplacés vers le bas (vers la falaise).
Nous commençons par la version sans le vent :
o o o o o o o o o o o o
o o o o o o o o o o o o
o o o o o o o o o o o o
x C C C C C C C C C C T
La position de l'agent est représentée par "x", la falaise par "C" et l'état terminal par "T". Vous pouvez désormais utiliser la méthode step() pour expérimenter l'environnement :
(24, -1.0, False, {'prob': 1.0})
o o o o o o o o o o o o
o o o o o o o o o o o o
x o o o o o o o o o o o
o C C C C C C C C C C T
(25, -1.0, False, {'prob': 1.0})
o o o o o o o o o o o o
o o o o o o o o o o o o
o x o o o o o o o o o o
o C C C C C C C C C C T
(26, -1.0, False, {'prob': 1.0})
o o o o o o o o o o o o
o o o o o o o o o o o o
o o x o o o o o o o o o
o C C C C C C C C C C T
(38, -100.0, True, {'prob': 1.0})
o o o o o o o o o o o o
o o o o o o o o o o o o
o o o o o o o o o o o o
o C x C C C C C C C C T
La fonction ci-dessous définit une politique d'exploration-exploitation pour l'agent. A chaque décision, on choisit la meilleure action avec une probabilité de $1-\epsilon$, sinon on en choisit une autre aléatoirement. Cette méthode est déjà complétée.
Voici la classe à remplir selon l'algorithme décrit ci-dessus. Vous devriez avoir des résultats équivalent à ceux imprimés.
Episode 500/500.Reshaped Grid Policy (0=up, 1=right, 2=down, 3=left):
[[3 1 1 1 1 1 1 1 1 1 2 2]
[0 1 2 1 1 1 2 2 2 2 2 2]
[1 1 1 1 1 1 1 1 1 1 1 2]
[0 0 0 0 0 0 0 0 0 0 0 0]]
Nous remarquons que l'algorithme Q-learning a convergé vers le chemin "optimal". Nous pouvons vérifier la convergence avec les graphiques suivants.
Out[0]:
(<Figure size 360x216 with 1 Axes>, <Figure size 360x216 with 1 Axes>)
Vous pouvez désormais ajouter du vent en utilisant l'attribut "wind=True". Nous remarquons qu'aller vers la droite, en bord de falaise, est risqué. Aller vers le haut nous garantit une sécurité.
o o o o o o o o o o o o
o o o o o o o o o o o o
o x o o o o o o o o o o
o C C C C C C C C C C T
UP [(1.0, 13, -1.0, False)]
RIGHT [(0.8, 26, -1.0, False), (0.2, 37, -100.0, True)]
Si votre algorithme est correct, vous devriez converger pour cet exercice vers le "safer path".
Episode 2000/2000.Reshaped Grid Policy (0=up, 1=right, 2=down, 3=left):
[[1 1 1 1 1 1 1 1 1 1 1 2]
[0 1 0 1 1 0 0 0 1 1 1 2]
[0 0 0 0 0 0 0 0 0 0 0 2]
[0 0 0 0 0 0 0 0 0 0 0 0]]
Propriété : Fléau de la dimension : Lorsque le nombre de dimensions augmente, le volume de l'espace croît rapidement si bien que les données se retrouvent « isolées » et deviennent éparses. Cela est problématique pour les méthodes nécessitant un nombre significatif de données pour être valides, les rendant alors peu efficaces voire inopérantes.
Notre algorithme de Q-learning est concerné : échantilloner $Q(s,a)$ peut devenir une tâche insurmontable pour des environnements de grandes dimensions. Par exemple, aux échecs, $Q(s,a)$ est de taille
$7\times10^{13}$ après seulement dix coups.
Nous comprenons que si il y a un nombre restreint d'interactions, la propagation de l'information peut ne pas avoir atteint tous les états. Comment généraliser ce qui a déjà été appris dans des situations semblables lorsqu'on rencontre de nouveaux états ? Il est possible d'approximer des fonctions de valeurs avec des réseaux de neurones.