قبل أن أبدأ في تنفيذ الوكيل نفسه ، كان عليّ أن أتعرف على البيئة التي سأستخدمها وصنع غلاف مخصص فوقه حتى يتمكن من التفاعل مع الوكيل أثناء التدريب.
استخدمت بيئة الشطرنج من مكتبة 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'])
يوفر طريقة مدمجة لتمثيل جميع القطع على اللوحة واللاعب النشط حاليًا. ومع ذلك ، بما أنني خططت لتغذية المدخلات إلى شبكة عصبية ، اضطررت إلى تعديل تمثيل الحالة.
نظرًا لوجود 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
كانت الهدف من هذا الغلاف هو توفير سياسة مكافأة للوكيل ودالة الخطوة التي تستخدم للتفاعل مع البيئة أثناء التدريب.
كان الشطرنج مفيدًا في الحصول على معلومات مثل التحركات القانونية الممكنة في الوضع الحالي للمجلس وأيضًا للتعرف على زملائه أثناء اللعبة.
حاولت إنشاء سياسة مكافأة لإعطاء نقاط إيجابية لزملاء الفحص وإخراج قطع العدو أثناء نقاط سلبية لفقدان اللعبة.
يتم استخدام المخزن المؤقت لإعادة التشغيل خلال فترة التدريب لحفظ (الحالة ، الإجراء ، المكافأة ، الحالة التالية) الإخراج بواسطة Q-network ويستخدم لاحقًا بشكل عشوائي للاشتراك في الشبكة المستهدفة
تُرجع 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 بشكل أفضل قليلاً.
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3