[PYTHON] Löse dein eigenes Labyrinth mit Q-Lernen

Überblick

Mit Q-Learning, einem der verstärkenden Lernmethoden, habe ich versucht, ein einfaches Labyrinth meiner eigenen Arbeit zu lösen. Die Implementierung erfolgte mit Python.

Lernen stärken

Intensiviertes Lernen ist neben überwachtem und unbeaufsichtigtem Lernen eine der Methoden des maschinellen Lernens. Kurz gesagt, der "Agent" wird geschult, um den "Wert" in der gegebenen "Umgebung" zu maximieren. Beim Bestärkungslernen werden im Allgemeinen die drei Elemente Zustand * s *, Aktion * a * und Belohnung * r * verwendet. Unten finden Sie eine Beschreibung der einzelnen Elemente.

Status * s *: Zeigt den Status der "Umgebung" an. Aktion * a *: Gibt die Aktion an, die der "Agent" in einer bestimmten "Umgebung" ausgeführt hat. Belohnung * r *: Zeigt die Belohnung an, die durch die Ausführung einer Aktion durch den "Agenten" erhalten wurde.

Wenn Sie den "Wert der Ausführung einer Aktion * a * in einem bestimmten Zustand * s *" kennen, können Sie den Agenten trainieren, um den Wert zu maximieren.

Q Lernen

Die Q-Lernmethode ist eine Methode, bei der der "Wert, wenn eine Aktion * a * in einem bestimmten Zustand * s * ausgeführt wird" im vorherigen Abschnitt als Q-Wert bezeichnet wird und das Lernen durch Aktualisieren dieses Werts ausgeführt wird. Der Q-Wert bei der Ausführung der Aktion $ a_t $ im Zustand $ s_t $ wird als $ Q (s_t, a_t) $ ausgedrückt. Es wird entsprechend der Belohnung * r * aktualisiert, die diesen Q-Wert erhalten kann, aber nicht nur der direkten Aktion, die die Belohnung tatsächlich erhalten kann, sondern auch der vorherigen Aktion und der vorherigen Aktion ・ Man kann sagen, dass es insofern wertvoll ist, als es sich einer Belohnung nähert. Durch Einbeziehen und Aktualisieren des erwarteten Werts der Belohnung, die durch diese Aktion endgültig erzielt wird, berechnen wir daher, wie viel sie zu jedem Zeitpunkt wert ist. Die spezifische Formel lautet wie folgt. $ Q(s_t,a_t)=Q(s_t,a_t)+\alpha(r_{t+1}+\gamma \text{max}Q(s_{t+1},a_{t+1})-Q(s_t,a_t)) $

Die nächste t + 1 Belohnung $ r_ {t + 1} $ und der maximale Q-Wert im Zustand $ s_ {t + 1} $ $ \ text {max} beim Aktualisieren von $ Q (s_t, a_t) $ Verwenden Sie Q (s_ {t + 1}, a_ {t + 1}) $. $ \ Alpha $ und $ \ gamma $ sind Hyperparameter.

Umgebung

python 3.5.2

Implementierung (Labyrinthteil)

Die Implementierung des Labyrinthteils ist wie folgt. Die Struktur des Labyrinths ist ein Gitter von $ 5 \ mal 5 $. (Siehe Kommentare im Code für Details)

tresure.py


import numpy as np

class Game():
    def __init__(self):
        self.x_size = 5
        self.y_size = 5
        self.init_position = np.array([4,0])
        self.game_board = np.zeros((self.x_size,self.y_size))
        """
Labyrinthstruktur
        0 0 0 0 G
        0 D 0 D D
        0 0 D 0 0
        D 0 0 0 0
        S 0 D 0 0

        G = 1
        D = -1
        """
        self.game_board[0][4] = 1
        self.game_board[1][1] = -1
        self.game_board[3][0] = -1
        self.game_board[2][2] = -1
        self.game_board[1][3] = -1
        self.game_board[1][4] = -1
        self.game_board[4][2] = -1
    
    def judge(self,x,y):
        #Beurteilung, ob das Spiel vorbei ist
        if self.game_board[x][y] == 0:
            return 0
        elif self.game_board[x][y] == 1:
            return 1
        else:
            return -1
    
    def check_size(self,x,y):
        #Stellen Sie fest, ob es sich außerhalb des Labyrinths befindet
        if x < 0 or y < 0 or x >= self.x_size or y >= self.y_size:
            return 0
        else:
            return 1
    
    def move(self,position,direction):
        if direction == 'up':
            position[0] -= 1
        elif direction == 'down':
            position[0] += 1
        elif direction == 'right':
            position[1] -= 1
        elif direction == 'left':
            position[1] += 1
        
        return position

Die Regel ist, dass der Spieler vom S-Feld aus beginnen und sich für jeden Zustand zu einem beliebigen Feld nach oben, unten, links oder rechts bewegen kann. Wenn Sie G erreichen, erhalten Sie ein Ziel und eine Belohnung. Wenn Sie zu D wechseln, ist das Spiel beendet und Sie erhalten eine negative Belohnung als Strafe.

Implementierung (Lernteil)

Der Code sieht so aus

Code des gesamten Lernteils

train.py


import numpy as np
from treasure import Game
import copy
import matplotlib.pyplot as plt

#board proscess
game = Game()
game_board = game.game_board
print(game_board)
game_direction = ['up','down','left','right']

def get_action(Q_table,dire,epsilon,x,y):

    #random choice
    if np.random.rand() < epsilon:
        return np.random.choice(dire)

    else:
        return dire[np.argmax(Q_table[x,y])]

def game_init():
    #init process
    game = Game()
    position= game.init_position
    
    return game,position

def game_reward(game,position):
    #result print
    if game.judge(position[0],position[1]) == 1:
        #print('You got a goal!')
        return 1
    elif game.judge(position[0],position[1]) == -1:
        #print('You died..')
        return -1
    else:
        return 0

def game_step(game,position,Q_table,dire,epsilon):
    while(True):
        pos = copy.deepcopy(position)
        direction = get_action(Q_table,dire,epsilon,pos[0],pos[1])
        index_dire = dire.index(direction)
        move_position = game.move(pos,direction)
        if game.check_size(pos[0],pos[1]):
            break
    reward = game_reward(game,move_position)

    return move_position,index_dire,reward

def Q_koushin(Q,state_x,state_y,state_a,s_next_x,state_next_y,alpha,reward,gamma):
    Q[state_x,state_y,state_a] += alpha*(reward + gamma*np.max(Q[s_next_x,state_next_y]) - Q[state_x,state_y,state_a])
    return Q[state_x,state_y,state_a]


if __name__ == '__main__':
    #hyper parameter
    epsilon = 0.01
    alpha = 0.5
    gamma = 0.8
    Q_table = np.zeros((game_board.shape[0],game_board.shape[1],len(game_direction)))
    episode = 200
    sucess = []

    for i in range(episode):
        game,position = game_init()
        while(not game.judge(position[0],position[1])):
            next_position,dire,reward = game_step(game,position,Q_table,game_direction,epsilon)
            Q_table[position[0],position[1],dire] = Q_koushin(Q_table,position[0],position[1],dire,next_position[0],next_position[1],alpha,reward,gamma)
            position = next_position
        
        if i % 10 == 0:
            count = 0
            heatmap = np.zeros((game_board.shape[0],game_board.shape[1]))
            for j in range(100):
                game,position = game_init()
                while(not game.judge(position[0],position[1])):
                    next_position,dire,reward = game_step(game,position,Q_table,game_direction,epsilon)
                    position = next_position
                    heatmap[next_position[0]][next_position[1]] += 1
                if reward == 1:
                    count += 1
            sucess.append(count)
            print(i)
            print(heatmap)
    print(sucess)

Ich werde jeden Teil unten erklären.

** Maßnahmen nach der epsilon-gierigen Methode **

train.py


def get_action(Q_table,dire,epsilon,x,y):
    #random choice
    if np.random.rand() < epsilon:
        return np.random.choice(dire)

    else:
        return dire[np.argmax(Q_table[x,y])]

Es bewegt sich zufällig mit einer Wahrscheinlichkeit von $ \ epsilon $ und wählt ansonsten das mit dem höchsten Q-Wert aus.

** Belohnungsfunktionseinstellungen **

train.py


def game_reward(game,position):
    #result print
    if game.judge(position[0],position[1]) == 1:
        #print('You got a goal!')
        return 1
    elif game.judge(position[0],position[1]) == -1:
        #print('You died..')
        return -1
    else:
        return 0

Als das Ziel erreicht war, war die Belohnung 1, als das Spiel vorbei war, war die Strafe -1 und zu anderen Zeiten war es 0.

** Q-Wert aktualisieren **

train.py


def Q_koushin(Q,state_x,state_y,state_a,s_next_x,state_next_y,alpha,reward,gamma):
    Q[state_x,state_y,state_a] += alpha*(reward + gamma*np.max(Q[s_next_x,state_next_y]) - Q[state_x,state_y,state_a])
    return Q[state_x,state_y,state_a]

Aktualisieren Sie den Q-Wert gemäß der Formel.

** Spieler bewegen **

train.py


def game_step(game,position,Q_table,dire,epsilon):
    while(True):
        pos = copy.deepcopy(position)
        direction = get_action(Q_table,dire,epsilon,pos[0],pos[1])
        index_dire = dire.index(direction)
        move_position = game.move(pos,direction)
        if game.check_size(pos[0],pos[1]):
            break
    reward = game_reward(game,move_position)

    return move_position,index_dire,reward

Machen Sie während des Spiels einen Zug. Es beurteilt, ob es sich außerhalb des Labyrinths befindet, und gibt, wenn es in Ordnung ist, die Position des Ziels, die Bewegungsrichtung und die erhaltene Belohnung zurück. Da die Liste in Python als Referenz übergeben wird, habe ich eine tiefe Kopie erstellt, damit die ursprüngliche Liste nicht geändert wird.

** Lernteil **

train.py


if __name__ == '__main__':
    #hyper parameter
    epsilon = 0.01
    alpha = 0.5
    gamma = 0.8
    Q_table = np.zeros((game_board.shape[0],game_board.shape[1],len(game_direction)))
    episode = 200
    sucess = []

    for i in range(episode):
        game,position = game_init()
        while(not game.judge(position[0],position[1])):
            next_position,dire,reward = game_step(game,position,Q_table,game_direction,epsilon)
            Q_table[position[0],position[1],dire] = Q_koushin(Q_table,position[0],position[1],dire,next_position[0],next_position[1],alpha,reward,gamma)
            position = next_position
        
        if (i+1) % 20 == 0:
            count = 0
            heatmap = np.zeros((game_board.shape[0],game_board.shape[1]))
            for j in range(100):
                game,position = game_init()
                while(not game.judge(position[0],position[1])):
                    next_position,dire,reward = game_step(game,position,Q_table,game_direction,epsilon)
                    position = next_position
                    heatmap[next_position[0]][next_position[1]] += 1
                if reward == 1:
                    count += 1
            sucess.append(count)
            print('%d mal' %(i+1))
            print(heatmap)

Als Q_table haben wir eine Matrix von $ 5 \ times5 \ times4 $ in (Labyrinthquadrate) $ \ times $ (Bewegungsrichtung nach oben, unten, links und rechts) erstellt. Der Q-Wert wurde für jeden Zug aktualisiert, bis das Ziel erreicht wurde oder das Spiel beendet war. Außerdem habe ich jedes Mal, wenn ich das Spiel 20 Mal beendet habe, das Spiel 100 Mal mit der Q_table gespielt und untersucht, wie viele Tore ich hatte und wo ich bestanden habe.

Ergebnis

Das Ergebnis ist wie folgt.

#Labyrinthstrukturdiagramm
[[ 0.  0.  0.  0.  G.]
 [ 0. -1.  0. -1. -1.]
 [ 0.  0. -1.  0.  0.]
 [-1.  0.  0.  0.  0.]
 [ S.  0. -1.  0.  0.]]
Um 20 mal
[[4.500e+01 1.800e+01 1.500e+01 6.000e+00 3.000e+00]
 [4.000e+01 1.400e+01 5.000e+00 3.000e+00 5.000e+00]
 [9.000e+00 4.148e+03 8.000e+00 8.270e+02 5.000e+00]
 [6.700e+01 4.172e+03 1.100e+01 8.350e+02 3.000e+00]
 [0.000e+00 4.900e+01 0.000e+00 2.000e+00 0.000e+00]]
40 mal
[[1.600e+01 1.000e+01 5.000e+00 2.000e+00 2.000e+00]
 [1.300e+01 1.000e+01 2.000e+00 3.000e+00 3.000e+00]
 [7.000e+00 4.105e+03 9.000e+00 6.400e+02 3.000e+00]
 [7.300e+01 4.132e+03 7.000e+00 6.450e+02 2.000e+00]
 [0.000e+00 4.900e+01 0.000e+00 2.000e+00 0.000e+00]]
Um 60 mal
[[1.900e+01 8.000e+00 3.000e+00 3.000e+00 3.000e+00]
 [1.700e+01 1.600e+01 0.000e+00 2.000e+00 4.000e+00]
 [6.000e+00 3.754e+03 8.000e+00 2.120e+02 4.000e+00]
 [6.700e+01 3.783e+03 6.000e+00 2.140e+02 2.000e+00]
 [0.000e+00 5.600e+01 0.000e+00 0.000e+00 0.000e+00]]
Um 80 mal
[[1.100e+01 6.000e+00 6.000e+00 6.000e+00 6.000e+00]
 [1.100e+01 1.200e+01 0.000e+00 6.000e+00 4.000e+00]
 [6.000e+00 3.544e+03 1.300e+01 2.069e+03 1.107e+03]
 [5.900e+01 3.571e+03 1.500e+01 2.080e+03 1.109e+03]
 [0.000e+00 5.700e+01 0.000e+00 3.000e+00 2.000e+00]]
Um 100 mal
[[8.000e+00 8.000e+00 8.000e+00 8.000e+00 8.000e+00]
 [8.000e+00 1.600e+01 0.000e+00 5.000e+00 2.000e+00]
 [8.000e+00 4.783e+03 1.500e+01 3.083e+03 1.225e+03]
 [5.400e+01 4.824e+03 2.300e+01 3.100e+03 1.224e+03]
 [0.000e+00 7.100e+01 0.000e+00 1.000e+01 1.000e+00]]
Um 120 mal
[[1.100e+01 1.100e+01 1.100e+01 1.100e+01 1.100e+01]
 [1.100e+01 6.000e+00 0.000e+00 6.000e+00 3.000e+00]
 [1.100e+01 4.215e+03 1.500e+01 2.403e+03 1.660e+03]
 [5.900e+01 4.251e+03 1.900e+01 2.416e+03 1.665e+03]
 [1.000e+00 6.400e+01 0.000e+00 4.000e+00 4.000e+00]]
140 mal
[[ 99. 100.  98.  96.  96.]
 [100.   4.   1.   0.   0.]
 [101. 101.   0.   0.   0.]
 [  0. 102.   0.   0.   0.]
 [  0. 102.   0.   0.   0.]]
Um 160 mal
[[ 96.  95.  96.  96.  95.]
 [ 97.   2.   0.   0.   0.]
 [ 97. 100.   1.   0.   0.]
 [  0.  99.   0.   0.   0.]
 [  0. 100.   2.   0.   0.]]
180 mal
[[101. 100. 100. 100.  99.]
 [101.   0.   0.   1.   0.]
 [100. 101.   0.   0.   0.]
 [  0. 101.   0.   0.   0.]
 [  0. 100.   0.   0.   0.]]
Um 200 mal
[[ 99.  99. 101. 100.  99.]
 [100.   1.   1.   0.   0.]
 [100. 100.   0.   0.   0.]
 [  0. 101.   0.   0.   0.]
 [  0. 101.   0.   0.   0.]]

#Anzahl der Tore(100 mal)
[3, 2, 3, 6, 8, 11, 96, 95, 99, 99]

Betrachtet man die Ergebnisse, so war das Spiel in den frühen Stadien, in denen das Lernen nicht vorankam, in der Nähe des Starts oft zu Ende, aber nach 140-maligem Lernen scheint es, dass fast der richtige Weg gefunden werden kann. Ich kann es sehen.

Zusammenfassung

Ich habe versucht, ein einfaches Labyrinth mit Q-Learning zu lösen. Es war eine gute Gelegenheit, die Implementierung zu üben. In Zukunft möchte ich kompliziertere Spiele mit einer anderen Methode des verstärkenden Lernens spielen.

Verweise

Platinum Data Blog von BrainPad Einführung in die Stärkung des Lernens ~ Grundkenntnisse für diejenigen, die lernen möchten, das Lernen zu stärken ~ 2017 https://blog.brainpad.co.jp/entry/2017/02/24/121500

Recommended Posts

Löse dein eigenes Labyrinth mit Q-Lernen
Löse dein eigenes Labyrinth mit DQN
Lösen Sie OpenAI Gym Copy-v0 mit Q-Learning
Trainiere UGATIT mit deinem eigenen Datensatz
Ihr eigener Twitter-Client mit Django
[Stärkung des Lernens] DQN mit Ihrer eigenen Bibliothek
Erstellen Sie mit Twisted Ihren eigenen DNS-Server
Erstellen Sie mit SQLAlchemy Ihren eigenen zusammengesetzten Wert
So importieren Sie Ihr eigenes Modul mit jupyter
Veröffentlichen Sie Ihre eigene Python-Bibliothek auf Homebrew
Versuchen Sie, Ihr eigenes AWS-SDK mit bash zu erstellen
Erstellen Sie schnell Ihr eigenes Modul mit setuptools (Python)
Trainieren Sie Stanford NER Tagger mit Ihren eigenen Daten
Erstelle deinen eigenen Musik-Player mit Bottle0.13 + jPlayer2.5!
Schritte zum Installieren Ihrer eigenen Bibliothek mit pip
Ablauf beim Erstellen eines eigenen Pakets mit setup.py mit Python
Erstellen Sie Ihre eigene Ausnahme
Memo zum Erstellen einer eigenen Box mit Peppers Python
Rufen Sie mit Go mit cgo Ihre eigene C-Sprachbibliothek auf
Löse AtCoder 167 mit Python
Schreiben Sie Ihre eigene Aktivierungsfunktion mit Pytorch (hartes Sigmoid)
Rufen wir Ihre eigene C ++ - Bibliothek mit Python auf (Einstellungen)
Definieren Sie Ihre eigene Distanzfunktion mit k-Mitteln des Scikit-Lernens
Löse Mathe mit Python
Löse Mathe mit PuLP
Löse POJ 2386 mit Python
Versuchen Sie, Ihre eigenen Objekte mit Prioritätswarteschlangen in Python zu sortieren
Führen Sie die Intelligenz Ihrer eigenen Python-Bibliothek mit VScode aus.
Lernen Sie "x86-Architektur mit Ihrem eigenen Emulator" mit Manjaro (Linux)
Reinforcement Learning 23 Erstellen und verwenden Sie Ihr eigenes Modul mit Colaboratory
Löse AtCoder ABC166 mit Python
Arbeiten Sie mit Websites mit Python_Webbrowser
Erstellen Sie Ihre eigene Django-Middleware
Erstellen Sie Ihre eigene VPC mit einem einzigen öffentlichen Subnetz Nur mit boto
[Einführung in Style GAN] Einzigartiges Lernen von Animation mit Ihrer eigenen Maschine ♬
So erstellen Sie Ihre eigene Domain-Site mit Heroku (kostenloser Plan)
Einführung in Deep Learning (2) - Versuchen Sie Ihre eigene nichtlineare Regression mit Chainer-
Zeichnen Sie mit PySide Ihren eigenen Drop Indicator (Realisieren Sie QProxyStyle mit schwarzer Magie)