AlphaZero巧妙了使用MCTS搜索树和神经网络一起,通过MCTS搜索树优化神经网络参数,反过来又通过优化的神经网络指导MCTS搜索。两者一主一辅,非常优雅的解决了这类状态完全可见,信息充分的棋类问题。前面结合一个五子棋AI的案例代码实现了蒙特卡洛树搜索,还使用Tensorflow2实现神经网络的部分。现在还差训练模型部分和人机对战的界面,我们先来实现人机交互。
AI人工智能(调包侠)速成之路十(AlphaZero代码实战2:蒙特卡洛树搜索)
AI人工智能(调包侠)速成之路十一(AlphaZero代码实战3:神经网络实现)
先写出能交互的游戏界面,这里使用import tkinter as tk。Tkinter 是 Python 的标准 GUI 库。Python 使用 Tkinter 可以快速的创建 GUI 应用程序。由于 Tkinter 是内置到 python 的安装包中、只要安装好 Python 之后就能 import Tkinter 库、如果需要专业的游戏界面也可以使用游戏开发引擎例如:Unity是全球应用非常广泛的实时内容开发平台,为游戏、汽车、建筑工程、影视动画等广泛领域的开发者提供强大且易于上手的工具来创作、运营和变现3D、2D、VR和AR可视化...。
游戏界面的设计和实现不是我们的重点,这里主要介绍人机对弈时AI面对局面变化所做的计算和应对方法。
#后端
board = GobangBoard(width=15, n_in_row=5)
game = GobangGame(board)
policy_value_net = GobangPolicyValueNet2(board_width=15, model_file="model")
try:
Human_player = Human()
mcts_player = MCTSPlayer(policy_value_net.policy_value_fn, n_playout=300) #搜索次数
game.start_play(Human_player, mcts_player, start_player=0)
except KeyboardInterrupt:
print('\n\rquit')
#后端
5个类对象配合实现游戏主体。
1 棋盘对象board 负责棋盘状态的维护,局面信息从这个对象获取。
2 神经网络对象policy_value_net 负责根据输入的局面信息前向传播给出输入局面估值和应对局面多个行动的概率。
3 人类玩家对象Human_player 负责把鼠标键盘的输入转换为对棋盘对象的状态改变。
4 AI玩家对象mcts_player 负责根据输入局面信息配合神经网络对象给出的估值结合蒙特卡洛树搜索给出应对方法。
5 游戏对象game 负责游戏的开始,结束等流程控制。
"""窗口循环"""
root.mainloop()
#事件监听处理
def coorBack(event): #return coordinates of cursor 返回光标坐标
global click_x, click_y,last_action,aido
click_x = event.x
click_y = event.y
if(last_action<0 and aido > 0):
coorJudge()
if(person_flag<0):
aido = 0
aido = AI_do()
def AI_do():
#time.sleep(10)
global click_x, click_y,last_action,action_list,person_flag #
mcts_player.last_action=mcts_player.get_action(game.board)
last_action = mcts_player.last_action
game.board.do_move(mcts_player.last_action)
action_list.append(last_action)
人机交互界面初始化后进入窗口循环,绑定鼠标输入响应。人类玩家通过观察游戏界面点击鼠标改变棋盘状态, 窗口捕获到鼠标信息后调用coorJudge()函数改变窗口状态,然后再调用AI_do()函数调用AI玩家对象mcts_player的get_action(game.board)方法,该方法根据输入局面信息配合神经网络对象给出的估值结合蒙特卡洛树搜索给出应对方法。接着棋盘状态被改变,继续循环等待人类玩家操作。
def get_action(self, board, temp=1e-3, return_prob=False):
move_probs = np.zeros(board.get_action_count()) # alphaGo Zero论文里面由MCTS返回的的pi数组
if len(board.get_available_moves()) > 0:
acts, probs = self.mcts.get_move_probs(board, temp)
move_probs[list(acts)] = probs
if self._is_selfplay:
move = np.random.choice(acts, p=0.75*probs + 0.25*np.random.dirichlet(0.3*np.ones(len(probs)))) # 增加一个Dirichlet Noise来探索
self.mcts.update_with_move(move)
else:
move = np.random.choice(acts, p=probs) # 如果用默认值temp=1e-3,就相当于选择P值最高的动作
self.mcts.update_with_move(-1)
if return_prob:
return move, move_probs
else:
return move
else:
print("WARNING: the board is full")
mcts_player的get_action(game.board)方法,传入的参数是棋盘对象board 负责棋盘状态的维护,局面信息从这个对象获取。
acts, probs = self.mcts.get_move_probs(board, temp)执行蒙特卡洛搜索n_playout次,得到每个动作相应的概率pi值。temp是控制探索水平的温度参数(训练的时候用1,增加尝试不同行为;人机对弈的时候一般用0.01,让输出的行为稳定在高访问次数的节点上)。
def get_move_probs(self, state, temp=1e-3):
"""
执行蒙特卡洛搜索n_playout次,得到每个动作相应的概率pi值。
:param state: 一个Board类的对象,描述了当前棋局
:param temp: 在范围(0, 1]的温度值
:return: 所有动作值和所有动作相应的所有概率pi值
"""
for n in range(self._n_playout):
state_copy = copy.deepcopy(state)
self._playout(state_copy)
# 计算每个动作的概率pi值
act_visits = [(act, node._n_visits) for act, node in self._root._children.items()]
acts, visits = zip(*act_visits)
act_probs = softmax(1.0/temp * np.log(np.array(visits) + 1e-10))
return acts, act_probs
人机对战的部分全部完成。没有训练之前AI只相当于明白了游戏规则的“幼儿”,所以训练神经网络成了目前核心难点,也是资源消耗最多的地方。把上面代码中人类玩家的部分去掉,甚至不需要窗口的输入界面,直接上AI玩家循环起来就可以实现自对弈(左右互搏)。AI玩家对象mcts_player负责根据输入局面信息配合神经网络对象给出的估值结合蒙特卡洛树搜索给出应对方法。AI可以不断重复的自己跟自己对弈,然后从对弈结果中总结出局面估值(代替传统的行业专家或者是复杂的估值函数),并积累应对局面的经验值。
我们在下一篇实现AI人工智能体的自对弈,然后用自对弈数据训练神经网络。训练好了就是人工智能,训练不好就变成人工智障了......。
AlphaZero代码实战系列 源代码打包
下载地址:https://download.csdn.net/download/askmeaskyou/12931806