在2016年3月,Deepmind研发的AlphaGo以4:1的成绩,击败了曾荣获18次世界冠军的围棋选手,李世石(Lee Sedol)。超过2亿观众见证了这一历史时刻。一台机器已经学会了一种超越人类的围棋策略。这在以前被认为是一项不可能完成的任务,或者至少需要十年之功。
AlphaGo与李世石的第3场比赛
这已是一项了不起的成就。然而,在2017年10月18日,DeepMind又再次取得了突破。
论文《无需人类知识就能称霸围棋》(Mastering the Game of Go without Human Knowledge),揭示了一种新的算法——AlphaGo Zero,它以100:0的惊人成绩打败了AlphaGo。更令人难以置信的是,它从零开始,通过自我博弈,逐渐学会了能打败自己之前的策略。至此,开发一个超级AI不再需要依赖人类专家的游戏数据库了。
仅48天后的2017年12月5日,DeepMind又发布了另一篇论文《通过一种通用的强化学习算法称霸国际象棋和日本象棋》(Mastering Chess and Shogi by Self-Play with a General Reinforcement Learning Algorithm),它展示了AlphaGo Zero如何能够学会国际象棋(StockFish和Elmo)和象棋。整个学习过程,从第一次参与游戏到成为世界上最厉害的计算机程序,只用了24小时。
就这样,AlphaZero华丽丽地诞生了——它无需储备任何人类棋谱,就可以以通用算法完成快速自我升级。
关于这个成就,有两点最让人称奇:
AlphaZero对人类游戏经验根本就不需要
这点的重要性怎么说都不过分。也就是说,对于任何有充分信息的游戏(对阵双方对游戏状态都全程掌握),AlphaGo Zero的方法论都可以得到完美应用!因为除了游戏规则之外,人类任何游戏经验值都是不需要的。
AlphaGo Zero的基础方法可以应用于任何具有完美信息的游戏(游戏状态在任何时候,双方玩家都完全知道的),因为在游戏规则之外,不需要事先的专家知识。
这就是DeepMind能在发表AlphaGo Zero论文48天后,马上就能发表第二篇论文。毫不夸张地说,所需要改变的仅仅是新游戏规则,及与神经网络和蒙特卡罗树搜索相关的超参数。
这个算法的优雅程度秒杀众生
即便AlphaZero使用的是世界上只有极少数人能够看懂的超复杂算法,它仍然是项了不起的成就。同它相比,之前的算法可谓不复杂不成活,这才是它真正的魅力。究其核心,无非是以下极简而美的学习逻辑:
脑补各种场景,挑能赢的路走,想想别人会怎么应对,并不断探索未知。
在思考未来可能的情景时,优先考虑有前途的路径,同时考虑其他人最有可能如何对你的行动作出反应,并继续探索未知。
遇到不熟悉的状况,评估它的利害程度,把它同之前的各种让你走到今天这一步的场景作比较。
穷尽你对未来的想象,用你试过最多的招数来应对。
在你考虑了未来的可能性之后,采取你已经探索过的行动。
游戏结束时,回头看看在哪里犯过错,然后洗心革面、更新认知。
在游戏结束时,回过头来评估你在哪里错误地判断了未来的位置,并相应地更新你的理解。
这听起来是不是很像你学玩游戏的方式? 当做错一个动作时,要么是因为你误判了这个动作会带来的结果,要么是你误判了对手可能会采取的行动。这两点正是AlphaZero学会如何玩游戏的法门。
如何构建自己的AlphaZero
首先,我们需要学习和理解AlphaGo Zero的原理。我之前写过一篇AlphaGo Zero的知识点速查手册可供参考:
https://medium.com/applied-data-science/alphago-zero-explained-in-one-diagram-365f5abf67e0
Tim Wheeler的博客中一篇文章也讲的很详细:
http://tim.hibal.org/blog/alpha-zero-how-and-why-it-works/
代码
基于下面这个代码库进行讲解:
https://github.com/AppliedDataSciencePartners/DeepReinforcementLearning
从运行Jupyter notebook中run.ipynb的前两个panel开始。一旦它完成了游戏的足够回合,那么神经网络将开始训练。通过随后的自我对弈和训练,它将逐渐在预测胜率和下一步行动上做得越来越好,从而做出更好的决策。
现在,我们需要更详细地看看面前的代码,并且展示下AI是怎样随着时间的增加变得越来越厉害的。
四子连珠(Connect4)
我们的算法将要学习如何玩这个游戏。虽然不如围棋那样复杂,但也有4531985219092种游戏走位。
四子连珠
游戏规则很简单。玩家轮流在任何一栏的顶部布置自己的颜色。最先在垂直、水平或对角线上放置一排同一种颜色棋子的玩家获胜,如果这种情况没有出现,那游戏就是平局。
下面是组成代码库的关键文件:
game.py——这个文件包含四子连珠的游戏规则
每个正方形都被分配了一个从0到41的数字,如下图所示:
game.py文件给出了从一种游戏状态到另一种状态的逻辑,并且给出了一个选择的动作。比如,考虑到empty board和38号动作,takeAction方法返回到一个新的游戏状态,也就是底部一行的中心位置。
你可以将game.py文件用任何符合相同API和算法的游戏文件替换掉,根据你给它的规则,通过自我对弈的方法学习。
run.ipynb——这个文件包含开启学习过程的代码
它通过算法中的主要环节加载游戏规则,并且由三个阶段组成:
1、自我对弈
2、重新训练神经网络
3、评估神经网络
有两个智能体也参与到这个环节中,他们分别为best_player和current_player。
best_player包含执行最佳的神经网络,并且可以用于生成自我对弈的记忆。然后,current_player在这些记忆上重新训练它的神经网络,然后再与best_player对弈。如果它赢了,best_player内部的神经网络被转换为current_player内部的神经网络,然后循环再次启动。
agent.Py——这个文件包含游戏中的一个玩家Agent class
在游戏中,每个玩家都是用自己的神经网络和蒙特卡罗搜索树进行初始化的。
我们需要用模拟的办法运行蒙特卡罗树搜索过程。具体地说,智能体移动到树的叶节点,用它的神经网络对节点进行评估,然后通过树将节点的值返回。
之后,我们还需要用act method多次重复模拟,让智能体理解从当前位置出发的最有利的移动。然后它将最终选择的动作返回到游戏中,以执行动作。
最后,replay method利用以前游戏的记忆,重新训练神经网络。
model.py——这个文件包括residual_cnn类,它定义了如何建立神经网络的实例
用Keras搭建残差卷积网络示例
它采用的是AlphaGoZero论文中浓缩版的神经网络结构——即一个卷积层,接着是许多剩余层,然后分成一个数值和指挥中枢。
可以在config文件中指定卷积筛选器的深度和数量。
Keras库是用来与后台的tensorflow建立网络。
查看个人的卷积滤波器和浓密连接层的神经网络,在run.ipynb笔记本运行以下代码:
current_player.model.viewLayers()
神经网络中的卷积核
MCTS.py——这个文件包含节点(Node),边(Edge)和MCTS类,构成了蒙特卡洛树搜索
MCTS类包含了前文提到的 moveToLeaf 和backFill 方法,以及Edge类的实例存储有关每个潜在移动的统计信息。
config.py——这是你设置影响算法的关键参数的地方
调整这些变量会影响运行时间,神经网络的准确性和整体算法的成功。以上参数产生一个高品质的四子连珠选手,但要花很长时间才能做到。为了加快算法的速度,请尝试以下参数。
funcs.py——包含可以在两个智能体之间进行比赛的playMatches和playMatchesBetweenVersions函数
如果你想挑战之前创建的智能算法,可以运行下面的代码(在run.ipynb笔记本)
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——当你运行该算法,所有的模型和存储文件保存在 runfolder的根目录下
稍后要从此检查点重新运行算法,请将运行文件夹传输到run_archive文件夹,并将运行编号附加到文件夹名称。然后,将运行编号,型号版本号和内存版本号输入到initialise.py文件中,对应于run_archive文件夹中相关文件的位置。像往常一样运行算法,然后从这个检查点开始。
memory.py
Memory类的一个实例存储以前游戏的记忆,该算法用于重新训练current_player的神经网络。
loss.py
该文件包含一个自定义损失函数,在传递到交叉熵损失函数之前,屏蔽了来自非法移动的预测。
settings.py
run和run_archive文件夹的位置。
loggers.py
日志文件保存到运行文件夹内的日志文件夹中。
要打开日志记录,请在此文件中将logger_disabled变量的值设置为False。
查看日志文件将帮助你了解该算法的工作原理,并在其“头脑”中查看。 例如,下面是logger.mcts文件中的示例。
logger.mcts文件的输出
同样从logger.tourney文件,你可以在评估阶段看到每个移动的概率:
logger.tourney文件的输出
训练出的结果让人惊喜
通过几天的训练,得到以下小批量迭代次数与损失的关系图:
小批量迭代次数与损失的关系图
最上面的线是策略头中的误差(MCTS移动概率的交叉熵,相对于神经网络的输出)。底部的线是价值头(实际游戏数值和神经网络预测值之间的均方误差)。中间的线是两者的平均值。
显然,神经网络在预测每个游戏状态的值以及可能的下一步移动方面正在变得更好。为了说明这个结果如何变得越来越强大,我让17个参与者组成联赛,从神经网络的第1次迭代到第49次。每一组比赛两次,两个玩家都有机会先玩。
这是最后的排名:
显然,神经网络的最新版本比早期版本更胜一筹,赢得了大部分的游戏。 这也似乎表明学习过程没有达到极限 - 随着训练时间的进一步延长,玩家将会继续变得更强大,学习越来越复杂的策略。
作为一个例子,随着时间的推移,一个神经网络挑选的策略较早的占据了中间列。观察算法的第一个版本与第三十个版本之间的区别:
第一个神经网络版本
第三十个神经网络样本
这是一个很好的策略,因为很多线路都需要中间列 – 尽早占领这一列可以确保你的对手无法利用这一优势。 神经网络已经在没有人类指导下,学到了这一点。
学习其他游戏
在游戏文件中有一个称为“Metasquares” 的game.py文件。其中的X和O用于形成不同大小的正方形。较大的方格意味着要落更多的棋子,当棋盘布满时,落子多的一方获胜。
如果你将Connect4 (四子连珠) 的game.py文件替换成Metasquares的game.py文件,同样算法将会用于学习玩Metasquares游戏。
赶紧自己来动手试试吧!