Ceci est mon premier article sur Qiita. Nous consultons et développons principalement l'apprentissage automatique dans une société appelée Ridge-i.
J'ai l'occasion d'enseigner sur le renforcement de l'apprentissage, donc basé sur la troisième ligne
--Monte Carlo
Je l'ai implémenté avec Jupyter (ipython) et créé du matériel pédagogique.
Au fait, si vous êtes un joueur fort, seul le tirage au sort doit être répété. (C'est un gars célèbre de WarGame.)
Comme conclusion
--Monte Carlo Facile à mettre en œuvre. Presque aucune perte dans 100 essais (perd parfois dans environ 50) --Q-Learning Faites attention à la conception renouvelable. Le plus fort dans 100000 batailles s'il est d'environ 3 lignes
Il n'a fallu que 1 à 2 heures pour mettre en œuvre le Q-Learning, mais il a fallu environ 6 heures pour que DQN apprenne correctement. (Pleurs)
En termes d'amélioration de l'efficacité d'apprentissage, il serait préférable de retourner et de faire pivoter correctement le tableau, mais cette fois je l'ai choisi en mettant l'accent sur la clarté. De plus, je n'ai pas correctement conçu l'interface et masqué les variables, donc je la viole parfois. Ignorez cette zone.
Cliquez ici pour Github. https://github.com/narisan25/TTT-RL
Si vous souhaitez connaître les détails théoriques, veuillez nous contacter séparément. Également souligné, amélioré, conseillé, super accueil.
Ceci est une esquisse approximative. Il y a beaucoup de points à améliorer, mais cette fois nous allons nous concentrer sur la clarté et la vitesse (il suffit de bouger)
Mettez 1 pour X, 0 pour vide et -1 pour ○ dans le tableau 0-9.
EMPTY=0
PLAYER_X=1
PLAYER_O=-1
MARKS={PLAYER_X:"X",PLAYER_O:"O",EMPTY:" "}
DRAW=2
class TTTBoard:
def __init__(self,board=None):
if board==None:
self.board = []
for i in range(9):self.board.append(EMPTY)
else:
self.board=board
self.winner=None
def get_possible_pos(self):
pos=[]
for i in range(9):
if self.board[i]==EMPTY:
pos.append(i)
return pos
def print_board(self):
tempboard=[]
for i in self.board:
tempboard.append(MARKS[i])
row = ' {} | {} | {} '
hr = '\n-----------\n'
print((row + hr + row + hr + row).format(*tempboard))
def check_winner(self):
win_cond = ((1,2,3),(4,5,6),(7,8,9),(1,4,7),(2,5,8),(3,6,9),(1,5,9),(3,5,7))
for each in win_cond:
if self.board[each[0]-1] == self.board[each[1]-1] == self.board[each[2]-1]:
if self.board[each[0]-1]!=EMPTY:
self.winner=self.board[each[0]-1]
return self.winner
return None
def check_draw(self):
if len(self.get_possible_pos())==0 and self.winner is None:
self.winner=DRAW
return DRAW
return None
def move(self,pos,player):
if self.board[pos]== EMPTY:
self.board[pos]=player
else:
self.winner=-1*player
self.check_winner()
self.check_draw()
def clone(self):
return TTTBoard(self.board.copy())
def switch_player(self):
if self.player_turn == self.player_x:
self.player_turn=self.player_o
else:
self.player_turn=self.player_x
Faites-en un modèle Observer + Mediator. Avec cela, vous pouvez gérer les tours, les victoires et les pertes, l'affichage, etc. tout en empêchant le joueur de toucher directement le plateau.
class TTT_GameOrganizer:
act_turn=0
winner=None
def __init__(self,px,po,nplay=1,showBoard=True,showResult=True,stat=100):
self.player_x=px
self.player_o=po
self.nwon={px.myturn:0,po.myturn:0,DRAW:0}
self.nplay=nplay
self.players=(self.player_x,self.player_o)
self.board=None
self.disp=showBoard
self.showResult=showResult
self.player_turn=self.players[random.randrange(2)]
self.nplayed=0
self.stat=stat
def progress(self):
while self.nplayed<self.nplay:
self.board=TTTBoard()
while self.board.winner==None:
if self.disp:print("Turn is "+self.player_turn.name)
act=self.player_turn.act(self.board)
self.board.move(act,self.player_turn.myturn)
if self.disp:self.board.print_board()
if self.board.winner != None:
# notice every player that game ends
for i in self.players:
i.getGameResult(self.board)
if self.board.winner == DRAW:
if self.showResult:print ("Draw Game")
elif self.board.winner == self.player_turn.myturn:
out = "Winner : " + self.player_turn.name
if self.showResult: print(out)
else:
print ("Invalid Move!")
self.nwon[self.board.winner]+=1
else:
self.switch_player()
#Notice other player that the game is going
self.player_turn.getGameResult(self.board)
self.nplayed+=1
if self.nplayed%self.stat==0 or self.nplayed==self.nplay:
print(self.player_x.name+":"+str(self.nwon[self.player_x.myturn])+","+self.player_o.name+":"+str(self.nwon[self.player_o.myturn])
+",DRAW:"+str(self.nwon[DRAW]))
def switch_player(self):
if self.player_turn == self.player_x:
self.player_turn=self.player_o
else:
self.player_turn=self.player_x
C'est un simple que vous venez de mettre là où vous pouvez le mettre.
import random
class PlayerRandom:
def __init__(self,turn):
self.name="Random"
self.myturn=turn
def act(self,board):
acts=board.get_possible_pos()
i=random.randrange(len(acts))
return acts[i]
def getGameResult(self,board):
pass
class PlayerHuman:
def __init__(self,turn):
self.name="Human"
self.myturn=turn
def act(self,board):
valid = False
while not valid:
try:
act = input("Where would you like to place " + str(self.myturn) + " (1-9)? ")
act = int(act)
#if act >= 1 and act <= 9 and board.board[act-1]==EMPTY:
if act >= 1 and act <= 9:
valid=True
return act-1
else:
print ("That is not a valid move! Please try again.")
except Exception as e:
print (act + "is not a valid move! Please try again.")
return act
def getGameResult(self,board):
if board.winner is not None and board.winner!=self.myturn and board.winner!=DRAW:
print("I lost...")
Tout d'abord, combattons les humains au hasard. Dommage si vous perdez.
def Human_vs_Random():
p1=PlayerHuman(PLAYER_X)
p2=PlayerRandom(PLAYER_O)
game=TTT_GameOrganizer(p1,p2)
game.progress()
Human_vs_Random()
Turn is Random
| |
-----------
| | O
-----------
| |
Turn is Human
Where would you like to place 1 (1-9)? 1
X | |
-----------
| | O
-----------
| |
Turn is Random
X | |
-----------
O | | O
-----------
| |
Turn is Human
Where would you like to place 1 (1-9)? 2
X | X |
-----------
O | | O
-----------
| |
Turn is Random
X | X |
-----------
O | O | O
-----------
| |
I lost...
Winner : Random
Human:0,Random:1,DRAW:0
Ce qui restait dans le journal était un exemple de perte de soins.
Comme prévu, c'est ennuyeux si c'est juste aléatoire, donc s'il y a un endroit où vous pouvez gagner avec votre prochain coup, essayez de le pointer correctement. (Aléatoire sinon)
class PlayerAlphaRandom:
def __init__(self,turn,name="AlphaRandom"):
self.name=name
self.myturn=turn
def getGameResult(self,winner):
pass
def act(self,board):
acts=board.get_possible_pos()
#see only next winnable act
for act in acts:
tempboard=board.clone()
tempboard.move(act,self.myturn)
# check if win
if tempboard.winner==self.myturn:
#print ("Check mate")
return act
i=random.randrange(len(acts))
return acts[i]
Maintenant, d'ici, nous entrerons dans le domaine de l'apprentissage amélioré. A Monte Carlo, nous essaierons un certain nombre de fois jusqu'à la fin du jeu selon une certaine politique, et chercherons un bon coup en voyant le taux de victoire.
Le point important de Monte Carlo est que la force dépend du nombre de "temps fixes" et "d'une certaine politique".
Pour "une certaine politique", j'ai utilisé l'aléatoire amélioré que vous avez mentionné plus tôt. Après avoir essayé "un certain nombre de fois", s'il dépasse 100 fois, il semble que le mauvais coup ne soit pas pris. Si c'est environ 50 fois, vous perdrez parfois en fonction du nombre aléatoire.
À partir de là, vous pouvez intégrer les antécédents à une planification dynamique ou dériver de Montecult Tree Exploration (MCTS) pour combiner des politiques fortes et faibles, mais je ne les mentionnerai pas cette fois.
class PlayerMC:
def __init__(self,turn,name="MC"):
self.name=name
self.myturn=turn
def getGameResult(self,winner):
pass
def win_or_rand(self,board,turn):
acts=board.get_possible_pos()
#see only next winnable act
for act in acts:
tempboard=board.clone()
tempboard.move(act,turn)
# check if win
if tempboard.winner==turn:
return act
i=random.randrange(len(acts))
return acts[i]
def trial(self,score,board,act):
tempboard=board.clone()
tempboard.move(act,self.myturn)
tempturn=self.myturn
while tempboard.winner is None:
tempturn=tempturn*-1
tempboard.move(self.win_or_rand(tempboard,tempturn),tempturn)
if tempboard.winner==self.myturn:
score[act]+=1
elif tempboard.winner==DRAW:
pass
else:
score[act]-=1
def getGameResult(self,board):
pass
def act(self,board):
acts=board.get_possible_pos()
scores={}
n=50
for act in acts:
scores[act]=0
for i in range(n):
#print("Try"+str(i))
self.trial(scores,board,act)
#print(scores)
scores[act]/=n
max_score=max(scores.values())
for act, v in scores.items():
if v == max_score:
#print(str(act)+"="+str(v))
return act
p1=PlayerMC(PLAYER_X,"M1")
p2=PlayerMC(PLAYER_O,"M2")
game=TTT_GameOrganizer(p1,p2,10,False)
game.progress()
Draw Game
Winner : M2
Draw Game
Draw Game
Draw Game
Draw Game
Draw Game
Winner : M2
Draw Game
Draw Game
M1:0,M2:2,DRAW:8
C'est presque un match nul. Si vous en avez envie, essayez 100 essais. Je pense que ce sera un match nul.
Q-Learning
En passant, en parlant de renforcement de l'apprentissage, Q-Learning. Pendant le jeu, la récompense est de 0, si vous gagnez, vous obtenez +1. Si vous perdez, vous obtenez -1 et le nul est de 0. Sur cette base, nous mettrons à jour le dictionnaire de Q (s, a) avec la formule de mise à jour suivante.
Q(s,a) = Q(s,a) + alpha (reward + gammma* max(Q(s',a')- Q(s,a))
L'important est de recommander des mouvements aléatoires avec le concept de ε-gourmand. Sinon, vous tomberez bientôt dans l'optimum local. La valeur du premier Q est également importante. Si vous ne le faites pas, vous ne voudrez pas le chercher tout de suite. Un enfant égoïste.
J'ai été surpris de savoir quoi faire avec max (Q) à la fin du jeu et d'oublier de mettre à jour pendant le jeu.
class PlayerQL:
def __init__(self,turn,name="QL",e=0.2,alpha=0.3):
self.name=name
self.myturn=turn
self.q={} #set of s,a
self.e=e
self.alpha=alpha
self.gamma=0.9
self.last_move=None
self.last_board=None
self.totalgamecount=0
def policy(self,board):
self.last_board=board.clone()
acts=board.get_possible_pos()
#Explore sometimes
if random.random() < (self.e/(self.totalgamecount//10000+1)):
i=random.randrange(len(acts))
return acts[i]
qs = [self.getQ(tuple(self.last_board.board),act) for act in acts]
maxQ= max(qs)
if qs.count(maxQ) > 1:
# more than 1 best option; choose among them randomly
best_options = [i for i in range(len(acts)) if qs[i] == maxQ]
i = random.choice(best_options)
else:
i = qs.index(maxQ)
self.last_move = acts[i]
return acts[i]
def getQ(self, state, act):
# encourage exploration; "optimistic" 1.0 initial values
if self.q.get((state, act)) is None:
self.q[(state, act)] = 1
return self.q.get((state, act))
def getGameResult(self,board):
r=0
if self.last_move is not None:
if board.winner is None:
self.learn(self.last_board,self.last_move, 0, board)
pass
else:
if board.winner == self.myturn:
self.learn(self.last_board,self.last_move, 1, board)
elif board.winner !=DRAW:
self.learn(self.last_board,self.last_move, -1, board)
else:
self.learn(self.last_board,self.last_move, 0, board)
self.totalgamecount+=1
self.last_move=None
self.last_board=None
def learn(self,s,a,r,fs):
pQ=self.getQ(tuple(s.board),a)
if fs.winner is not None:
maxQnew=0
else:
maxQnew=max([self.getQ(tuple(fs.board),act) for act in fs.get_possible_pos()])
self.q[(tuple(s.board),a)]=pQ+self.alpha*((r+self.gamma*maxQnew)-pQ)
#print (str(s.board)+"with "+str(a)+" is updated from "+str(pQ)+" refs MAXQ="+str(maxQnew)+":"+str(r))
#print(self.q)
def act(self,board):
return self.policy(board)
pQ=PlayerQL(PLAYER_O,"QL1")
p2=PlayerQL(PLAYER_X,"QL2")
game=TTT_GameOrganizer(pQ,p2,100000,False,False,10000)
game.progress()
QL1:4371,QL2:4436,DRAW:1193
QL1:8328,QL2:8456,DRAW:3216
QL1:11903,QL2:11952,DRAW:6145
QL1:14268,QL2:14221,DRAW:11511
QL1:15221,QL2:15099,DRAW:19680
QL1:15730,QL2:15667,DRAW:28603
QL1:16136,QL2:16090,DRAW:37774
QL1:16489,QL2:16439,DRAW:47072
QL1:16832,QL2:16791,DRAW:56377
QL1:17128,QL2:17121,DRAW:65751
C'est presque convergé sur le tirage au sort. Vous pouvez voir que la victoire et la défaite sont divisées par ε.
Mettez ε à zéro, éliminez les éléments aléatoires et essayez d'attaquer avec le meilleur coup
pQ.e=0
p2=PlayerMC(PLAYER_X,"M1")
game=TTT_GameOrganizer(pQ,p2,100,False,False,10)
game.progress()
QL1:1,M1:0,DRAW:9
QL1:1,M1:0,DRAW:19
QL1:2,M1:0,DRAW:28
QL1:2,M1:0,DRAW:38
QL1:3,M1:0,DRAW:47
QL1:4,M1:0,DRAW:56
QL1:5,M1:0,DRAW:65
QL1:5,M1:0,DRAW:75
QL1:6,M1:0,DRAW:84
QL1:6,M1:0,DRAW:94
Monte Carlo a également perdu de temps en temps. Après tout, Monte Carlo ne peut pas échapper aux caprices des nombres aléatoires. Au fait, si vous combattez Q-Learning dans cet état, cela vous fera très mal.
DQN (Deep Q Network)
Eh bien, le sujet principal de cette fois. C'est DQN. Le goulot d'étranglement de Q-Learning est que la table Q (s, a) devient énorme. Ce serait bien s'il était disposé en trois rangées, mais dans Go, S et a seraient d'énormes souvenirs. Dans Q-Network, Q (s) est utilisé pour émettre la récompense attendue pour chaque a et prendre argmax. Avec Deep Q Network, "Vous trouverez une fonctionnalité qui gagne par vous-même!?", N'est-il pas acceptable de jouer environ 1000 fois? J'en étais fou.
・ ・ ・ ・ Mais je suis resté coincé.
Cela ne devient pas du tout plus fort. De plus, il y a trop d'hyper paramètres. Combien de couches cachées dois-je avoir? L'erreur est-elle correcte avec SME? Est-ce que l'Optimizer Adam ou SGD? Honnêtement, je voulais Grid Search. Mais comme il n'y a pas d'enseignant en premier lieu, il n'est pas possible de mesurer la perte. La précision ne peut être connue qu'en combattant l'adversaire.
De plus, même si j'apprenais, le lien variable était coupé et je n'ai pas appris du tout. Je suis vraiment dedans. De plus, c'est lent car je faisais diverses choses sur une machine sans GPU. .. .. Sans GPU, il faut environ 5 à 10 minutes pour apprendre.
import chainer
from chainer import Function, gradient_check, Variable, optimizers, serializers, utils
import chainer.functions as F
import chainer.links as L
import numpy as np
from chainer import computational_graph as c
# Network definition
class MLP(chainer.Chain):
def __init__(self, n_in, n_units, n_out):
super(MLP, self).__init__(
l1=L.Linear(n_in, n_units), # first layer
l2=L.Linear(n_units, n_units), # second layer
l3=L.Linear(n_units, n_units), # Third layer
l4=L.Linear(n_units, n_out), # output layer
)
def __call__(self, x, t=None, train=False):
h = F.leaky_relu(self.l1(x))
h = F.leaky_relu(self.l2(h))
h = F.leaky_relu(self.l3(h))
h = self.l4(h)
if train:
return F.mean_squared_error(h,t)
else:
return h
def get(self,x):
# input x as float, output float
return self.predict(Variable(np.array([x]).astype(np.float32).reshape(1,1))).data[0][0]
class DQNPlayer:
def __init__(self, turn,name="DQN",e=1,dispPred=False):
self.name=name
self.myturn=turn
self.model = MLP(9, 162,9)
self.optimizer = optimizers.SGD()
self.optimizer.setup(self.model)
self.e=e
self.gamma=0.95
self.dispPred=dispPred
self.last_move=None
self.last_board=None
self.last_pred=None
self.totalgamecount=0
self.rwin,self.rlose,self.rdraw,self.rmiss=1,-1,0,-1.5
def act(self,board):
self.last_board=board.clone()
x=np.array([board.board],dtype=np.float32).astype(np.float32)
pred=self.model(x)
if self.dispPred:print(pred.data)
self.last_pred=pred.data[0,:]
act=np.argmax(pred.data,axis=1)
if self.e > 0.2: #decrement epsilon over time
self.e -= 1/(20000)
if random.random() < self.e:
acts=board.get_possible_pos()
i=random.randrange(len(acts))
act=acts[i]
i=0
while board.board[act]!=EMPTY:
#print("Wrong Act "+str(board.board)+" with "+str(act))
self.learn(self.last_board,act, -1, self.last_board)
x=np.array([board.board],dtype=np.float32).astype(np.float32)
pred=self.model(x)
#print(pred.data)
act=np.argmax(pred.data,axis=1)
i+=1
if i>10:
print("Exceed Pos Find"+str(board.board)+" with "+str(act))
acts=self.last_board.get_possible_pos()
act=acts[random.randrange(len(acts))]
self.last_move=act
#self.last_pred=pred.data[0,:]
return act
def getGameResult(self,board):
r=0
if self.last_move is not None:
if board.winner is None:
self.learn(self.last_board,self.last_move, 0, board)
pass
else:
if board.board== self.last_board.board:
self.learn(self.last_board,self.last_move, self.rmiss, board)
elif board.winner == self.myturn:
self.learn(self.last_board,self.last_move, self.rwin, board)
elif board.winner !=DRAW:
self.learn(self.last_board,self.last_move, self.rlose, board)
else: #DRAW
self.learn(self.last_board,self.last_move, self.rdraw, board)
self.totalgamecount+=1
self.last_move=None
self.last_board=None
self.last_pred=None
def learn(self,s,a,r,fs):
if fs.winner is not None:
maxQnew=0
else:
x=np.array([fs.board],dtype=np.float32).astype(np.float32)
maxQnew=np.max(self.model(x).data[0])
update=r+self.gamma*maxQnew
#print(('Prev Board:{} ,ACT:{}, Next Board:{}, Get Reward {}, Update {}').format(s.board,a,fs.board,r,update))
#print(('PREV:{}').format(self.last_pred))
self.last_pred[a]=update
x=np.array([s.board],dtype=np.float32).astype(np.float32)
t=np.array([self.last_pred],dtype=np.float32).astype(np.float32)
self.model.zerograds()
loss=self.model(x,t,train=True)
loss.backward()
self.optimizer.update()
#print(('Updated:{}').format(self.model(x).data))
#print (str(s.board)+"with "+str(a)+" is updated from "+str(pQ)+" refs MAXQ="+str(maxQnew)+":"+str(r))
#print(self.q)
La source est longue. .. .. Je pense qu'il y a des preuves d'essais et d'erreurs, mais je ne les ai pas nettoyés.
Avec cela, vous apprendrez d'abord à frapper et à gagner.
pDQ=DQNPlayer(PLAYER_X)
p2=PlayerAlphaRandom(PLAYER_O)
game=TTT_GameOrganizer(pDQ,p2,20000,False,False,1000)
game.progress()
DQN:206,AlphaRandom:727,DRAW:67
DQN:468,AlphaRandom:1406,DRAW:126
DQN:861,AlphaRandom:1959,DRAW:180
DQN:1458,AlphaRandom:2315,DRAW:227
DQN:2185,AlphaRandom:2560,DRAW:255
DQN:3022,AlphaRandom:2704,DRAW:274
DQN:3832,AlphaRandom:2856,DRAW:312
DQN:4632,AlphaRandom:3023,DRAW:345
DQN:5481,AlphaRandom:3153,DRAW:366
DQN:6326,AlphaRandom:3280,DRAW:394
DQN:7181,AlphaRandom:3400,DRAW:419
DQN:8032,AlphaRandom:3522,DRAW:446
DQN:8902,AlphaRandom:3618,DRAW:480
DQN:9791,AlphaRandom:3705,DRAW:504
DQN:10673,AlphaRandom:3793,DRAW:534
DQN:11545,AlphaRandom:3893,DRAW:562
DQN:12420,AlphaRandom:3986,DRAW:594
DQN:13300,AlphaRandom:4074,DRAW:626
DQN:14183,AlphaRandom:4158,DRAW:659
DQN:15058,AlphaRandom:4246,DRAW:696
C'est devenu beaucoup plus fort. Comme prévu, il semble que vous puissiez battre le aléatoire amélioré.
pDQ.e=1
game=TTT_GameOrganizer(pDQ,pQ,30000,False,False,1000)
game.progress()
DQN:4,QL1:436,DRAW:560
DQN:6,QL1:790,DRAW:1204
DQN:6,QL1:1135,DRAW:1859
DQN:6,QL1:1472,DRAW:2522
DQN:6,QL1:1801,DRAW:3193
DQN:6,QL1:2123,DRAW:3871
DQN:6,QL1:2439,DRAW:4555
DQN:6,QL1:2777,DRAW:5217
DQN:7,QL1:3128,DRAW:5865
DQN:9,QL1:3648,DRAW:6343
DQN:13,QL1:4132,DRAW:6855
DQN:13,QL1:4606,DRAW:7381
DQN:13,QL1:5087,DRAW:7900
DQN:14,QL1:5536,DRAW:8450
DQN:14,QL1:6011,DRAW:8975
DQN:14,QL1:6496,DRAW:9490
DQN:14,QL1:7394,DRAW:9592
DQN:14,QL1:7925,DRAW:10061
DQN:16,QL1:8357,DRAW:10627
DQN:16,QL1:8777,DRAW:11207
Je me demande si elle est enfin devenue plus forte. .. .. C'est une force délicate. .. J'ai encore beaucoup de pertes dans ce journal, mais après 100 000 batailles, j'ai failli me contenter d'un match nul.
pDQ.e=0
p2=PlayerHuman(PLAYER_O)
game=TTT_GameOrganizer(pDQ,p2,2)
game.progress()
Turn is Human
Where would you like to place -1 (1-9)? 1
//anaconda/lib/python3.5/site-packages/ipykernel/__main__.py:69: VisibleDeprecationWarning: converting an array with ndim > 0 to an index will result in an error in the future
O | |
-----------
| |
-----------
| |
Turn is DQN
O | |
-----------
| X |
-----------
| |
Turn is Human
Where would you like to place -1 (1-9)? 2
O | O |
-----------
| X |
-----------
| |
Turn is DQN
O | O | X
-----------
| X |
-----------
| |
Turn is Human
Where would you like to place -1 (1-9)? 7
O | O | X
-----------
| X |
-----------
O | |
Turn is DQN
O | O | X
-----------
X | X |
-----------
O | |
Turn is Human
Where would you like to place -1 (1-9)? 6
O | O | X
-----------
X | X | O
-----------
O | |
Turn is DQN
O | O | X
-----------
X | X | O
-----------
O | | X
Turn is Human
Where would you like to place -1 (1-9)? 7
O | O | X
-----------
X | X | O
-----------
O | | X
I lost...
Invalid Move!
Turn is Human
Where would you like to place -1 (1-9)? 2
| O |
-----------
| |
-----------
| |
Turn is DQN
| O |
-----------
| X |
-----------
| |
Turn is Human
Where would you like to place -1 (1-9)? 1
O | O |
-----------
| X |
-----------
| |
Turn is DQN
O | O | X
-----------
| X |
-----------
| |
Turn is Human
Where would you like to place -1 (1-9)? 7
O | O | X
-----------
| X |
-----------
O | |
Turn is DQN
O | O | X
-----------
X | X |
-----------
O | |
Turn is Human
Where would you like to place -1 (1-9)? 6
O | O | X
-----------
X | X | O
-----------
O | |
Turn is DQN
O | O | X
-----------
X | X | O
-----------
O | | X
Turn is Human
Where would you like to place -1 (1-9)? 8
O | O | X
-----------
X | X | O
-----------
O | O | X
Draw Game
DQN:1,Human:0,DRAW:1
Eh bien, c'était un tel mouvement.
Q-Learning était assez facile à mettre en œuvre, mais avec Deep Q Network, il était très souvent indécis sans essais et erreurs. Même si je l'ai implémenté pour la première fois avec Relu, il ne s'est pas du tout renforcé, et il s'est amélioré avec Leaky Relu. Peut-être que je ne pourrais pas bien l'exprimer avec Relu parce que -1 est sur le tableau. De plus, pour une raison quelconque, Adam ne fonctionnait pas et SGD fonctionnait. C'est étrange. Je pensais qu'Adam était le plus fort. De plus, si vous ne jouez pas contre Alpha Random et que vous vous battez contre Q-Learning (type fort) depuis le début, vous perdrez rapidement la motivation et vous perdrez. Au début, il semble que vous deviez combattre les faibles pour les motiver.
De plus, la chose la plus difficile était
――Comment enseigner à DQN ce que vous ne devriez pas faire
C'est le but.
Cette fois, si je touchais un endroit où il y avait déjà un morceau, je donnais de force une récompense négative et j'apprenais 10 fois, ce qui fonctionnait bien. Dois-je entrer dans un endroit où je peux le frapper?
Si vous avez des questions ou souhaitez vous améliorer, n'hésitez pas à me le faire savoir. Conseils et suggestions, bienvenue de plus en plus.
Même ainsi, cela a pris plus de temps que prévu, même si je pensais que cela prendrait environ 2-3 heures pour la troisième ligne. Je suis parfaitement conscient qu'il y a un écart ridicule entre ce que je sais, ce que je peux implémenter (écrire du code) et ce que je peux faire (travailler correctement). Nous vous encourageons à le mettre en œuvre vous-même sans trop regarder cette source.
Eh bien, je me demande si je ferai une version d'Othello quand j'aurai le temps. .. .. Je suis inquiet pour le prochain défi, savoir s'il faut essayer correctement la configuration 3NN d'AlphaGo.
Recommended Posts