Avant de commencer à implémenter l'agent lui-même, j'ai dû me familiariser avec l'environnement que j'utiliserai et que je vais faire un wrapper personnalisé par-dessus afin qu'il puisse interagir avec l'agent pendant la formation.
J'ai utilisé l'environnement d'échecs de la bibliothèque Kaggle_environments.
from kaggle_environments import make env = make("chess", debug=True)
J'ai également utilisé ChessNut, qui est une bibliothèque Python légère qui aide à analyser et à valider les jeux d'échecs.
from Chessnut import Game initial_fen = env.state[0]['observation']['board'] game=Game(env.state[0]['observation']['board'])
Il fournit une manière compacte de représenter toutes les pièces du tableau et du lecteur actuellement actif. Cependant, comme j'avais l'intention d'alimenter l'entrée dans un réseau neuronal, j'ai dû modifier la représentation de l'état.
Puisqu'il existe 12 types différents de pièces sur une planche, j'ai créé 12 canaux de grilles 8x8 pour représenter l'état de chacun de ces types sur la carte.
class EnvCust: def __init__(self): self.env = make("chess", debug=True) self.game=Game(env.state[0]['observation']['board']) print(self.env.state[0]['observation']['board']) self.action_space=game.get_moves(); self.obs_space=(self.env.state[0]['observation']['board']) def get_action(self): return Game(self.env.state[0]['observation']['board']).get_moves(); def get_obs_space(self): return fen_to_board(self.env.state[0]['observation']['board']) def step(self,action): reward=0 g=Game(self.env.state[0]['observation']['board']); if(g.board.get_piece(Game.xy2i(action[2:4]))=='q'): reward=7 elif g.board.get_piece(Game.xy2i(action[2:4]))=='n' or g.board.get_piece(Game.xy2i(action[2:4]))=='b' or g.board.get_piece(Game.xy2i(action[2:4]))=='r': reward=4 elif g.board.get_piece(Game.xy2i(action[2:4]))=='P': reward=2 g=Game(self.env.state[0]['observation']['board']); g.apply_move(action) done=False if(g.status==2): done=True reward=10 elif g.status == 1: done = True reward = -5 self.env.step([action,'None']) self.action_space=list(self.get_action()) if(self.action_space==[]): done=True else: self.env.step(['None',random.choice(self.action_space)]) g=Game(self.env.state[0]['observation']['board']); if g.status==2: reward=-10 done=True self.action_space=list(self.get_action()) return self.env.state[0]['observation']['board'],reward,done
Le point de ce wrapper était de fournir une politique de récompense pour l'agent et une fonction de pas qui est utilisée pour interagir avec l'environnement pendant la formation.
ChessNut a été utile pour obtenir des informations comme les mouvements juridiques possibles à l'état actuel du conseil d'administration et également pour reconnaître les cochets pendant le jeu.
J'ai essayé de créer une stratégie de récompense pour donner des points positifs pour les camarades de contrôle et éliminer les pièces ennemies tandis que des points négatifs pour perdre le jeu.
Le tampon de relecture est utilisé pendant la période de formation pour enregistrer la sortie (État, action, récompense, état suivant) par le Network Q et ultérieurement utilisé au hasard pour la rétro-propagation du réseau cible
ChessNut renvoie une action en justice au format UCI qui ressemble à «A2A3», cependant, pour interagir avec le réseau neuronal, j'ai converti chaque action en un indice distinct en utilisant un modèle de base. Il y a un total de 64 carrés, j'ai donc décidé d'avoir 64 * 64 index uniques pour chaque mouvement.
Je sais que tous les 64 * 64 mouvements ne seraient pas légaux, mais je pouvais gérer la légalité en utilisant l'échelle et le modèle était assez simple.
import torch import torch.nn as nn import torch.optim as optim class DQN(nn.Module): def __init__(self): super(DQN, self).__init__() self.conv_layers = nn.Sequential( nn.Conv2d(12, 32, kernel_size=3, stride=1, padding= nn.ReLU(), nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1), nn.ReLU() ) self.fc_layers = nn.Sequential( nn.Flatten(), nn.Linear(64 * 8 * 8, 256), nn.ReLU(), nn.Linear(256, 128), nn.ReLU(), nn.Linear(128, 4096) ) def forward(self, x): x = x.unsqueeze(0) x = self.conv_layers(x) x = self.fc_layers(x) return x def predict(self, state, valid_action_indices): with torch.no_grad(): q_values = self.forward(state) q_values = q_values.squeeze(0) valid_q_values = q_values[valid_action_indices] best_action_relative_index = valid_q_values.argmax().item() max_q_value=valid_q_values.argmax() best_action_index = valid_action_indices[best_action_relative_index] return max_q_value, best_action_index
Ce réseau neuronal utilise les couches convolutionnelles pour absorber l'entrée de 12 canaux et utilise également les index d'action valides pour filtrer la prédiction de sortie de récompense.
model = DQN().to(device) # The current Q-network target_network = DQN().to(device) # The target Q-network optimizer = torch.optim.Adam(model.parameters(), lr=1e-4) replay_buffer = ReplayBuffer(buffer_size=10000) epsilon = 0.5 gamma = 0.99 batch_size=15 def train(episodes): for ep in range(1,episodes 1): print('Episode Number:',ep) myenv=EnvCust() done=False state=myenv.obs_space i=0 while not done and i batch_size: mini_batch = replay_buffer.sample(batch_size) for e in mini_batch: state, action, reward, next_state, done = e g=Game(next_state) act=g.get_moves(); ind_a=action_index(act) input_state=torch.tensor(fen_to_board(next_state), dtype=torch.float32, requires_grad=True).to(device) tpred,_=target_network.predict(input_state,ind_a) target = reward gamma * tpred * (1 - done) act_ind=uci_to_action_index(action) input_state2=torch.tensor(fen_to_board(state), dtype=torch.float32, requires_grad=True).to(device) current_q_value =model(input_state2)[0,act_ind] loss = (current_q_value - target) ** 2 optimizer.zero_grad() loss.backward() optimizer.step() if ep % 5 == 0: target_network.load_state_dict(model.state_dict())
C'était évidemment un modèle très basique qui n'avait aucune chance de bien performer (et ce n'est pas le cas), mais cela m'a aidé à comprendre comment les DQN fonctionnent un peu mieux.
Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.
Copyright© 2022 湘ICP备2022001581号-3