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.
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.
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.
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.
python 3.5.2
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.
Der Code sieht so aus
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.
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.
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.
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