欢迎访问集智主站:集智,通向智能时代的引擎git
教会机器经过深度学习和自我博弈学习玩《四子连珠》游戏(Connect4)。github
在本文,我(做者 David Foster——译者注)会主要讲到如下三件事:算法
AlphaGo → AlphaGo Zero → AlphaZero数据库
2016 年 3 月,在 2 百万人眼前,DeepMind 的 AlphaGo 以 4-1 击败了世界围棋冠军李世石。一台机器学到了人类顶尖的围棋策略,这在之前是不可思议的事情。后端
就其自身而言,这已是了不得的成就了,然而 2017 年 10 月,DeepMind 又往前迈了一大步。bash
在其发布的《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 诞生了——一种无需预先得到人类专业知识就能迅速掌握某些领域技能的通用算法。app
对于这项成就,有两个方面很奇妙:dom
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 游戏。
换言之,经过这种方式,咱们搭建的模型能够学习任何一种博弈游戏。