Antes de começar a implementar o próprio agente, tive que me familiarizar com o ambiente que vou usar e fazer um invólucro personalizado em cima dele para que ele possa interagir com o agente durante o treinamento.
usei o ambiente de xadrez da biblioteca Kaggle_environments.
from kaggle_environments import make env = make("chess", debug=True)
Eu também usei o Chessnut, que é uma biblioteca Python leve que ajuda a analisar e validar jogos de xadrez.
from Chessnut import Game initial_fen = env.state[0]['observation']['board'] game=Game(env.state[0]['observation']['board'])
fornece uma maneira compacta de representar todas as peças da placa e o jogador atualmente ativo. No entanto, como planejei alimentar a entrada de uma rede neural, tive que modificar a representação do estado.
Como existem 12 tipos diferentes de peças em uma placa, criei 12 canais de grades 8x8 para representar o estado de cada um desses tipos na placa.
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
O ponto deste invólucro era fornecer uma política de recompensa para o agente e uma função de etapa que é usada para interagir com o ambiente durante o treinamento.
chessnut foi útil para obter informações como os movimentos legais possíveis no estado atual do conselho e também para reconhecer colegas de seleção durante o jogo.
Tentei criar uma política de recompensa para dar pontos positivos para os colegas e tirar peças inimigas, enquanto pontos negativos para perder o jogo.
O buffer de replay é usado durante o período de treinamento para salvar a saída (estado, ação, recompensa, próximo estado) pela rede Q e posteriormente usada aleatoriamente para retropagem da rede de destino
chessnut retorna ação legal no formato UCI, que se parece com 'A2A3', no entanto, para interagir com a rede neural, converti cada ação em um índice distinto usando um padrão básico. Existem 64 quadrados totais, então decidi ter 64*64 índices exclusivos para cada movimento.
eu sei que nem todos os 64*64 movimentos seriam legais, mas eu poderia lidar com a legalidade usando o chessnut e o padrão era simples o suficiente.
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
Esta rede neural usa as camadas convolucionais para obter a entrada de 12 canais e também usa os índices de ação válidos para filtrar a previsão da saída de recompensa.
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())
esse era obviamente um modelo muito básico que não teve chance de realmente ter um bom desempenho (e não foi), mas me ajudou a entender como os DQNs funcionam um pouco melhor.
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3