python构建决策引擎_用Python和Keras搭建你自己的AlphaZero

教会机器通过深度学习和自我博弈学习玩《四子连珠》游戏(Connect4)。

在本文,我(作者 David Foster——译者注)会主要讲到以下三件事:

AlphaZero 迈入人工智能一大步的两个原因。

你怎样可以搭建一个 AlphaZero 一样的AI玩《四子连珠》游戏。

你怎样可以将代码适用到其它游戏中。

AlphaGo → AlphaGo Zero → AlphaZero

2016 年 3 月,在 2 百万人眼前,DeepMind 的 AlphaGo 以 4-1 击败了世界围棋冠军李世石。一台机器学到了人类顶尖的围棋策略,这在以前是难以想象的事情。

就其自身而言,这已经是了不起的成就了,然而 2017 年 10 月,DeepMind 又往前迈了一大步。

在其发布的《Mastering the Game of Go without Human Knowledge》(无需人类知识掌握围棋)中,DeepMind 展示了一种新算法 AlphaGo Zero,它以 100-0 的战绩击败的自己的旧版本 AlphaGo。令人难以置信的是,AlphaGo Zero 完全是通过自我博弈学习,从“白板”开始,逐渐找到了能打败 AlphaGo 的策略。创建一个这样的超级人工智能已经完全不需要任何人类专业知识构成的数据库进行训练。

仅仅 48 天后的 2017 年 12 月 5 日,DeepMind 又发表了另一篇论文《Mastering Chess and Shogi by Self-Play with a General Reinforcement Learning Algorithm》(用通用强化学习算法自我对弈,掌握国际象棋和将棋),显示 AlphaGo Zero 也能打败国际象棋世界冠军 StockFish 和日本将棋冠军 Elmo。而整个学习过程,从展示给 AlphaGo Zero 这些棋类开始到它成为这两种棋的世界顶尖高手,只用了不到 24 小时。

在这种情况下,AlphaZero 诞生了——一种无需预先获得人类专业知识就能迅速掌握某些领域技能的通用算法。

对于这项成就,有两个方面很奇妙:

1.AlphaZero 无需任何人类专业知识作为输入

这一点的重要性,再强调也不为过。这意味着如果有完善的信息(如果自始至终双方都完全知道下棋状态),AlphaGo Zero 的根本方法可以用到任何棋类游戏中,因为除了该种棋类的规则之外,AI 无需预先学习任何专业知识。

这就是为何 DeepMind 在发布初篇 AlphaGo Zero 论文后不到 48 天就能发布打败国际象棋和将棋人类冠军的论文。简单说,所需的改变就只有描述棋类机制的输入文件,以及调整与神经网络和蒙特卡洛树搜索相关的高参数。

算法非常优雅

即便 AlphaZero 使用了超级复杂的算法,当今世界只有一小部分人能理解,那么它依然算的上是了不起的成就。然而,它的非凡之处就在于论文中的很多理念实际上远比之前的版本简单。其核心思想,就是遵循这些简单的学习口诀一样的东西:

从内心先将所有可能会出现的场景过一遍,优先选择有希望的路径,同时也思考对手对你的行动最可能做出怎样的反应,并继续探索未知情境。

抵达不熟悉的状态后,评估一下你认为当前情形对自己是否有利,关联一下前几步的得分,分析走到当前这一步的心理路径。

在考虑完将来所有的可能性后,采取探索最多的行动。

在比赛结束时,回溯并评估当时对未来场景出现了哪些误判,相应地优化对这些场景的理解。

这和你学习下棋的过程是不是很像?当你下了一步坏棋,要么是因为你误判了走这步棋的未来情况,要么你误判了对手可能会怎么下,因此没有考虑到这中可能性。而正是从这两个方面训练 AlphaZero 学习下棋。

怎样搭建你自己的 AlphaZero

本文主要是讲解如何搭建AlphaZero,因此假定你已经对AlphaZero的原理有了大致了解。如果不太熟悉的,可预先查阅一下相关资料,可以参考我制作的这篇速查表或这篇文章。

代码

将 Github 上的代码库复制下来

https://github.com/AppliedDataSciencePartners/DeepReinforcementLearning

我后面会引用这里面的代码。

要开始学习过程,首先在 run.ipynb Jupyter notebook 中运行前两个面板。一旦它创建了足够的博弈情景,神经网络就开始训练了。

再通过自我博弈和训练,它会越来越擅长在任何位置预测博弈值和下一步棋的动作,从而做出更好的决策,越来越聪明。

现在我们更详细地看看代码,并展示一些结果,证明 AI 随着时间推移越来越强。

注意:这是我自己根据 DeepMind 所发论文对 AlphaZero 的理解,如有不当之处,敬请指正。

《四子连珠》

我们的算法要学习玩的游戏是《四子连珠》(Connect4)。虽然它不像围棋那么复杂,但是仍然总共有 4,531,985,219,092 个游戏位置。

游戏的规则很直接:玩家轮流在任何一栏的顶部放置自己的颜色的棋子。谁最先在垂直、水平或对角线上都放置了同一种颜色,则获胜。如果全部网格都被填满,仍然没有出现同一颜色的棋子出现在同一条线上,则平局。

以下是组成代码库的关键文件的总结:

game.py

该文件包含《四子连珠》的游戏规则。

每个方格分配一个从0到41的数字,如图:

此文件给出了根据给定动作,从一种游戏状态转移至另一种的逻辑。例如,给定空棋盘和 38 号动作,takeAction 方法返回到一个新的游戏状态,起始玩家的位置则位于中间列的底部。

你可以用任何符合相同 API 的游戏文件替换 game.py 文件,原则上算法将根据你给它的规则通过自我博弈学习游戏策略。

run.ipynb

它包含了开始学习过程的代码。它会加载游戏规则,然后迭代算法的主循环,其中包含三个阶段:

自我博弈

再训练神经网络

评估神经网络

在这一循环中有两个 agent:best_player 和 current_player。

其中 best_player 包含了性能最好的神经网络,用于生成自我博弈记忆。Current_player 然后会根据这些记忆再训练其神经网络,接着与 best_player 进行对弈。如果它赢了, best_player 中的神经网络就会换成 current_player 中的神经网络,循环再次开始。

agent.py

它包含 Agent类(游戏中的一个玩家)。每个玩家都用自己的神经网络和蒙特卡罗搜索树进行初始化。

Simulate 方法运行蒙特卡罗树搜索过程。具体说来,agent 移动至树的一个叶节点,用其神经网络评估该节点,然后通过树回填(backfill)该节点的值。

Act 方法多次重复 simulate 方法,以理解从当前位置移动至哪个位置是最有利的。然后它将选定的动作返回给游戏,以执行该游戏。

replay 方法使用之前的游戏记忆再训练神经网络。

Model.py

该文件包含了 Residual_CNN 类,它定义如何构建神经网络的实例。

其采用 AlphaGo Zero 论文中的神经网络架构的压缩版本——即一个卷积层,接着是一些残留层,然后分解成值端(value head)和策略端(policy head)。

卷积过滤器的深度和数量可以在 config 文件中设置。

Keras 程序库用于搭建神经网络,使用 TensorFlow 后端。

要在神经网络中查看单个卷积过滤和密集连接的层,可在 run.ipynb notebook 中运行以下代码:

current_player.model.viewLayers()

复制代码

MCTS.py

它包含节点、边缘和 MCTS 类,它们构成了一个蒙特卡洛搜索树。

MCTS 类包含前面提到的 moveToLeaf 和 backFill 方法,并且边缘类的实例存储每个可能的移动的统计数据。

config.py

这是你设置影响算法的关键参数的地方。

调整这些变量将影响算法的运行时间、神经网络的准确性和算法的整体成功。上面的参数产生了一个高质量的《四子连珠》玩家,但是要花很长时间才能完成。为了加快算法的速度,请尝试以下参数。

funcs.py

它包含了将两个 agent 进行匹配的 playMatches 和 playMatchesBetweenVersions 函数。

如果要和你创建的玩家对战,请运行以下代码(它也在 run.ipynb notebook 中):

from game import Game

from funcs import playMatchesBetweenVersions

import loggers as lg

env = Game()

playMatchesBetweenVersions(

env

, 1 # the run version number where the computer player is located

, -1 # the version number of the first player (-1 for human)

, 12 # the version number of the second player (-1 for human)

, 10 # how many games to play

, lg.logger_tourney # where to log the game to

, 0 # which player to go first - 0 for random

)

复制代码

initialise.py

当你运行该算法时,所有的模型和内存文件都保存在 run 文件夹中,在根目录中。

稍后要从这个检查点重新启动算法,将 run 文件夹转移到 run_archive 文件夹中,将一个运行编号(run number)附加到文件夹名字上。然后,将运行编号、模型版本号和 memory 版本号输入到 initialise.py 文件中,run_archive 文件夹中相关文件的位置对应。然后从这个检查点开始,像往常一样运行该算法。

memory.py

这是 Memory class 的一个实例,用以存储之前游戏的记忆,该算法会用它们重新训练 current_player 的神经网络。

loss.py

此文件包含一个自定义损失函数,用以在传递到交叉熵损失函数之前对非法移动的预测进行掩码处理。

settings.py

run和run_archive 文件夹的位置。

logger.py

这个文件包含一个自定义的损失函数,它在传递到交叉熵损失函数之前,掩盖了非法移动的预测。

settings.py

run 和 run_archive 文件夹的位置。

loggers.py

日志文件被保存到 run 文件夹中的 log 文件夹。要打开日志记录,可将该文件中 logger_disabled 变量的值设置为“False”。查看日志文件将帮助你了解算法的工作原理,并了解它的“思想”。例如,下面是 logger.mcts 文件中的一个样例:

同样来自 logger.tourney 文件的一个样例,你可以在评估阶段看到每个与移动相关的概率:

结果

经过几天的训练,小批量迭代次数后得出以下损失图表:

最上面的线是策略端的误差(MCTS的交叉熵移动概率与神经网络的输出相对应)。下面的线是值端的误差(实际博弈值与神经网络值之间的均方差)。中间的线是两者的平均值。

很明显,神经网络在预测每个博弈状态的价值和可能的下一步动作方面做得越来越好。为了展示这一结果如何变得更加强大,我在17个玩家之间进行了一场联赛,从首次迭代的神经网络到第 49 次迭代,每对搭档都对战了两次,两名玩家都有机会先玩。

以下是最终排名:

显然,后期版本的神经网络优于早期版本,赢得了它们之间的大部分比赛。另外,学习似乎并没有达到饱和,因为随着训练时间增加,玩家变得越来越强大,并且学习的策略越来越复杂。

例如,随着时间的推移,神经网络所偏爱的一个明确策略就是尽早枪战中心栏。观察算法的第 1 个版本和第 30 个版本之间的差别:

神经网络的第一个版本

神经网络的第三十个版本

这是一个很好的策略,因为很多下棋的线路都需要中间栏——要求尽量不要让对手利用这一点。而神经网络在没有任何人类知识输入的情况下,已经学会了这一点。

学习一种不同的博弈游戏

在 games 文件夹里有个 game.py 文件,用于一个叫做 Metasquares 的游戏。这个游戏是在网格中放置 X 和 O 标记,以尝试形成不同大小的方块。方块越大,玩家分数越高。当网格被填满时,得分最多的玩家获胜。

如果你将《四子连珠》的 game.py 文件替换为 Metasquare 的 game.py 文件,那么我们上面使用的算法就会学习玩 Metasquares 游戏。

换言之,通过这种方式,我们搭建的模型可以学习任何一种博弈游戏。

推荐阅读

你可能感兴趣的:(python构建决策引擎)