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:43] – [Choix des politiques] 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' | ||
+ | </ | ||