[PYTHON] Versuchen Sie Q-Lernen in einem Kampf im Drakue-Stil [Einführung in die Stärkung des Lernens]

Was ist zu tun?

Lassen Sie uns einen supereinfachen rundenbasierten Kampf im Drakue-Stil machen und Q lernen. バトルスクショ.png Der Zweck ist es, den tapferen Mann, der die Welt nur mit wenigen Prozent Chance retten kann, schlauer zu machen, indem er Q lernt.

Außerdem werde ich die Implementierung des Spielteils und des Q-Lernens erklären, aber ich werde das Q-Lernen selbst nicht erklären. Wenn Sie die detaillierte Theorie des Q-Lernens kennenlernen möchten, werden Sie sich freuen, wenn Sie diese guten Artikel einzeln lesen.

Stärkung des Lernens (1): Zustandswertfunktion und Bellman-Gleichung

Leute, die lesen wollen

Mach ein Spiel

Die Regeln sind einfach wie folgt aufgebaut:

Implementierung der Zeichenklasse

Lassen Sie uns nun das Spiel selbst implementieren. Erstens ist die Zeichenklasse.

dq_battle.py


class Character(object):

    """Zeichenklasse"""

    ACTIONS = {0: "Attacke", 1: "Wiederherstellung"}

    def __init__(self, hp, max_hp, attack, defence, agillity, intelligence, name):
        self.hp = hp  #Aktuelle HP
        self.max_hp = max_hp  #Maximale HP
        self.attack = attack  #Offensivkraft
        self.defence = defence  #Verteidigungskraft
        self.agillity = agillity  #Beweglichkeit
        self.intelligence = intelligence  #Weise
        self.name = name  #Charaktername

    #Gibt eine Statuszeichenfolge zurück
    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):

        #Attacke
        if action == 0:

            #Offensivkraft-Defensive Schadensberechnung
            damage = self.attack - target.defence
            draw_damage = damage  #Für Protokolle

            #Wenn die verbleibenden HP des Gegners geringer sind als der Schaden, ist der Schaden nur die verbleibenden HP
            if target.hp < damage:
                damage = target.hp

            #Schaden verursachen
            target.hp -= damage

            #Gib das Kampfprotokoll zurück
            return "{}Ist{}Zu{}Beschädigt".format(
                self.name, target.name, draw_damage)

        #Wiederherstellung
        elif action == 1:

            #Der Wiederherstellungsbetrag sei der Wert von INT
            heal_points = self.intelligence
            draw_heal_points = heal_points  #Für Protokolle

            #Wenn Sie auf maximale HP wiederherstellen können, maximale HP-Verwenden Sie die aktuellen HP als Wiederherstellungsbetrag
            if self.hp + heal_points > self.max_hp:
                heal_points = self.max_hp - self.hp

            #Wiederherstellung
            self.hp += heal_points

            #Gib das Kampfprotokoll zurück
            return "{}HP{}Wiederhergestellt".format(
                self.name, draw_heal_points)

Da das Schlachtdesign diesmal einfach ist, haben wir es in einer Klasse zusammengefasst, ohne zwischen dem Spieler und dem Feind zu unterscheiden.

Jeder Charakter (Brave and Demon King)

Hat den Status von.

Schadensberechnung in "Angriff" ist

Es wird nach der einfachen Formel berechnet. Auch der Umfang der Wiederherstellung mit dem Befehl "Wiederherstellung" entspricht dem Wert der Klugheit.

Gesamtbild des Kampfdesigns (Zustandsübergang)

Als nächstes werden wir den Kampfkörper implementieren. Zunächst müssen Sie das Gesamtbild (Zustandsübergang) der Schlacht verstehen.

dq_battle.py


class GameState(Enum):

    """Spielstatus-Management-Klasse"""
    TURN_START = auto()      #Start drehen
    COMMAND_SELECT = auto()  #Befehlsauswahl
    TURN_NOW = auto()        #Während des Zuges (jede Charakteraktion)
    TURN_END = auto()        #Ende der Runde
    GAME_END = auto()        #Spiel ist aus

Wie oben für die Schlacht erwähnt ** "Runde starten" "Befehl auswählen" "Während der Runde" "Runde beenden" "Spiel beenden" ** Es gibt fünf Staaten.

Das Zustandsübergangsdiagramm ist wie unten gezeigt.

バトル状態遷移.png

Auf diese Weise besteht die Grundlage des Kampfdesigns darin, den Übergang vom "Turn Start" -Zustand zum "Turn End" -Zustand endlos bis zum "Game End" -Zustand zu wiederholen (bis die HP des Helden oder des Dämonenkönigs 0 werden). Wird sein.

Implementierung des Kampfkörpers

Lassen Sie uns nun den Kampf selbst durchführen. Schauen wir uns zuerst den gesamten Code an.

dq_battle.py


class Game():

    """Spielkörper"""

    HERO_MAX_HP = 20
    MAOU_MAX_HP = 50

    def __init__(self):

        #Charakter erzeugen
        self.hero = Character(
            Game.HERO_MAX_HP, Game.HERO_MAX_HP, 4, 1, 5, 7, "Mutig")

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

        #Zur Charakterliste hinzufügen
        self.characters = []
        self.characters.append(self.hero)
        self.characters.append(self.maou)

        #Definieren Sie Variablen für Zustandsübergänge
        self.game_state = GameState.TURN_START

        #Anzahl der Züge
        self.turn = 1

        #Zeichenkette zum Speichern des Kampfprotokolls
        self.log = ""

    #Verbessere das Spiel in jeder Runde
    def step(self, action):

        #Hauptschleife
        while (True):
            if self.game_state == GameState.TURN_START:
                self.__turn_start()
            elif self.game_state == GameState.COMMAND_SELECT:
                self.__command_select(action)  #Übergeben Sie die Aktion
            elif self.game_state == GameState.TURN_NOW:
                self.__turn_now()
            elif self.game_state == GameState.TURN_END:
                self.__turn_end()
                break  #Verlasse die Schleife am Ende der Kurve
            elif self.game_state == GameState.GAME_END:
                self.__game_end()
                break

        #Ob das Spiel vorbei ist
        done = False
        if self.game_state == GameState.GAME_END:
            done = True

        #Gibt "Zustand s, Belohnung r, Spielende" zurück
        return (self.hero.hp, self.maou.hp), self.reward, done

    #Initialisiere das Spiel auf den Zustand der ersten Runde
    def reset(self):
        self.__init__()
        return (self.hero.hp, self.maou.hp)

    #Zeichne das Kampfprotokoll
    def draw(self):
        print(self.log, end="")

    def __turn_start(self):

        #Staatsübergang
        self.game_state = GameState.COMMAND_SELECT

        #Protokoll initialisieren
        self.log = ""

        #Zeichnung
        s = " ***Wende" + 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):

        #Aktionsauswahl
        self.action = action

        #Zeichen Zufallszahl 0.5〜1.Sortieren Sie nach Agilität von 5 und speichern Sie in der Warteschlange
        self.character_que = deque(sorted(self.characters,
                                          key=lambda c: c.agillity*random.uniform(0.5, 1.5)))

        #Staatsübergang
        self.game_state = GameState.TURN_NOW

        #Protokoll speichern
        self.__save_log("Befehlsauswahl-> " + Character.ACTIONS[self.action])

    def __turn_now(self):

        #Sequentielle Aktion aus der Zeichenwarteschlange
        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)  #Dämonenkönig greift immer an

            #Protokoll speichern
            self.__save_log(s)

        #Spielende, wenn HP 0 oder weniger ist
        for c in self.characters:
            if c.hp <= 0:
                self.game_state = GameState.GAME_END
                return

        #Schalten Sie das Ende aus, wenn alle die Aktion beendet haben
        if len(self.character_que) == 0:
            self.game_state = GameState.TURN_END
            return

    def __turn_end(self):

        #Belohnung festlegen
        self.reward = 0

        #Initialisierung der Zeichenwarteschlange
        self.character_que = deque()

        #Drehen Sie den Fortschritt
        self.turn += 1

        #Staatsübergang
        self.game_state = GameState.TURN_START

    def __game_end(self):

        if self.hero.hp <= 0:
            self.__save_log("\033[31m{}\033[0m".format("Der Held ist tot"))
            self.reward = -1  #Belohnung festlegen
        elif self.maou.hp <= 0:
            self.__save_log("\033[32m{}\033[0m".format("Besiegte den Dämonenkönig"))
            self.reward = 1  #Belohnung festlegen

        self.__save_log("-----Spielende-----")

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

Der Code ist etwas lang, aber es gibt nur zwei wichtige Teile des Q-Lernens.

Die erste ist die step () -Methode. Dies ist der Hauptteil der Schlacht.

dq_battle.py


    #Verbessere das Spiel in jeder Runde
    def step(self, action):

        #Hauptschleife
        while (True):
            if self.game_state == GameState.TURN_START:
                self.__turn_start()
            elif self.game_state == GameState.COMMAND_SELECT:
                self.__command_select(action)  #Übergeben Sie die Aktion
            elif self.game_state == GameState.TURN_NOW:
                self.__turn_now()
            elif self.game_state == GameState.TURN_END:
                self.__turn_end()
                break  #Verlasse die Schleife am Ende der Kurve
            elif self.game_state == GameState.GAME_END:
                self.__game_end()
                break

        #Ob das Spiel vorbei ist
        done = False
        if self.game_state == GameState.GAME_END:
            done = True

        #Gibt "Zustand s, Belohnung r, Spielende" zurück
        return (self.hero.hp, self.maou.hp), self.reward, done

Grundsätzlich ist der Verarbeitungsablauf derselbe wie das oben beschriebene Zustandsübergangsdiagramm.

Beim Q-Lernen muss der aktuelle Status jedoch ** in jeder Runde ** ausgewertet werden, sodass Sie die Hauptschleife nicht nur im Status "Spielende", sondern auch im Status "Spielende" verlassen müssen.

Im Zustand "Ende der Runde" müssen folgende Variablen ausgewertet werden, um Q-Lernen durchzuführen:

Dort sind drei.

Ob es das Ende des Spiels ist, hängt einfach davon ab, ob die HP des Helden oder die HP des Dämonenkönigs 0 geworden sind.

Wir müssen ein wenig über den Staat nachdenken. Es gibt mehrere Statistiken wie Offensivkraft und Defensivkraft, aber es gibt tatsächlich nur zwei Statistiken, die beim Q-Lernen bewertet werden sollten: "Brave HP" und "Demon King HP".

In diesem Kampfdesign sind die Werte wie Angriffs- und Verteidigungskraft immer konstant, sodass keine anderen Statistiken als HP ausgewertet werden müssen. Umgekehrt sind diese Informationen auch erforderlich, wenn sich der Status aufgrund von Polieren, Debuffing usw. ändert.

Die Belohnung r wird in jedem der Zustände "Ende des Zuges" und "Ende des Spiels" bewertet.

dq_battle.py



    def __turn_end(self):

        #Belohnung festlegen
        self.reward = 0
    
    #(Kürzung)

    def __game_end(self):

        if self.hero.hp <= 0:
            self.__save_log("\033[31m{}\033[0m".format("Der Held ist tot"))
            self.reward = -1  #Belohnung festlegen
        elif self.maou.hp <= 0:
            self.__save_log("\033[32m{}\033[0m".format("Besiegte den Dämonenkönig"))
            self.reward = 1  #Belohnung festlegen

Die Belohnung für den Durchgang von Runden ist 0. Wenn Sie sich des Zwecks bewusst sind, "den Dämonenkönig mit der schnellsten Geschwindigkeit zu besiegen", können Sie die Belohnung nach dem Zug negativ machen. (Es ist jedoch schwierig, geeignete Parameter einzustellen.)

Wenn der Held am Ende des Spiels fällt, wird er mit "-1" belohnt, und wenn er den Dämonenkönig besiegt, wird er mit "+1" belohnt.

Der zweite wichtige Teil ist die Methode reset ().

dq_battle.py


    #Initialisiere das Spiel auf den Zustand der ersten Runde
    def reset(self):
        self.__init__()
        return (self.hero.hp, self.maou.hp)

Es ist nur eine Methode, um das Spiel zu initialisieren. Außerdem muss der Ausgangszustand für das Q-Lernen zurückgegeben werden.

Zusammen mit der obigen Methode step ()

** Spielinitialisierung (Zurücksetzen) → Den Zug vorrücken, bis der Kampf endet (Schritt) → Spielinitialisierung (Zurücksetzen) → Den Zug vorrücken, bis der Kampf endet (Schritt) ・ ・ ・ **

Sie können mit dem Lernen fortfahren, indem Sie das Spiel wiederholen.

Das Obige ist der grundlegende Teil des Spiels für das Q-Lernen.

Implementieren Sie Q-Learning

Über die Agentenklasse

Q-Learning wird innerhalb der Agentenklasse implementiert. Ein Agent ist eine Klasse wie ein Spieler, der tatsächlich ein Spiel spielt.

Da der Agent der Spieler selbst ist, kann er die Aktion (Angriff oder Wiederherstellung) auswählen und den Zustand kennen (wie die HP des Helden oder des Dämonenkönigs), aber Es ist nicht möglich, die internen Informationen des Spiels zu kennen (z. B. die Zufallszahl, die die Reihenfolge der Aktionen bestimmt).

Das Lernen basiert nur auf der "Aktion" und dem "Zustand" und der "Belohnung", die durch diese Aktion erhalten werden. Dies ist ein grundlegendes Verständnis zur Stärkung des Lernens im Allgemeinen, einschließlich des Q-Lernens.

Zuerst werde ich die gesamte Agentenklasse veröffentlichen.

q-learning.py


DIV_N = 10

class Agent:
    """Agentenklasse"""

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

    #Ε Politik-Definiert durch die gierige Methode
    def policy(self, s, actions):

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

            #Epsilon Chance, zufällig zu handeln
            return np.random.randint(len(actions))

        else:

            #(Wenn Q den Zustand s enthält und der Q-Wert in diesem Zustand nicht 0 ist)
            if s in self.Q and sum(self.Q[s]) != 0:

                #Handeln Sie so, dass der Q-Wert maximiert wird
                return np.argmax(self.Q[s])
            else:
                return np.random.randint(len(actions))

    #Status in Nummer umwandeln
    def digitize_state(self, s):

        hero_hp, maou_hp = s

        #Tauchen Sie jeweils die HP des Helden und des Dämonenkönigs_Teilen Sie durch 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_Gibt die Anzahl der Zustände bis zum Quadrat von N zurück
        return s_digitize[0] + s_digitize[1]*DIV_N

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

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

        # episode_Kampf um die Zählung
        for e in range(episode_count):

            #Setzen Sie die Spielumgebung zurück
            tmp_s = env.reset()

            #Konvertieren Sie den aktuellen Status in einen numerischen Wert
            s = self.digitize_state(tmp_s)

            done = False

            #Wiederholen Sie die Aktion bis zum Ende des Spiels
            while not done:

                # ε-Wählen Sie die Aktion gemäß der gierigen Richtlinie
                a = self.policy(s, actions)

                #Erhöhen Sie das Spiel um eine Runde und geben Sie den "Status, Belohnung, Spielende" zu diesem Zeitpunkt zurück
                tmp_s, reward, done = env.step(a)

                #Status in Nummer umwandeln
                n_state = self.digitize_state(tmp_s)

                #Wertschöpfung durch Aktion a(gain) =Sofortige Belohnung+Zeitabzinsungssatz*Maximaler Q-Wert in den folgenden Zuständen
                gain = reward + gamma * max(self.Q[n_state])

                #Q-Wert derzeit geschätzt (vor dem Lernen)
                estimated = self.Q[s][a]

                #Aktualisieren Sie den Q-Wert basierend auf dem aktuellen Schätzwert und dem tatsächlichen Wert, wenn Sie Aktion a ausführen
                self.Q[s][a] += learning_rate * (gain - estimated)

                #Ändern Sie den aktuellen Status in den nächsten Status
                s = n_state

Status in Nummer umwandeln

Was in der Agentenklasse etwas verwirrend ist, ist die Methode, die den Status in eine Zahl konvertiert.

q-learning.py


    #Status in Nummer umwandeln
    def digitize_state(self, s):

        hero_hp, maou_hp = s

        #Tauchen Sie jeweils die HP des Helden und des Dämonenkönigs_Teilen Sie in 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_Gibt die Anzahl der Zustände bis zum Quadrat von N zurück
        return s_digitize[0] + s_digitize[1]*DIV_N

Wie ich bereits kurz erwähnt habe, gibt es zwei Zustandsvariablen, die beim Lernen von Q ausgewertet werden sollten: "Brave HP" und "Devil's HP". Beim Q-Lernen muss der Zustand jedoch als einzelne Zahl dargestellt werden. Mit anderen Worten ist das Bild wie folgt.

Sie können wie oben konvertieren, dies erhöht jedoch den Status um die Anzahl der HP x HP. Wie bei einem bestimmten nationalen Rollenspiel, das kein Drakue ist, übersteigt die Anzahl der Staaten 1 Million, wenn die HP 4-stellig ist, und es ist schwierig (lacht). Teilen wir daher den Zustand nach dem Verhältnis von HP.

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

Eine kurze Erklärung dieses Codes Teilen Sie mit np.linspace () von 0 bis maximal HP in N, Dies ist ein Bild, das die Anzahl der Abteilungen zurückgibt, zu denen die aktuelle HP mit np.digitize () gehört.

Da diesmal N = 10 ist,

Es wird so konvertiert. Und dazu

"Tapferer Zustand (0-9) + Dämonenkönigzustand (0-9) * 10" Durch Berechnung kann die Anzahl der Zustände von 0 auf 99 auf 100 unterdrückt werden.

Wenn der Status "15" ist, können Sie intuitiv verstehen, dass die HP des Dämonenkönigs weniger als "10"% und die HP des Helden weniger als "50"% betragen.

Definition von Maßnahmen

Die Politik ist ε-gierig.

q-learning.py


    #Ε Politik-Definiert durch die gierige Methode
    def policy(self, s, actions):

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

            #Epsilon Chance, zufällig zu handeln
            return np.random.randint(len(actions))

        else:

            #(Wenn Q den Zustand s enthält und der Q-Wert in diesem Zustand nicht 0 ist)
            if s in self.Q and sum(self.Q[s]) != 0:

                #Handeln Sie so, dass der Q-Wert maximiert wird
                return np.argmax(self.Q[s])
            else:
                return np.random.randint(len(actions))

Um es Anfängern kurz zu erklären, ist es im Grunde eine Richtlinie, die Aktion so zu entscheiden, dass der Aktionswert maximiert wird, und eine zufällige Aktion mit einer Wahrscheinlichkeit von ε zu übernehmen.

Indem den Aktionen ein gewisses Maß an Zufälligkeit verliehen wird, werden verschiedene Aktionen durchsucht, sodass ein angemessenes Lernen möglich ist, ohne vom Anfangswert des Q-Werts abhängig zu sein.

Implementierung von Q-Learning

Übrigens haben wir zu diesem Zeitpunkt alle Variablen und Methoden, die für das Q-Lernen erforderlich sind.

Der Q-Lernalgorithmus ist wie folgt.

  1. Initialisieren Sie $ Q (s, a) $.
  2. Wiederholen Sie den Kampf beliebig oft:
  3. Initialisierung der Spielumgebung
  4. Bewegen Sie den Zug bis zum Ende des Spiels:
  5. Wählen Sie die Aktion $ a $ gemäß der Strategie $ π $ aus.
  6. Führen Sie die Aktion $ a $ aus und beobachten Sie die Belohnung $ r $ und den nächsten Zustand $ s '$.
  7. Aktualisieren Sie $ Q (s, a) $ wie folgt.
    $ Q (s, a) $ \ linker Pfeil $ Q (s, a) + α (r + γ * $ \ underset {a ′} {max} $$ Q (s ′, a ′) −Q (s, a)) $
  8. $ s $ \ leftarrow $ s '$.

Wie am Anfang des Artikels erwähnt, werde ich die Theorie des Q-Lernens nicht erklären, also lassen Sie uns den obigen Algorithmus gehorsam implementieren.

q-learning.py


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

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

        # episode_Kampf um die Zählung
        for e in range(episode_count):

            #Setzen Sie die Spielumgebung zurück
            tmp_s = env.reset()

            #Konvertieren Sie den aktuellen Status in einen numerischen Wert
            s = self.digitize_state(tmp_s)

            done = False

            #Wiederholen Sie die Aktion bis zum Ende des Spiels
            while not done:

                # ε-Wählen Sie die Aktion gemäß der gierigen Richtlinie
                a = self.policy(s, actions)

                #Erhöhen Sie das Spiel um eine Runde und geben Sie den "Status, Belohnung, Spielende" zu diesem Zeitpunkt zurück
                tmp_s, reward, done = env.step(a)

                #Status in Nummer umwandeln
                n_state = self.digitize_state(tmp_s)

                #Wertschöpfung durch Aktion a(gain) =Sofortige Belohnung+Zeitabzinsungssatz*Maximaler Q-Wert in den folgenden Zuständen
                gain = reward + gamma * max(self.Q[n_state])

                #Q-Wert derzeit geschätzt (vor dem Lernen)
                estimated = self.Q[s][a]

                #Aktualisieren Sie den Q-Wert basierend auf dem aktuellen Schätzwert und dem tatsächlichen Wert, wenn Sie Aktion a ausführen
                self.Q[s][a] += learning_rate * (gain - estimated)

                #Ändern Sie den aktuellen Status in den nächsten Status
                s = n_state

Damit ist die Implementierung des Spiels und das Q-Lernen abgeschlossen.

Run & Learn Game

Lass uns zufällig handeln

F Bevor wir lernen, versuchen wir, was passiert, wenn Sie mit zufälligen Aktionen von Helden kämpfen.

Fügen Sie den folgenden Code hinzu.

q-learning.py



class Agent:

    #(Kürzung)

    #Testschlacht
    def test_run(self, env, actions, draw=True, episode_count=1000):

        turn_num = 0  #Anzahl der Niederlagen
        win_num = 0  #Anzahl der Siege

        # episode_Kampf um die Zählung
        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()  #Zeichne das Kampfprotokoll

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

        #Geben Sie die durchschnittliche Gewinnrate und die durchschnittliche Anzahl der Niederlage-Runden aus
        if not win_num == 0:
            print("Durchschnittliche Gewinnrate{:.2f}%".format(win_num*100/episode_count))
            print("Durchschnittliche Anzahl von Niederlagen:{:.2f}".format(turn_num / win_num))
        else:
            print("Durchschnittliche Gewinnrate 0%")


if __name__ == "__main__":

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

    actions = dq_battle.Character.ACTIONS

    """Völlig zufälliger Kampf"""
    agent.epsilon = 1.0
    agent.test_run(game, actions, episode_count=1000)

Durch Setzen von ε = 1,0 wird 100% völlig zufällig gehandelt. Außerdem habe ich versucht, die durchschnittliche Gewinnrate und die durchschnittliche Anzahl besiegter Runden aus den Ergebnissen von 1000 Schlachten zu berechnen.

Unten sind die Ausführungsergebnisse.

$ python q-learning.py 
Durchschnittliche Gewinnrate 0.90%
Durchschnittliche Anzahl von Niederlagen:64.89

Die Gewinnrate ist ziemlich niedrig ...

Wie Sie an der Anzahl der Runden sehen können, handelt es sich in der Regel um einen langfristigen Kampf. Je länger der Kampf dauert, desto mehr wird der Held sterben, und infolgedessen wird es schwierig sein, zu gewinnen.

F Versuchen Sie, nach dem Lernen zu kämpfen

Fügen Sie den folgenden Code hinzu.

q-learning.py



if __name__ == "__main__":

    #(Kürzung)

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

    """Testschlacht"""
    agent.epsilon = 0
    agent.test_run(game, actions, episode_count=1000)

Setzen wir ε = 0,2 und führen das Q-Lernen durch.

Danach finden 1000 Testkämpfe statt. Durch Setzen von ε = 0 (0% zufällig) wird das Verhalten gemäß dem gelernten Aktionswert ausgeführt.

Unten werden die Ausführungsergebnisse angezeigt, indem die Anzahl der zu lernenden Schlachten geändert wird.

** Ausführungsergebnis (Anzahl der Lernkämpfe: 50, Anzahl der Testkämpfe: 1000) **

$ python q-learning.py 
Durchschnittliche Gewinnrate 42.60%
Durchschnittliche Anzahl von Niederlagen:56.19

** Ausführungsergebnis (500 Lernschlachten, 1000 Testschlachten) **

$ python q-learning.py 
Durchschnittliche Gewinnrate 100.00%
Durchschnittliche Anzahl von Niederlagen:55.00

** Ausführungsergebnis (5000 Lernschlachten, 1000 Testschlachten) **

$ python q-learning.py 
Durchschnittliche Gewinnrate 100.00%
Durchschnittliche Anzahl von Niederlagen:54.00

Die Gewinnquote beträgt 100%!

Was ist der Q-Wert nach dem Lernen?

Lassen Sie uns ein wenig überlegen. Sehen wir uns den Q-Wert des gelernten Ergebnisses an.

Unten wird der Q-Wert beim Lernen mit 1000 Schlachten für einige Zustände extrahiert. Q-value1.png

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

Wie man den Staat sieht, ist der 10. Platz die verbleibende HP des Dämonenkönigs und der 1. Platz die verbleibende HP des Helden. Mit anderen Worten, die obige Abbildung zeigt, wie sich der Aktionswert in Abhängigkeit von den verbleibenden HP des Helden ändert, wenn die verbleibenden HP des Dämonenkönigs etwa 50% betragen.

Aus der Abbildung ist ersichtlich, dass der Befehl "Wiederherstellung" ausgewählt ist, wenn die verbleibenden HP (1. Platz) des Helden niedrig sind, und wenn die verbleibenden HP hoch sind, der Befehl "Angriff" ausgewählt ist.

Schauen wir uns auch den Q-Wert an, wenn die verbleibenden HP des Helden festgelegt sind. Q-value1.png

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

Die obige Abbildung zeigt, wie sich der Aktionswert in Abhängigkeit von den verbleibenden HP des Dämonenkönigs ändert, wenn die verbleibenden HP des Helden etwa 70% betragen. Sie können sehen, dass je weniger HP der Dämonenkönig übrig hat, desto mehr "Angriff" überlegen ist.

Schließlich

Da dieser Artikel hauptsächlich implementiert ist, werden andere Überlegungen weggelassen. Wenn Sie es sich leisten können, wird es interessant sein, zu lernen, indem Sie die Hyperparameter ändern oder versuchen, die Kampfregeln komplizierter zu gestalten.

Da ich ein Anfänger in der Stärkung des Lernens bin, können Sie auch auf Fehler hinweisen. Ich bin froh, dass mein Wissen gestärkt wurde.

Die Quelle ist auf Github. https://github.com/nanoseeing/DQ_Q-learning

Nachschlagewerk

Recommended Posts

Versuchen Sie Q-Lernen in einem Kampf im Drakue-Stil [Einführung in die Stärkung des Lernens]
Tiefe Stärkung des Lernens 1 Einführung in die Stärkung des Lernens
[Einführung in die Stärkung des Lernens] Teil 1 - Epsilon-Greedy-Algorithmus im Banditenspiel
[Einführung in die Stärkung des Lernens] Stärkung des Lernens, um sich vorerst zu bewegen
[Einführung] Stärkung des Lernens
[Für Anfänger] Einführung in die Vektorisierung beim maschinellen Lernen
Einführung in das maschinelle Lernen
Versuchen Sie, eine Blackjack-Strategie zu entwickeln, indem Sie das Lernen stärken (② Registrieren Sie die Umgebung im Fitnessstudio).
[Lernmemorandum] Einführung in vim
Eine Einführung in das maschinelle Lernen
Verstärkungslernen 5 Versuchen Sie, CartPole zu programmieren?
Versuchen Sie, eine Blackjack-Strategie zu entwickeln, indem Sie das Lernen stärken (③ Stärkung des Lernens in Ihrer eigenen OpenAI Gym-Umgebung).
Super Einführung in das maschinelle Lernen
Einführung in Deep Learning ~ Backpropagation ~
Ich las "Das Lernen mit Python von der Einführung bis zur Praxis stärken", Kapitel 1
Versuchen Sie, eine Blackjack-Strategie zu entwickeln, indem Sie das Lernen stärken ((1) Implementierung von Blackjack)
Lernen stärken 13 Probieren Sie Mountain_car mit ChainerRL aus.
Einführung in das maschinelle Lernen Schreiben von Notizen
Einführung in das tiefe Lernen ~ Funktionsnäherung ~
Versuchen Sie, Trace in Python zu berechnen
Versuchen Sie, Daten in MongoDB abzulegen
Einführung in Deep Learning ~ Codierungsvorbereitung ~
Stärkung des Lernens 8 Versuchen Sie, die Chainer-Benutzeroberfläche zu verwenden
Einführung in die Bibliothek für maschinelles Lernen SHOGUN
Probieren Sie Cython in kürzester Zeit aus
Einführung in Deep Learning ~ Dropout Edition ~
Einführung in Deep Learning ~ Forward Propagation ~
Einführung in Deep Learning ~ CNN Experiment ~
Möglichkeit der Anwendung auf die Evakuierungsroutengestaltung des Labyrinthproblems beim Lernen der Verstärkung
[Einführung in Python] Wie verwende ich eine Klasse in Python?
Einführung in das maschinelle Lernen: Funktionsweise des Modells
Verbessertes Lernen, um von null bis tief zu lernen
Einführung in Deep Learning ~ Falten und Pooling ~
Eine Einführung in OpenCV für maschinelles Lernen
Versuchen Sie, NumPys add.at mit Julia zu reproduzieren
Einführung in TensorFlow - Erläuterung der Begriffe und Konzepte des maschinellen Lernens
Einführung in Docker Erstellen einer Ubuntu-Umgebung in Ubuntu
Probieren Sie den erweiterten Standard-Lernalgorithmus PPO von OpenAI aus
Einführung in Vektoren: Lineare Algebra in Python <1>
Einführung in die Überprüfung der Wirksamkeit Kapitel 1 in Python geschrieben
Stärkung des Lernens 11 Probieren Sie OpenAI Acrobot mit ChainerRL aus.
Einführung in Deep Learning (1) --Chainer wird Anfängern leicht verständlich erklärt.