[PYTHON] Essayez l'apprentissage Q dans une bataille de style Drakue [Introduction au renforcement de l'apprentissage]

Que faire?

Faisons une bataille au tour par tour de style Drakue super simple et laissons-la apprendre Q. バトルスクショ.png Le but est de rendre l'homme courageux, qui ne peut sauver le monde qu'avec quelques pour cent de chances, plus intelligent en apprenant Q.

De plus, je vais vous expliquer l'implémentation de la partie jeu et l'apprentissage Q, mais je n'expliquerai pas l'apprentissage Q lui-même. Si vous voulez connaître la théorie détaillée de l'apprentissage Q, vous serez heureux si vous lisez ces bons articles un par un.

Renforcement de l'apprentissage (1): fonction de valeur d'état et équation de Bellman

Les gens qui veulent lire

Faire un jeu

Les règles sont simplement conçues comme suit:

--Brave contre le roi démon 1: 1

Implémentation de la classe de caractères

Maintenant, implémentons le jeu lui-même. Le premier est la classe de caractères.

dq_battle.py


class Character(object):

    """Classe de caractère"""

    ACTIONS = {0: "attaque", 1: "récupération"}

    def __init__(self, hp, max_hp, attack, defence, agillity, intelligence, name):
        self.hp = hp  #HP actuel
        self.max_hp = max_hp  #HP maximum
        self.attack = attack  #Puissance offensive
        self.defence = defence  #Puissance de défense
        self.agillity = agillity  #Agilité
        self.intelligence = intelligence  #Sage
        self.name = name  #Le nom du personnage

    #Renvoie une chaîne d'état
    def get_status_s(self):
        return "[{}] HP:{}/{} ATK:{} DEF:{} AGI:{} INT:{}".format(
            self.name, self.hp, self.max_hp, self.attack, self.defence, self.agillity, self.intelligence)

    def action(self, target, action):

        #attaque
        if action == 0:

            #Puissance offensive-Calcul des dégâts défensifs
            damage = self.attack - target.defence
            draw_damage = damage  #Pour les journaux

            #Si les PV restants de l'adversaire sont inférieurs au montant des dégâts, les dégâts ne sont que les PV restants
            if target.hp < damage:
                damage = target.hp

            #A fait des dégats
            target.hp -= damage

            #Rendre le journal de bataille
            return "{}Est{}À{}Endommagé".format(
                self.name, target.name, draw_damage)

        #récupération
        elif action == 1:

            #Soit le montant de la récupération la valeur de INT
            heal_points = self.intelligence
            draw_heal_points = heal_points  #Pour les journaux

            #Si vous pouvez récupérer au maximum HP, maximum HP-Utilisez le HP actuel comme montant de récupération
            if self.hp + heal_points > self.max_hp:
                heal_points = self.max_hp - self.hp

            #récupération
            self.hp += heal_points

            #Rendre le journal de bataille
            return "{}HP{}Rétabli".format(
                self.name, draw_heal_points)

Puisque la conception de la bataille est cette fois simple, nous l'avons regroupée en une seule classe sans faire de distinction entre le joueur et l'ennemi.

Chaque personnage (Brave et Demon King)

--HP (force physique) --ATTACK (puissance d'attaque) --LA DÉFENSE --AGILITY (rapidité) --INTELLIGENCE

A le statut de.

Le calcul des dommages dans "attaque" est

Il est calculé par la formule simple. De plus, la quantité de récupération avec la commande «Récupération» est la même que la valeur de l'intelligence.

Vue d'ensemble de la conception de la bataille (transition d'état)

Ensuite, nous mettrons en œuvre le corps de combat. Tout d'abord, vous devez comprendre la vue d'ensemble (transition d'état) de la bataille.

dq_battle.py


class GameState(Enum):

    """Classe de gestion de l'état du jeu"""
    TURN_START = auto()      #Démarrer le virage
    COMMAND_SELECT = auto()  #Sélection de commande
    TURN_NOW = auto()        #Pendant le tour (chaque action de personnage)
    TURN_END = auto()        #Fin de tour
    GAME_END = auto()        #Jeu terminé

Comme mentionné ci-dessus pour la bataille ** "Démarrer le tour" "Sélectionner la commande" "Pendant le tour" "Terminer le tour" "Fin de partie" ** Il y a cinq états.

Le diagramme de transition d'état est illustré ci-dessous.

バトル状態遷移.png

De cette façon, les bases de la conception de bataille sont de boucler la transition de l'état «début de tour» à l'état «fin de tour» à l'infini jusqu'à l'état «fin de jeu» (jusqu'à ce que les PV du héros ou du roi démon deviennent 0). Sera.

Mise en œuvre du corps de combat

Maintenant, mettons en œuvre la bataille elle-même. Regardons d'abord le code entier.

dq_battle.py


class Game():

    """Corps de jeu"""

    HERO_MAX_HP = 20
    MAOU_MAX_HP = 50

    def __init__(self):

        #Générer du caractère
        self.hero = Character(
            Game.HERO_MAX_HP, Game.HERO_MAX_HP, 4, 1, 5, 7, "Courageux")

        self.maou = Character(
            Game.MAOU_MAX_HP, Game.MAOU_MAX_HP, 5, 2, 6, 3, "Diable")

        #Ajouter à la liste des personnages
        self.characters = []
        self.characters.append(self.hero)
        self.characters.append(self.maou)

        #Définir des variables pour les transitions d'état
        self.game_state = GameState.TURN_START

        #Nombre de tours
        self.turn = 1

        #Chaîne de caractères pour enregistrer le journal de combat
        self.log = ""

    #Faites avancer le jeu à chaque tour
    def step(self, action):

        #Boucle principale
        while (True):
            if self.game_state == GameState.TURN_START:
                self.__turn_start()
            elif self.game_state == GameState.COMMAND_SELECT:
                self.__command_select(action)  #Passez l'action
            elif self.game_state == GameState.TURN_NOW:
                self.__turn_now()
            elif self.game_state == GameState.TURN_END:
                self.__turn_end()
                break  #Sortir de la boucle à la fin du virage
            elif self.game_state == GameState.GAME_END:
                self.__game_end()
                break

        #Si le jeu est terminé
        done = False
        if self.game_state == GameState.GAME_END:
            done = True

        #Renvoie "état s, récompense r, fin de partie"
        return (self.hero.hp, self.maou.hp), self.reward, done

    #Initialisez le jeu à l'état du premier tour
    def reset(self):
        self.__init__()
        return (self.hero.hp, self.maou.hp)

    #Dessiner le journal de bataille
    def draw(self):
        print(self.log, end="")

    def __turn_start(self):

        #Transition d'état
        self.game_state = GameState.COMMAND_SELECT

        #Initialiser le journal
        self.log = ""

        #dessin
        s = " ***tour" + str(self.turn) + " ***"
        self.__save_log("\033[36m{}\033[0m".format(s))
        self.__save_log(self.hero.get_status_s())
        self.__save_log(self.maou.get_status_s())

    def __command_select(self, action):

        #Sélection d'action
        self.action = action

        #Caractère aléatoire numéro 0.5〜1.Trier par agilité de 5 et stocker dans la file d'attente
        self.character_que = deque(sorted(self.characters,
                                          key=lambda c: c.agillity*random.uniform(0.5, 1.5)))

        #Transition d'état
        self.game_state = GameState.TURN_NOW

        #Enregistrer le journal
        self.__save_log("Sélection de commande-> " + Character.ACTIONS[self.action])

    def __turn_now(self):

        #Action séquentielle de la file d'attente de caractères
        if len(self.character_que) > 0:
            now_character = self.character_que.popleft()
            if now_character is self.hero:
                s = now_character.action(self.maou, self.action)
            elif now_character is self.maou:
                s = now_character.action(self.hero, action=0)  #Le roi démon attaque toujours

            #Enregistrer le journal
            self.__save_log(s)

        #Fin du jeu si HP est égal ou inférieur à 0
        for c in self.characters:
            if c.hp <= 0:
                self.game_state = GameState.GAME_END
                return

        #Tourner la fin quand tout le monde a terminé
        if len(self.character_que) == 0:
            self.game_state = GameState.TURN_END
            return

    def __turn_end(self):

        #Définir la récompense
        self.reward = 0

        #Initialisation de la file d'attente de caractères
        self.character_que = deque()

        #Progresser
        self.turn += 1

        #Transition d'état
        self.game_state = GameState.TURN_START

    def __game_end(self):

        if self.hero.hp <= 0:
            self.__save_log("\033[31m{}\033[0m".format("Le héros est mort"))
            self.reward = -1  #Définir la récompense
        elif self.maou.hp <= 0:
            self.__save_log("\033[32m{}\033[0m".format("Vaincu le roi démon"))
            self.reward = 1  #Définir la récompense

        self.__save_log("-----Fin du jeu-----")

    def __save_log(self, s):
        self.log += s + "\n"

Le code est un peu long, mais il n'y a que deux parties importantes de l'apprentissage Q.

La première est la méthode step (). C'est la partie principale de la bataille.

dq_battle.py


    #Faites avancer le jeu à chaque tour
    def step(self, action):

        #Boucle principale
        while (True):
            if self.game_state == GameState.TURN_START:
                self.__turn_start()
            elif self.game_state == GameState.COMMAND_SELECT:
                self.__command_select(action)  #Passez l'action
            elif self.game_state == GameState.TURN_NOW:
                self.__turn_now()
            elif self.game_state == GameState.TURN_END:
                self.__turn_end()
                break  #Sortir de la boucle à la fin du virage
            elif self.game_state == GameState.GAME_END:
                self.__game_end()
                break

        #Si le jeu est terminé
        done = False
        if self.game_state == GameState.GAME_END:
            done = True

        #Renvoie "état s, récompense r, fin de partie"
        return (self.hero.hp, self.maou.hp), self.reward, done

Fondamentalement, le flux de traitement est le même que le diagramme de transition d'état décrit ci-dessus.

Cependant, dans l'apprentissage Q, l'état actuel doit être évalué ** à chaque tour **, vous devez donc quitter la boucle principale non seulement dans l'état "fin de partie" mais aussi dans l'état "fin de tour".

Dans l'état "fin de tour", les variables qui doivent être évaluées pour effectuer l'apprentissage Q sont:

Il ya trois.

Que ce soit la fin du jeu est simplement déterminé par le fait que le HP du héros ou le HP du roi démon est devenu 0.

Nous devons réfléchir un peu à l'état de l'art. Il y a plusieurs statistiques telles que la puissance offensive et la puissance défensive, mais il n'y a en fait que deux statistiques qui devraient être évaluées dans l'apprentissage Q: "Brave HP" et "Demon King HP".

Dans cette conception de bataille, les valeurs telles que la puissance d'attaque et la puissance de défense sont toujours constantes, il n'est donc pas nécessaire d'évaluer des statistiques autres que HP. Inversement, si l'état change en raison du buffing, du debuffing, etc., ces informations sont également requises.

La récompense r est évaluée dans chacun des états «fin de tour» et «fin de partie».

dq_battle.py



    def __turn_end(self):

        #Définir la récompense
        self.reward = 0
    
    #(réduction)

    def __game_end(self):

        if self.hero.hp <= 0:
            self.__save_log("\033[31m{}\033[0m".format("Le héros est mort"))
            self.reward = -1  #Définir la récompense
        elif self.maou.hp <= 0:
            self.__save_log("\033[32m{}\033[0m".format("Vaincu le roi démon"))
            self.reward = 1  #Définir la récompense

La récompense pour le passage des tours est de 0. Si vous êtes conscient du but de "vaincre le roi démon à la vitesse la plus rapide", vous pouvez rendre la récompense après le tour négative. (Cependant, il est difficile de définir des paramètres appropriés.)

A la fin de la partie, si le héros tombe, il sera récompensé par "-1", et s'il bat le roi démon, il sera récompensé par "+1".

La deuxième partie importante est la méthode reset ().

dq_battle.py


    #Initialisez le jeu à l'état du premier tour
    def reset(self):
        self.__init__()
        return (self.hero.hp, self.maou.hp)

C'est juste une méthode pour initialiser le jeu. De plus, il est nécessaire de retourner l'état initial pour l'apprentissage Q.

Avec la méthode step () ci-dessus

** Initialisation du jeu (réinitialisation) → Avancez le tour jusqu'à la fin de la bataille (étape) → Initialisation du jeu (réinitialisation) → Avancez le tour jusqu'à la fin de la bataille (étape) ・ ・ ・ **

Vous pouvez poursuivre l'apprentissage en répétant le jeu.

Ce qui précède est la partie de base du jeu pour l'apprentissage Q.

Mettre en œuvre l'apprentissage Q

À propos de la classe d'agent

Le Q-learning est implémenté dans la classe d'agent. Un agent est une classe comme un joueur qui joue réellement à un jeu.

Puisque l'agent est le joueur lui-même, il peut choisir l'action (attaque ou récupération) et connaître l'état (tel que les HP du héros ou du roi démon), mais Il n'est pas possible de connaître les informations internes du jeu (comme le nombre aléatoire qui détermine l'ordre des actions).

L'apprentissage est basé uniquement sur «l'action» et sur «l'état» et la «récompense» obtenus par cette action. Il s'agit d'une compréhension de base du renforcement de l'apprentissage en général, y compris l'apprentissage Q.

Tout d'abord, je publierai toute la classe d'agent.

q-learning.py


DIV_N = 10

class Agent:
    """Classe d'agent"""

    def __init__(self, epsilon=0.2):
        self.epsilon = epsilon
        self.Q = []

    #Ε politique-Défini par la méthode gourmande
    def policy(self, s, actions):

        if np.random.random() < self.epsilon:

            #Epsilon a la chance d'agir au hasard
            return np.random.randint(len(actions))

        else:

            #(Si Q contient l'état s et la valeur Q dans cet état n'est pas 0)
            if s in self.Q and sum(self.Q[s]) != 0:

                #Agir pour que la valeur Q soit maximisée
                return np.argmax(self.Q[s])
            else:
                return np.random.randint(len(actions))

    #Convertir l'état en nombre
    def digitize_state(self, s):

        hero_hp, maou_hp = s

        #DIV chacun des HP du héros et du roi démon_Diviser par N
        s_digitize = [np.digitize(hero_hp, np.linspace(0, dq_battle.Game.HERO_MAX_HP, DIV_N + 1)[1:-1]),
                      np.digitize(maou_hp, np.linspace(0, dq_battle.Game.MAOU_MAX_HP, DIV_N + 1)[1:-1])]

        # DIV_Renvoie le nombre d'états jusqu'au carré de N
        return s_digitize[0] + s_digitize[1]*DIV_N

    #Q Apprenez
    def learn(self, env, actions, episode_count=1000, gamma=0.9, learning_rate=0.1):

        self.Q = defaultdict(lambda: [0] * len(actions))

        # episode_Bataille pour le compte
        for e in range(episode_count):

            #Réinitialiser l'environnement de jeu
            tmp_s = env.reset()

            #Convertir l'état actuel en valeur numérique
            s = self.digitize_state(tmp_s)

            done = False

            #Répétez l'action jusqu'à la fin du jeu
            while not done:

                # ε-Choisissez une action selon une politique gourmande
                a = self.policy(s, actions)

                #Avancez le jeu d'un tour et renvoyez "l'état, la récompense, la fin du jeu" à ce moment
                tmp_s, reward, done = env.step(a)

                #Convertir l'état en nombre
                n_state = self.digitize_state(tmp_s)

                #Valeur acquise par l'action a(gain) =Récompense immédiate+Taux d'actualisation du temps*Valeur Q maximale dans les états suivants
                gain = reward + gamma * max(self.Q[n_state])

                #Valeur Q actuellement estimée (avant apprentissage)
                estimated = self.Q[s][a]

                #Mettez à jour la valeur Q en fonction de la valeur estimée actuelle et de la valeur réelle lors de l'exécution de l'action a
                self.Q[s][a] += learning_rate * (gain - estimated)

                #Changer l'état actuel pour l'état suivant
                s = n_state

Convertir l'état en nombre

Ce qui est un peu déroutant dans la classe d'agent, c'est la méthode qui convertit l'état en nombre.

q-learning.py


    #Convertir l'état en nombre
    def digitize_state(self, s):

        hero_hp, maou_hp = s

        #DIV chacun des HP du héros et du roi démon_Diviser en N
        s_digitize = [np.digitize(hero_hp, np.linspace(0, dq_battle.Game.HERO_MAX_HP, DIV_N + 1)[1:-1]),
                      np.digitize(maou_hp, np.linspace(0, dq_battle.Game.MAOU_MAX_HP, DIV_N + 1)[1:-1])]

        # DIV_Renvoie le nombre d'états jusqu'au carré de N
        return s_digitize[0] + s_digitize[1]*DIV_N

Comme je l'ai mentionné brièvement plus tôt, il y a deux variables d'état qui devraient être évaluées lors de l'apprentissage de Q: "Brave HP" et "Devil's HP". Cependant, dans l'apprentissage Q, l'état doit être représenté sous la forme d'un nombre unique. En d'autres termes, l'image est la suivante.

--État 1: (Brave HP, Demon King HP) = (0, 0) --État 2: (Brave HP, Demon King HP) = (0, 1) --État 3: (Brave HP, Demon King HP) = (0, 2)

Vous pouvez convertir comme ci-dessus, mais cela augmentera le statut du nombre de HP x HP. Comme un certain RPG national qui n'est pas un drakue, s'il y a 4 chiffres de HP, le nombre d'états dépasse 1 million et c'est difficile (rires). Par conséquent, divisons l'état en fonction du rapport de HP.

np.digitize(hero_hp, np.linspace(0, dq_battle.Game.HERO_MAX_HP, DIV_N + 1)[1:-1]

Une explication rapide de ce code Avec np.linspace (), divisez de 0 au maximum HP en N, C'est une image qui renvoie le nombre de divisions auxquelles appartient le HP actuel avec np.digitize ().

Puisque N = 10 cette fois,

--HP est inférieur à 10% → 0 --HP est de 10% ou plus, moins de 20% → 1 --HP est de 20% ou plus, moins de 30% → 2

Il sera converti comme ça. en outre

"État courageux (0-9) + état roi démon (0-9) * 10" En calculant, le nombre d'états peut être supprimé à 100 de 0 à 99.

Si l'état est "15", vous pouvez comprendre intuitivement que les PV du roi démon sont inférieurs à "10"% et les PV du héros sont inférieurs à "50"%.

Définition des mesures

La politique est ε-gourmande.

q-learning.py


    #Ε politique-Défini par la méthode gourmande
    def policy(self, s, actions):

        if np.random.random() < self.epsilon:

            #Epsilon a la chance d'agir au hasard
            return np.random.randint(len(actions))

        else:

            #(Si Q contient l'état s et la valeur Q dans cet état n'est pas 0)
            if s in self.Q and sum(self.Q[s]) != 0:

                #Agir pour que la valeur Q soit maximisée
                return np.argmax(self.Q[s])
            else:
                return np.random.randint(len(actions))

Pour expliquer brièvement pour les débutants, il s'agit essentiellement d'une politique de décider de l'action de sorte que la valeur de l'action soit maximisée et d'adopter une action aléatoire avec une probabilité de ε.

En donnant un certain degré d'aléatoire au comportement, divers comportements sont recherchés, de sorte qu'un apprentissage approprié est possible sans dépendre de la valeur initiale de la valeur Q.

Mise en œuvre de l'apprentissage Q

En passant, à ce stade, nous avons toutes les variables et méthodes requises pour l'apprentissage Q.

L'algorithme d'apprentissage Q est le suivant.

  1. Initialisez $ Q (s, a) $.
  2. Répétez la bataille un certain nombre de fois:
  3. Initialisation de l'environnement de jeu
  4. Avancez le tour jusqu'à la fin de la partie:
  5. Sélectionnez l'action $ a $ selon la stratégie $ π $.
  6. Exécutez l'action $ a $ et observez la récompense $ r $ et l'état suivant $ s '$.
  7. Mettez à jour $ Q (s, a) $ comme suit.
    $ Q (s, a) $ \ leftarrow $ Q (s, a) + α (r + γ * $ \ underet {a ′} {max} $$ Q (s ′, a ′) −Q (s, a)) $
  8. $ s $ \ leftarrow $ s '$.

Comme mentionné au début de l'article, je n'expliquerai pas la théorie de l'apprentissage Q, nous allons donc implémenter l'algorithme ci-dessus avec obéissance.

q-learning.py


    #Q Apprenez
    def learn(self, env, actions, episode_count=1000, gamma=0.9, learning_rate=0.1):

        self.Q = defaultdict(lambda: [0] * len(actions))

        # episode_Bataille pour le compte
        for e in range(episode_count):

            #Réinitialiser l'environnement de jeu
            tmp_s = env.reset()

            #Convertir l'état actuel en valeur numérique
            s = self.digitize_state(tmp_s)

            done = False

            #Répétez l'action jusqu'à la fin du jeu
            while not done:

                # ε-Choisissez une action selon une politique gourmande
                a = self.policy(s, actions)

                #Avancez le jeu d'un tour et renvoyez "l'état, la récompense, la fin du jeu" à ce moment
                tmp_s, reward, done = env.step(a)

                #Convertir l'état en nombre
                n_state = self.digitize_state(tmp_s)

                #Valeur acquise par l'action a(gain) =Récompense immédiate+Taux d'actualisation du temps*Valeur Q maximale dans les états suivants
                gain = reward + gamma * max(self.Q[n_state])

                #Valeur Q actuellement estimée (avant apprentissage)
                estimated = self.Q[s][a]

                #Mettez à jour la valeur Q en fonction de la valeur estimée actuelle et de la valeur réelle lors de l'exécution de l'action a
                self.Q[s][a] += learning_rate * (gain - estimated)

                #Changer l'état actuel pour l'état suivant
                s = n_state

Ceci termine la mise en œuvre du jeu et l'apprentissage Q.

Jeu Run & Learn

Agissons au hasard

Q Avant d'apprendre, essayons ce qui se passe lorsque les actions du héros sont aléatoires et combattues.

Ajoutez le code suivant.

q-learning.py



class Agent:

    #(réduction)

    #Test de bataille
    def test_run(self, env, actions, draw=True, episode_count=1000):

        turn_num = 0  #Nombre de tours de défaite
        win_num = 0  #Nombre de victoires

        # episode_Bataille pour le compte
        for e in range(episode_count):

            tmp_s = env.reset()
            s = self.digitize_state(tmp_s)

            done = False

            while not done:
                a = self.policy(s, actions)
                n_state, _, done = env.step(a)
                s = self.digitize_state(n_state)
                if draw:
                    env.draw()  #Dessiner le journal de bataille

            if env.maou.hp <= 0:
                win_num += 1
                turn_num += env.turn

        #Taux de victoire moyen en sortie et nombre moyen de tours de défaite
        if not win_num == 0:
            print("Taux de victoire moyen{:.2f}%".format(win_num*100/episode_count))
            print("Nombre moyen de tours de défaite:{:.2f}".format(turn_num / win_num))
        else:
            print("Taux de victoire moyen 0%")


if __name__ == "__main__":

    game = dq_battle.Game()
    agent = Agent()

    actions = dq_battle.Character.ACTIONS

    """Bataille complètement aléatoire"""
    agent.epsilon = 1.0
    agent.test_run(game, actions, episode_count=1000)

En fixant ε = 1.0, il est amené à agir à 100% de manière complètement aléatoire. Aussi, j'ai essayé de calculer le taux de victoire moyen et le nombre moyen de tours vaincus à partir des résultats de 1000 batailles.

Voici les résultats de l'exécution.

$ python q-learning.py 
Taux de victoire moyen 0.90%
Nombre moyen de tours de défaite:64.89

Le taux de victoire est assez faible ...

Comme vous pouvez le voir d'après le nombre de tours, cela a tendance à être une bataille à long terme. Plus la bataille est longue, plus le héros sera mourant et, par conséquent, il sera difficile de gagner.

Q Essayez de vous battre après avoir appris

Ajoutez le code suivant.

q-learning.py



if __name__ == "__main__":

    #(réduction)

    """Q Apprenez"""
    agent.epsilon = 0.2
    agent.learn(game, actions, episode_count=1000)

    """Test de bataille"""
    agent.epsilon = 0
    agent.test_run(game, actions, episode_count=1000)

Posons ε = 0,2 et exécutons l'apprentissage Q.

Après cela, 1000 batailles d'essai auront lieu. En définissant ε = 0 (0% aléatoire), le comportement est exécuté en fonction de la valeur d'action apprise.

Ci-dessous, les résultats de l'exécution sont affichés en modifiant le nombre de batailles à apprendre.

** Résultat de l'exécution (nombre de batailles d'apprentissage: 50, nombre de batailles d'essai: 1000) **

$ python q-learning.py 
Taux de victoire moyen 42.60%
Nombre moyen de tours de défaite:56.19

** Résultat d'exécution (500 batailles d'apprentissage, 1000 batailles d'essai) **

$ python q-learning.py 
Taux de victoire moyen 100.00%
Nombre moyen de tours de défaite:55.00

** Résultat de l'exécution (5000 batailles d'apprentissage, 1000 batailles d'essai) **

$ python q-learning.py 
Taux de victoire moyen 100.00%
Nombre moyen de tours de défaite:54.00

Le taux de gain est de 100%!

Quelle est la valeur Q après l'apprentissage?

Considérons un peu. Voyons la valeur Q du résultat appris.

Ci-dessous, la valeur Q lors de l'apprentissage avec 1000 batailles est extraite pour certains états. Q-value1.png

État 50:[-0.19, -0.1]
État 51:[-0.6623164987957537, -0.34788781183605283]
État 52:[-0.2711479211007827, 0.04936802595531123]
État 53:[-0.36097806076138395, 0.11066249745943924]
État 54:[-0.04065992616558749, 0.12416469852733954]
État 55:[0.17619052640036173, 0.09475948937059306]
État 56:[0.10659739434775867, 0.05112985778828942]
État 57:[0.1583472103200607, 0.016092008419030468]
État 58:[0.04964633744625512, 0.0020759614034820224]
État 59:[0.008345513895442138, 0.0]

Quant à la façon de voir l'état, la 10e place est le HP restant du roi démon, et la 1ère place est le HP restant du héros. En d'autres termes, la figure ci-dessus montre comment la valeur d'action change en fonction des HP restants du héros lorsque les HP restants du roi démon sont d'environ 50%.

Sur la figure, on peut voir que si le HP restant (1ère place) du héros est bas, la commande "Récupération" est sélectionnée, et si le HP restant est élevé, la commande "Attack" est sélectionnée.

Regardons également la valeur Q lorsque les PV restants du héros sont corrigés. Q-value1.png

État 07:[2.023809062133135, 0.009000000000000001]
État 17:[1.8092946131557912, 0.8310497919226313]
État 27:[0.8223927076749513, 0.5279685031058523]
État 37:[0.5565475393122992, 0.29257906153106145]
État 47:[0.25272081107828437, 0.26657637207739293]
État 57:[0.14094053800308323, 0.1533527340827757]
État 67:[0.0709128688771915, 0.07570873469406877]
État 77:[0.039059851207044236, 0.04408123679644829]
État 87:[0.023028972190011696, 0.02386492692407677]
État 97:[0.016992303227705185, 0.0075795064515745995]

La figure ci-dessus montre comment la valeur de l'action change en fonction des PV restants du roi démon lorsque les PV restants du héros sont d'environ 70%. Vous pouvez voir que moins le roi démon a de HP, plus "l'attaque" est supérieure.

finalement

Étant donné que cet article est principalement mis en œuvre, d'autres considérations seront omises. Si vous pouvez vous le permettre, il sera intéressant d'essayer d'apprendre en modifiant les hyper paramètres ou en essayant de rendre les règles de combat plus compliquées.

De plus, comme je suis un débutant dans le renforcement de l'apprentissage, n'hésitez pas à signaler toute erreur. Je suis heureux que mes connaissances se soient renforcées.

La source est sur github. https://github.com/nanoseeing/DQ_Q-learning

Livre de référence

Recommended Posts

Essayez l'apprentissage Q dans une bataille de style Drakue [Introduction au renforcement de l'apprentissage]
Apprentissage par renforcement profond 1 Introduction au renforcement de l'apprentissage
[Introduction au renforcement de l'apprentissage] part.1-Algorithme Epsilon-Greedy dans Bandit Game
[Apprentissage de renforcement d'introduction] Renforcement de l'apprentissage pour bouger pour le moment
[Introduction] Renforcer l'apprentissage
[Pour les débutants] Introduction à la vectorisation dans l'apprentissage automatique
Introduction à l'apprentissage automatique
Essayez de faire une stratégie de blackjack en renforçant l'apprentissage (② Enregistrer l'environnement dans le gymnase)
[Mémorandum d'apprentissage] Introduction à vim
Une introduction à l'apprentissage automatique
Apprentissage par renforcement 5 Essayez de programmer CartPole?
Essayez de faire une stratégie de blackjack en renforçant l'apprentissage (③ Renforcer l'apprentissage dans votre propre environnement OpenAI Gym))
Super introduction à l'apprentissage automatique
Introduction au Deep Learning ~ Rétropropagation ~
J'ai lu "Renforcer l'apprentissage avec Python de l'introduction à la pratique" Chapitre 1
Essayez de faire une stratégie de blackjack en renforçant l'apprentissage ((1) Implémentation du blackjack)
Renforcer l'apprentissage 13 Essayez Mountain_car avec ChainerRL.
Introduction à la rédaction de notes d'apprentissage automatique
Introduction à l'apprentissage en profondeur ~ Approximation des fonctions ~
Essayez de calculer Trace en Python
Essayez de mettre des données dans MongoDB
Introduction à l'apprentissage profond ~ Préparation au codage ~
Renforcer l'apprentissage 8 Essayez d'utiliser l'interface utilisateur de Chainer
Présentation de la bibliothèque d'apprentissage automatique SHOGUN
Essayez Cython dans les plus brefs délais
Introduction au Deep Learning ~ Dropout Edition ~
Introduction au Deep Learning ~ Propagation vers l'avant ~
Introduction à l'apprentissage profond ~ Expérience CNN ~
Possibilité d'application à la conception d'itinéraire d'évacuation du problème de labyrinthe dans l'apprentissage par renforcement
[Introduction à Python] Comment utiliser la classe en Python?
Introduction à l'apprentissage automatique: fonctionnement du modèle
Apprentissage amélioré pour apprendre de zéro à profond
Introduction au Deep Learning ~ Pliage et mise en commun ~
Une introduction à OpenCV pour l'apprentissage automatique
Essayez de reproduire l'add.at de NumPy avec Julia
Introduction à TensorFlow - Explication des termes et concepts d'apprentissage automatique
Introduction à docker Création d'un environnement ubuntu dans ubuntu
Essayez l'algorithme d'apprentissage amélioré standard d'OpenAI PPO
Introduction aux vecteurs: Algèbre linéaire en Python <1>
Introduction à la vérification de l'efficacité Chapitre 1 écrit en Python
Renforcer l'apprentissage 11 Essayez OpenAI acrobot avec ChainerRL.
Introduction au Deep Learning (1) --Chainer est expliqué d'une manière facile à comprendre pour les débutants-