"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > بناء وكيل شطرنج باستخدام DQN

بناء وكيل شطرنج باستخدام DQN

نشر في 2025-03-24
تصفح:344

حاولت مؤخرًا تنفيذ وكيل الشطرنج القائم على DQN.

الآن ، سيخبرك أي شخص يعرف كيف يعمل DQNS و Chess هذه فكرة غبية.

و ... لقد كان ، لكن كمبتدئ استمتعت به مع ذلك. في هذه المقالة ، سأشارك الأفكار التي تعلمتها أثناء العمل على هذا.


فهم البيئة.

قبل أن أبدأ في تنفيذ الوكيل نفسه ، كان عليّ أن أتعرف على البيئة التي سأستخدمها وصنع غلاف مخصص فوقه حتى يتمكن من التفاعل مع الوكيل أثناء التدريب.

  • استخدمت بيئة الشطرنج من مكتبة Kaggle_environments.

     from kaggle_environments import make
     env = make("chess", debug=True)
    
  • استخدمت أيضًا Chessnut ، وهي مكتبة Python خفيفة الوزن تساعد على تحليل ألعاب الشطرنج والتحقق من صحة.

     from Chessnut import Game
     initial_fen = env.state[0]['observation']['board']
     game=Game(env.state[0]['observation']['board'])
    

في هذه البيئة ، يتم تخزين حالة المجلس بتنسيق FEN.

Building a Chess Agent using DQN

يوفر طريقة مدمجة لتمثيل جميع القطع على اللوحة واللاعب النشط حاليًا. ومع ذلك ، بما أنني خططت لتغذية المدخلات إلى شبكة عصبية ، اضطررت إلى تعديل تمثيل الحالة.


تحويل Fen إلى تنسيق المصفوفة

Building a Chess Agent using DQN

نظرًا لوجود 12 نوعًا مختلفًا من القطع على لوحة ، قمت بإنشاء 12 قناة من شبكات 8x8 لتمثيل حالة كل من هذه الأنواع على اللوحة.


إنشاء غلاف للبيئة

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

كانت الهدف من هذا الغلاف هو توفير سياسة مكافأة للوكيل ودالة الخطوة التي تستخدم للتفاعل مع البيئة أثناء التدريب.

كان الشطرنج مفيدًا في الحصول على معلومات مثل التحركات القانونية الممكنة في الوضع الحالي للمجلس وأيضًا للتعرف على زملائه أثناء اللعبة.

حاولت إنشاء سياسة مكافأة لإعطاء نقاط إيجابية لزملاء الفحص وإخراج قطع العدو أثناء نقاط سلبية لفقدان اللعبة.


إنشاء مخزن مؤقت لإعادة التشغيل

Building a Chess Agent using DQN

يتم استخدام المخزن المؤقت لإعادة التشغيل خلال فترة التدريب لحفظ (الحالة ، الإجراء ، المكافأة ، الحالة التالية) الإخراج بواسطة Q-network ويستخدم لاحقًا بشكل عشوائي للاشتراك في الشبكة المستهدفة


وظائف مساعدة

Building a Chess Agent using DQN

Building a Chess Agent using DQN

تُرجع chessnut الإجراء القانوني بتنسيق UCI الذي يشبه "A2A3" ، ولكن للتفاعل مع الشبكة العصبية التي قمت بتحويلها إلى فهرس متميز باستخدام نمط أساسي. يوجد إجمالي 64 مربعًا ، لذلك قررت أن يكون لدي 64*64 فهرسة فريدة لكل خطوة.
أعلم أنه ليس كل التحركات 64*64 ستكون قانونية ، لكن يمكنني التعامل مع الشرعية باستخدام الشطرنج وكان النمط بسيطًا بما يكفي.


بنية الشبكة العصبية

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

تستخدم هذه الشبكة العصبية الطبقات التلافيفية لتأخذها في إدخال القناة 12 وتستخدم أيضًا فهارس الإجراء الصالحة لتصفية التنبؤ بإخراج المكافآت.


تنفيذ الوكيل

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())



من الواضح أن هذا كان نموذجًا أساسيًا للغاية لم يكن لديه فرصة للأداء بشكل جيد بالفعل (ولم يكن كذلك) ، لكنه ساعدني في فهم كيفية عمل DQNs بشكل أفضل قليلاً.

Building a Chess Agent using DQN

بيان الافراج يتم استنساخ هذه المقالة على: https://dev.to/ankit_upadhyay_1c38ae52c0/building-a-chess-agent-using-dqn-40po؟1 إذا كان هناك أي انتهاك ، يرجى الاتصال بـ [email protected] لحذفه.
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3