在开始实现 Agent 本身之前,我必须熟悉将要使用的环境,并在其之上制作一个自定义包装器,以便它可以在训练期间与 Agent 交互。
我使用了 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
这个包装器的目的是为代理提供奖励策略以及用于在训练期间与环境交互的步骤函数。
Chessnut 有助于获取信息,例如当前棋盘状态下可能的合法走法,以及在游戏过程中识别将死者。
我尝试制定奖励政策,为将死并消灭敌方棋子给予正分,而为输掉比赛给予负分。
重播缓冲区在训练期间用于保存 Q 网络输出的(状态、动作、奖励、下一个状态),并在以后随机用于目标网络的反向传播
Chessnut 以 UCI 格式返回合法动作,看起来像“a2a3”,但是为了与神经网络交互,我使用基本模式将每个动作转换为不同的索引。总共有 64 个方块,所以我决定为每个动作设置 64*64 个唯一索引。
我知道并非所有 64*64 的棋步都是合法的,但我可以使用 Chessnut 来处理合法性,而且模式足够简单。
from kaggle_environments import make env = make("chess", debug=True)
该神经网络使用卷积层接收 12 个通道输入,并使用有效的动作索引来过滤奖励输出预测。
from Chessnut import Game initial_fen = env.state[0]['observation']['board'] game=Game(env.state[0]['observation']['board'])
这显然是一个非常基本的模型,实际上不可能表现良好(而且也没有),但它确实帮助我理解了 DQN 如何更好地工作。
以上是使用 DQN 构建国际象棋代理的详细内容。更多信息请关注PHP中文网其他相关文章!