"Si un ouvrier veut bien faire son travail, il doit d'abord affûter ses outils." - Confucius, "Les Entretiens de Confucius. Lu Linggong"
Page de garde > La programmation > Construire un agent d'échecs utilisant DQN

Construire un agent d'échecs utilisant DQN

Publié le 2025-03-24
Parcourir:514

J'ai récemment essayé d'implémenter un agent d'échecs basé sur DQN.

Maintenant, quiconque sait comment les travaux de DQN et d'échecs vous diraient que c'est une idée stupide.

Et ... c'était le cas, mais en tant que débutant, je l'ai quand même apprécié. Dans cet article, je partagerai les idées que j'ai apprises en travaillant à ce sujet.


Comprendre l'environnement.

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'])
    

Dans cet environnement, l'état du conseil d'administration est stocké au format FEN.

Building a Chess Agent using DQN

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.


Conversion FEN en format matriciel

Building a Chess Agent using DQN

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.


Création d'un wrapper pour l'environnement

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.


Création d'un tampon de relecture

Building a Chess Agent using DQN

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


Fonctions auxiliaires

Building a Chess Agent using DQN

Building a Chess Agent using DQN

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.


Structure du réseau neuronal

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.


Implémentation de l'agent

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.

Building a Chess Agent using DQN

Déclaration de sortie Cet article est reproduit à: https://dev.to/ankit_upadhyay_1c38ae52c0/building-a-chess-agent-using-dqn-40po?1 s'il y a une contrefaçon, veuillez contacter [email protected] pour le supprimer.
Dernier tutoriel Plus>

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