Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente | ||
| public:rl_tp3 [2019/01/15 23:52] – [Outils d'analyse] edauce | public:rl_tp3 [2019/01/16 10:03] (Version actuelle) – [Choix des politiques] edauce | ||
|---|---|---|---|
| Ligne 1: | Ligne 1: | ||
| + | ===== TP3 : Q-learning tabulaire===== | ||
| + | |||
| + | Dans ce TP nous allons mettre en œuvre un algorithme d' | ||
| + | |||
| + | **Rappel**: | ||
| + | |||
| + | On note : | ||
| + | $$Q(s_t, a_t) = E(\sum_{t' | ||
| + | la fonction de valeur sur les transitions d' | ||
| + | |||
| + | La fonction de valeur de la politique optimale obéit à l' | ||
| + | $$Q(s_t, a_t) = r_t + \gamma | ||
| + | |||
| + | Dans le cadre de l' | ||
| + | Soit $\tilde{\pi}$ cette politique non optimale et $s_{t+1}$ l' | ||
| + | $$\tilde{Q}(s_t, | ||
| + | |||
| + | Ainsi la valeur de la transition | ||
| + | |||
| + | Si les mêmes transitions sont visitées plusieurs fois, il est possible de comparer la valeur précédemment stockée et la nouvelle valeur. La différence entre les deux est appelée //erreur de prédiction//: | ||
| + | $$e_t = r_t + \gamma \max_{a' | ||
| + | |||
| + | La mise à jour du Q-learning repose sur un paramètre d' | ||
| + | $$\tilde{Q}(s_t, | ||
| + | |||
| + | |||
| + | ==== Algorithme ==== | ||
| + | |||
| + | Dans le cadre du Q-learning, il n'est pas nécessaire de conserver l' | ||
| + | |||
| + | < | ||
| + | Q <-- zeros(N_obs, | ||
| + | s <-- initialiser_environnement() | ||
| + | répéter: | ||
| + | a <-- choix_selon_politique(s) | ||
| + | s_prim, r <-- environnement_step(a) | ||
| + | max_Q_prim <-- max (Q[s_prim,: | ||
| + | err <-- r + GAMMA * max_Q_prim - Q[s, a] | ||
| + | Q[s, a] <-- Q[s, a] + ALPHA * err | ||
| + | s <-- s_prim | ||
| + | </ | ||
| + | |||
| + | Pour les environnements épisodiques, | ||
| + | < | ||
| + | Q <-- zeros(N_obs, | ||
| + | répéter: | ||
| + | s <-- initialiser_environnement() | ||
| + | répéter : | ||
| + | a <-- choix_selon_politique(s) | ||
| + | s_prim, r, fini <-- environnement_step(a) | ||
| + | max_Q_prim <-- max Q[s_prim,:] | ||
| + | si fini: | ||
| + | err <-- r - Q[s, a] | ||
| + | sinon: | ||
| + | err <-- r + GAMMA * max_Q_prim - Q[s, a] | ||
| + | Q[s, a] <-- Q[s, a] + ALPHA * err | ||
| + | s <-- s_prim | ||
| + | si fini : | ||
| + | sortir de la boucle | ||
| + | </ | ||
| + | ==== Classe agent ==== | ||
| + | |||
| + | La classe agent doit être la plus générique possible pour pouvoir être utilisée dans différents environnements. | ||
| + | |||
| + | On distingue ici deux cas de figure : | ||
| + | * environnement continu : lorsque l' | ||
| + | * environnement discret : le nombre d' | ||
| + | |||
| + | <code python> | ||
| + | import numpy as np | ||
| + | |||
| + | class Agent: | ||
| + | def __init__(self, | ||
| + | self.env = env | ||
| + | if type(env.observation_space) is gym.spaces.discrete.Discrete: | ||
| + | self.N_obs = env.observation_space.n | ||
| + | else: | ||
| + | dim = np.prod(env.observation_space.shape) | ||
| + | self.N_obs = 2**dim | ||
| + | self.N_act = env.action_space.n | ||
| + | self.Q = np.zeros((self.N_obs, | ||
| + | self.ALPHA = ALPHA | ||
| + | self.GAMMA = GAMMA | ||
| + | </ | ||
| + | |||
| + | <note tip> | ||
| + | '' | ||
| + | |||
| + | Les valeurs par défaut sont ici '' | ||
| + | </ | ||
| + | |||
| + | ==== Discrétisation ==== | ||
| + | |||
| + | Pour les premiers tests, nous reprenons l' | ||
| + | Le pendule inversé étant un environnement à états continus, il faut définir une discrétisation : | ||
| + | |||
| + | <code python> | ||
| + | def discretise(self, | ||
| + | if type(self.env.env) is gym.envs.classic_control.cartpole.CartPoleEnv: | ||
| + | return | ||
| + | + 2 * int(obs[2] >= 0) | ||
| + | + 4 * int(obs[1] >= 0) | ||
| + | + 8 * int(obs[0] >= 0) | ||
| + | else: | ||
| + | return obs | ||
| + | </ | ||
| + | |||
| + | ==== Choix des politiques ==== | ||
| + | |||
| + | L' | ||
| + | |||
| + | La vitesse et la qualité de la convergence dépendra fortement de la politique choisie. Nous comparerons dans ce TP différentes politiques possibles. | ||
| + | |||
| + | On considérera ici : | ||
| + | * la politique gloutonne (" | ||
| + | * une politique aléatoire uniforme | ||
| + | * la politique $\varepsilon$-greedy | ||
| + | * la politique softmax | ||
| + | |||
| + | === Max et argmax === | ||
| + | |||
| + | Écrire une méthode '' | ||
| + | (on pourra utiliser la méthode '' | ||
| + | |||
| + | def max_Q(self, s): | ||
| + | ... | ||
| + | | ||
| + | Écrire une méthode '' | ||
| + | (on pourra utiliser la méthode '' | ||
| + | |||
| + | def greedy_pol(self, | ||
| + | ... | ||
| + | | ||
| + | <note tip> Il s'agit ici de la politique " | ||
| + | </ | ||
| + | |||
| + | === Politique aléatoire === | ||
| + | |||
| + | Écrire une méthode '' | ||
| + | (on pourra utiliser '' | ||
| + | |||
| + | def random_pol(self, | ||
| + | ... | ||
| + | |||
| + | === Politique epsilon-greedy === | ||
| + | |||
| + | Écrire une méthode '' | ||
| + | * si $a = \underset{a' | ||
| + | * $\pi(a|s) = 1 - \varepsilon + \frac{\varepsilon}{N_a}$ | ||
| + | * sinon: | ||
| + | * $\pi(a|s) = \frac{\varepsilon}{N_a}$ | ||
| + | |||
| + | Ecrire la méthode '' | ||
| + | |||
| + | def eps_greedy_pol(self, | ||
| + | ... | ||
| + | |||
| + | <note tip> | ||
| + | Si '' | ||
| + | act = np.random.choice(len(act_probs), | ||
| + | </ | ||
| + | |||
| + | === Politique softmax === | ||
| + | |||
| + | La distribution du softmax est calculée selon l' | ||
| + | $$\pi(a|s) = \frac{\exp(Q(s, | ||
| + | |||
| + | Pour éviter les problèmes numériques, | ||
| + | somme = 0 | ||
| + | pour a de 0 à N_act: | ||
| + | act_probs[a] = exp(Q[s,a] - max_Q(s)) | ||
| + | somme <-- somme + act_probs[a] | ||
| + | act_probs <-- act_probs / somme | ||
| + | |||
| + | Ecrire la méthode '' | ||
| + | |||
| + | def softmax_pol(self, | ||
| + | ... | ||
| + | | ||
| + | ==== Outils d' | ||
| + | Voilà, nous disposons à présent de tous les éléments nécessaires pour écrire l' | ||
| + | |||
| + | <note tip> | ||
| + | Le but est de trouver la politique d' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | </ | ||
| + | |||
| + | Pour comparer différentes politiques et différents paramètres, | ||
| + | |||
| + | On utilisera ici l' | ||
| + | |||
| + | On regardera ici : | ||
| + | * le nombre total d' | ||
| + | * la valeur de l' | ||
| + | |||
| + | A chaque exécution de l' | ||
| + | |||
| + | Exemple de programme principal: | ||
| + | <code python> | ||
| + | import gym | ||
| + | from agent import Agent | ||
| + | from tensorboardX import SummaryWriter | ||
| + | |||
| + | ENV_NAME = ' | ||
| + | env = gym.make(ENV_NAME) | ||
| + | |||
| + | agent = Agent(env, ALPHA = 0.01, GAMMA = 0.9, CHOICE = ' | ||
| + | writer = SummaryWriter(log_dir=' | ||
| + | |||
| + | N = 1000 | ||
| + | |||
| + | for num_episode in range(N): | ||
| + | agent.run_episode_Q_learning(env, | ||
| + | print(num_episode) | ||
| + | if num_episode % 10 == 0: | ||
| + | agent.run_episode_glouton(env, | ||
| + | print(" | ||
| + | writer.add_scalar("# | ||
| + | writer.add_scalar(" | ||
| + | </ | ||
| + | |||
| + | <note tip> | ||
| + | * Ecrivez la méthode '' | ||
| + | * Ecrivez la méthode '' | ||
| + | * l' | ||
| + | * Pensez à ajouter un attribut '' | ||
| + | </ | ||
| + | |||
| + | |||
| + | < | ||
| + | * Pensez à définir un dossier différent pour chaque politique et chaque jeu de paramètres testés | ||
| + | * Pour visualiser les courbes d' | ||
| + | < | ||
| + | $ tensorboard --logdir runs | ||
| + | </ | ||
| + | * Ouvrez un navigateur. Le tableau de bord est visible à l' | ||
| + | </ | ||