人工智能之对抗搜索
对抗搜索
1 为什么要学习对抗搜索?
上文开篇我们说了为什么要学习一点算法:不求能上天飞黄腾达,但至少得知道将来干掉自己的是谁,不能走的不明不白,是不?
李开复曾经把基础课程比拟为“内功”,把新的语言、技术、标准比拟为“外功”。 整天赶时髦的人最后只懂得招式,没有功力,是不可能成为高手的。真正学懂计算机的人(不只是“编程匠”)都对数学有相当的造诣,既能用科学家的严谨思维来求证,也能用工程师的务实手段来解决问题——而这种思维和手段的最佳演绎就是“算法”。
对抗搜索是一类算法的算法的总称,也是机器学习的一个分支。那我们为什么要学习对抗搜索呢?实在点,学它对我们有什么用?能增收或撩妹不?你总得给我个理由是不!
为了回答这个问题,我们先看一下这张图,也是AI的发展简史:
从图中可以看到,1997年Deep Blue世纪大战和2016年AlphaGo击败李世石,其中的关键技术即是对抗搜索技术。在棋类游戏里AI已经超过了人类,另外,在我们数学部分第一讲的概述中也提到了同样的问题,AI在计算机视觉领域(如ImageNet的识别)等也是远远优于人类的。**刺激不?危机不?**那怎么办呢?
成年人别问那么多,直接干学就完了!
再举一个棋类例子:设想你在玩井字棋:
井字棋是一种在3 * 3格子上进行的连珠游戏,和五子棋类似,分别代表O和X的两个游戏者轮流在格子里留下标记(一般来说先手者为X),任意三个标记形成一条直线,则为获胜。
2 什么是对抗搜索?
老规矩,为了方便描述,我们先介绍几个概念,有个先验印象,对抗搜索涉及几个常见概念:智能体、对抗搜索和博弈树。
智能体
智能体(agents):在信息技术尤其是人工智能和计算机领域,可以看作是能够通过传感器感知其环境,并借助于执行器作用于该环境的任何事物。以人类为例,我们是通过人类自身的五个感官(传感器)来感知环境的,然后我们对其进行思考,继而使用我们的身体部位(执行器)去执行操作。类似地,机器智能体通过我们向其提供的传感器来感知环境(可以是相机、麦克风、红外探测器),然后进行一些计算(思考),继而使用各种各样的电机/执行器来执行操作。现在,你应该清楚在你周围的世界充满了各种智能体,如你的手机、真空清洁器、智能冰箱、恒温器、相机,甚至你自己。
对抗搜索
对抗搜索也称为博弈搜索,在人工智能领域可以定义为:有完整信息的、确定性的、轮流行动的、两个游戏者的零和游戏(如象棋)。
游戏:意味着处理互动情况,互动意味着有玩家会参与进来(一个或多个);
确定性的:表示在任何时间点上,玩家之间都有有限的互动;
轮流行动的:表示玩家按照一定顺序进行游戏,轮流出招;
零和游戏:意味着游戏双方有着相反的目标,换句话说:在游戏的任何终结状态下,所有玩家获得的总和等于零,有时这样的游戏也被称为严格竞争博弈;
关于零和,也可以这样来理解:自己的幸福是建立在他人的痛苦之上的,二者的大小完全相等,因而双方都想尽一切办法以实现“损人利己”。零和博弈的结果是一方吃掉另一方,一方的所得正是另一方的所失,整个社会的利益并不会因此而增加一分。
例如下井字棋,一个游戏者赢了+1,则另一个一定输了-1,总和等于零。
博弈树
考虑两个游戏者:MIN和MAX,MAX先行,然后两人轮流出招,直到游戏结束。在游戏最后,给优胜者积分,给失败者罚分。
游戏可以形式地定义成含有下列组成部分的一类搜索问题:
- 初始状态,包含棋盘局面和确定该哪个游戏者出招。
- 后继状态,返回(move,state)对(两项分别为招数、状态)的一个列表,其中每一对表示一个合法的招数和其结果状态。
- 终止测试,测试判断游戏是否结束,游戏结束的状态称为终止状态。
- 效用(收益)函数,效用函数(又称为目标函数或者收益函数),对终止状态给出一个数值。在井字棋中,结果是赢、输或平,分别赋予数值+1、-1或0。有些游戏有更多的可能结果,例如双陆棋的收益范围从-192到+192。
每方的初始状态和合法招数定义了游戏的博弈树。上图给出了井字棋的部分博弈树。在初始状态,MIN有9个可能的走法。游戏交替执行,MAX下X,MIN下O,直到我们到达了树的叶节点对应的终止状态,也就是说一方的三个棋子连成一条直线或者所有棋位都填满了。叶节点上的数字指示了这个终止状态对于MAX来说的效用值;值越高被认为对MAX越有利,而对MIN则越不利。所以MAX的任务是利用搜索树(特别是终止状态的效用值)来确定最佳的招数,即求解终止状态为+1的招数。
3 对抗搜索算法
上节提到的#字棋游戏,我们可以大概画出它的博弈树:
有了这样一棵博弈树之后,有没什么方法找到最优解呢?我们介绍三种常见算法: 极小极大值算法、α-β剪枝、 蒙特卡罗树搜索算法。
3.1 极小极大值算法
本节我们以例子形式展开介绍极小极大算法。
3.1.1 分硬币游戏
虽然就算是井字棋这样的简单游戏,但是想要画出它的整个博弈树对我们而言也太复杂了,所以我们将转而讨论一个更简单的游戏:分硬币游戏。
假设我们已经有一个评价每种决策的收益的估值函数。对于极大层节点,如果我们知道了它的每一步决策的收益值,那么它总是会选择收益最大的那个决策,作为它的节点的收益值;反过来,对于极小层节点,它总是会选择收益最小的(对我方收益最小,就是对方收益最大)那个决策。
游戏规则是:一堆硬币,双方轮流将它分成大小不能相等的两堆,然后下一个人挑选任意一堆继续分下去,双方交替游戏,直到其中一个人无法继续分下去,则对方获得胜利。
假设我们刚开始有一堆7枚硬币,轮到我方先分。我需要找到我当前应该怎么样分这堆硬币。或者说,需要找到当前能够获得最优收益的决策,我们通过构造出一棵极大极小树来做到。
首先,我们穷举所有的可能的状态。用矩形代表轮到我方做决策的极大层节点,用圆形代表轮到对方做决策的极小层节点,列举出所有的状态:
注意,到这里我们还没有进行估值 ,因此这还不算是极大极小树。下面我们来设计这个游戏的估值函数,很简单,如果当前局面,我们已经赢了,那么收益为+1,如果我们输掉了,那么收益为-1,这个游戏没有平局,所以只可能有这两种收益值。
刚开始估值的时候,我们还位于根节点,我们对于整棵树是一无所知的,就像下面这样:
到这里,我们的极大极小树已经构建完成了。
我们发现,当前的根节点的收益值居然是-1,也就是说,只要对方够聪明,我们无论如何都无法取胜。
这就很绝望了,但是仔细想想,我们假设的前提是,对方是聪明绝顶,不犯错误的高手。
我们知道无论如何都会失败,那可不可以赌对方会犯错呢。
这样一想,其实3种必败的决策还是有一定的优劣性的。比如,最右边那个子节点,它的所有子树跟子树的子树收益都是-1,也就是说,对方就算乱下,我们都必输;而中间跟左边那个子节点,如果对手下错了,还有一一定几率能够通往+1的叶子节点的。因此,左边两个决策要比最右边的决策要相对好那么一点儿。因此,在发现我们已经必败的时候,依然能够在决策中做一个取舍,选择败得不明显的那种决策。
3.1.2 最优路径示例
设想有两个选手,橙色节点是MAX,蓝色节点是MIN,每人轮流移动一步,MAX先开始:
第一步:MAX选手根据DFS深度优先,生成整个博弈树,根据效用函数UTILITY得到所有叶子节点值,如下图,A是初始节点。
扩展:复杂度分析
博弈树中,分支因子(branching factor)是每个结点下的子结点数。如果各个结点分支因子不同,则可以计算平均分支因子。例如,在国际象棋中,如把一步合法走法算作一个“结点”,那么平均分支因子据信约为35。这表示棋手每一步走棋平均有大约35种合法走法,一盘棋一般每个游戏者走50步,那么搜索树大约有35^100个节点。
如图,b是分支因子数,d是游戏者走的步数之和。
3.2 α-β剪枝
上一小节我们介绍了极大极小树,对于分硬币这样相对简单的游戏,它还是能够用得上的。但是呢,它必须得穷举出所有的状态。再从终结状态开始,计算每个节点的估值,最后才能获得当前最优的决策。
极小极大值算法对博弈树执行了一个完整的深度优先探索,问题是必须检査的游戏状态的数目随着招数的数量指数级增长,比如即使是最简单的“井”字棋,它的第一步有9种决策,然后对面有9*8=72种决策,…,最后一层的决策个数达到了 9! = 362880 种。如此简单的游戏,在不做特殊处理的时候,都有几十万种决策(当然这个量级计算机还是能够hold住的)。它的棋盘大小仅仅是3 X 3,五子棋是15 X 15,围棋是19 X 19,想要穷举出所有决策,几乎是不可能的。
因此,我们不能够像上一章那样,每次都穷举出所有的结果,再去慢慢找最优决策。随着树的深度的增加,我们的节点个数是指数级上升的。这种情况下我们不得不搜索到一定程度,就停止继续往下搜索。
当我们停下来以后,这个时候,由于我们游戏还没有结束,我们如何判断当前的结果的好坏?
我们需要设计一个评价函数(Evaluation function)对于当前局面进行评分。这个评价函数如何设计?主要是根据不同的游戏,还有人类的日常经验来判断。
我当时设计五子棋AI的时候,就人为的设计了一个评价当前局面的分数的函数。比如已经有5个子连成一线了,它就是最高分;如果有4个子连成一线,它就是次高分;还有双3,…。这样我们就能根据局面,获得一个得分。当然,当对面调用这个评价函数的时候,获得的分数前面要取一个负号。因为对手的最高分,就是我们的最低分。
有了评价函数,我们就可以随时终止我们的搜索了。因为对于任何局面,我们都能够给出一个收益得分 。我们可以限定我们的搜索的深度,随时结束搜索。
但是我们的搜索空间仍然非常庞大。因为最开始的几层,可做的决策是相当多的。
比如五子棋,第一步就有225种下法。而对手对应就有225224=50,400种决策;再往下一层,就有225224*223=11,239,200种。这才第三层,就已经快爆炸了。
一般五子棋的高手都能想到后面五六步,甚至十几步。想要与之对抗,我们必须得想办法减少我们的搜索数量,增加我们的搜索深度,这样我们的AI才能看得更远的未来,想得更多,这样棋力才会变强。
在这里,我们借用剪枝技术消除搜索树的很大一部分,应用到一棵标准的极小极大值树上,它剪裁掉那些不可能影响最后决策的分支,仍然可以返回和极小极大值算法同样的结果。
我们先来理解一下,怎么样的搜索是没有必要的,假设我们限定了搜索深度为3,我们从头开始搜索,如下:
我们从根节点往下搜,直到第一个叶子节点:
此时,到达了第一个深度为3的节点,此时我们调用估值函数,假设我们获得它的收益为3,现在我们回头来看它的父节点:
现在仔细想想,如果我们继续获得它的子节点的收益,为一个比3要大的值,假设为12好了。那么当前的父节点,必然不会选择这个12,而会去选择3。因此,这个父亲节点的收益,无论如何,都不会超过3,那么它的取值范围,我们可以认为是:(-∞,3]。也就是说,我们的子节点,其实更新了它的父节点的收益的一个上界值,如图:
注意这个时候,其实跟之前的极大极小树的搜索过程没有区别,我们并没有进行任何的剪枝。接下来继续搜索:
根节点是一个MAX节点,跟之前相反,子节点的收益值3,可以用来更新的是根节点的下界(α值)。至于为什么,可以类比一下之前的。我们现在已经有搜索到一个3,如果我们以后搜索到比3小的值,那么根节点在取最大值的时候,肯定会选择更大的3,而不是其他值。因此最优解的下界就是3,不会再更小了。
我们带着根节点的取值区间[3, +∞)继续往下搜索,把这个区间赋给下一个子节点:
我们知道,当前子节点是一个收益为2的MAX节点。MAX节点可以更新父节点的上界。因此,父亲节点的上界,被修改成了2。 这里就出现了一个矛盾的区间[3,2],如下图:
由于这个区间已经产生了矛盾,我们可以直接给当前节点判死刑,跳过剩下所有的子节点了:
上面的操作叫做α-β剪枝!
可以这样理解,收益值的可行区间一旦变成矛盾的,说明当前节点必然不会是获得最优的决策,那么我们可以直接跳过这个节点,不管它还有多少个子节点没有被搜索。
Tips: 如果你觉得我上面一段很有道理,可以忽略这部分内容。
如果你是一个严谨的怀疑论者,心里不踏实,请继续看下去下面的证明过程。
我们就来仔细分析讨论一下,假如我们接着往下搜索会发生什么:
第一种,搜索到比2小的值,比如1:
第二种情况,搜索到比2大的值,比如5:
因此,我们可以放心地说,当发现收益值的区间产生矛盾的时候,我们当前的节点无论再怎么继续搜索,也不可能出现最优解了。这下可以放心跳过了。
证明完!
在这个例子里面,我们已经给中间那个点判了死刑,直接跳过它剩下的2个子节点,转到了右边那个节点。
由于α-β剪枝剪掉的点,都是必然不可能是最优解的节点,因此我们永远不会错过最优解。同时,由于及时的剪枝操作,我们大大地减少了需要搜索的节点数量,节省下来的算力就能进行更多更深层次的搜索。
这就是传说中的博弈树跟α-β剪枝的原理了。
α-β剪枝可以用于树的任何深度,而且很多情况下可以剪裁整个子树,而不是仅剪裁叶节点。一般原则是:考虑在树中某处的节点n,游戏者可以选择移动到该节点。如果游戏者在n的父节点或者更上层的任何选择点有一个更好的选择m,那么在实际的游戏中就永远不会到达n。所以一旦我们发现关于n的足够信息(通过检査它的某些后代),能够得到上述结论,我们就可以剪裁它。
扩展:
完整算法
复杂度分析
3.3 蒙特卡罗树搜索算法
下棋其实就是一个马尔科夫决策过程(MDP),即根据当前的棋面状态,确定下一步的该怎么走。
那么,该下哪一步才能确保后续赢棋的概率比较大呢?最容易想到的就是前述的一些方法:枚举后续的每一种走法,然后计算每一步赢棋的概率,选择概率最高的走,如下图所示:
3.3.1 蒙特卡罗方法
蒙特卡罗方法(Monte Carlo method)也称统计模拟方法,是1940年代中期由于科学技术的发展和电子计算机的发明,而提出的一种以概率统计理论为指导的数值计算方法。是指使用随机数(或更常见的伪随机数)来解决很多计算问题的方法。
蒙特卡罗方法于20世纪40年代美国在第二次世界大战中研制原子弹的“曼哈顿计划”计划的成员S.M.乌拉姆和J.冯·诺伊曼首先提出。数学家冯·诺伊曼用驰名世界的赌城–摩纳哥的Monte Carlo来命名这种方法,为它蒙上了一层神秘色彩。在这之前,蒙特卡罗方法就已经存在。1777年,法国数学家布丰(Georges Louis Leclere de Buffon,1707—1788)提出用投针实验的方法求圆周率π,这被认为是蒙特卡罗方法的起源。
3.3.2 蒙特卡罗方法的基本思想
当所求解问题是某种随机事件出现的概率,或者是某个随机变量的期望值时,通过某种“实验”的方法,以这种事件出现的频率估计这一随机事件的概率,或者得到这个随机变量的某些数字特征,并将其作为问题的解。
计算Pi
可以认为投针实验,在正方形内,投入一定数量的针,计算落入圆内针的数量与总共数量比值,从而计算Pi。
蒙特卡罗求定积分
蒙特卡洛方法的一个重要应用就是求定积分。来看下面的一个例子
3.3.3 UCB算法基础
如果博弈树非常庞大,按照极小极大值算法和α-β剪枝,那么对抗搜索的时间效率是十分低下的。蒙特卡罗树搜索算法就是优化博弈树搜索的算法。
下面先介绍UCB算法,这是MCTS的经典实现UCT(Upper Confidence bounds for Trees)里面用到的算法。公式如下:
3.3.4 Monte-Carlo Planning
蒙特卡罗树搜索(Monte Carlo Tree Search)是一种基于树数据结构、能权衡探索与利用、在搜索空间巨大仍然比较有效的的搜索算法。主要包括Selection、Expansion、Simulation和Backpropagation四个阶段。
1) Selection
2) Expansion
3) Simulation
4) Backpropagation
通过不断地模拟得到大部分节点的UCB值,然后下次模拟的时候根据UCB值有策略得选择值得exploitation和exploration的节点继续模拟,在搜索空间巨大并且计算能力有限的情况下,这种启发式搜索能更集中地、更大概率找到一些更好的节点。
下面是论文的伪代码实现:
简单理解,蒙特卡罗树搜索算法是一种模拟启发算法,根据UCB算法选择一个节点扩展,然后应用蒙特卡罗模拟方法计算叶子节点得分,向上传播,循环往复。
4 Alphago原理
4.1 架构
在架构上,AlphaGo可以说是拥有两个大脑,两个神经网络结构几乎相同的两个独立网络:策略网络与评价网络,这两个网络基本上是个13层的卷积神经网络所构成,卷积核大小为5 * 5,所以基本上与存取固定长宽像素的图像识别神经网络一样,只不过我们将矩阵的输入值换成了棋盘上各个坐标点的落子状况。
4.2 基础策略网络和增强策略网络
第一个大脑是策略网络,基本上就是一个单纯的监督式学习,用来判断对手最可能的落子位置。他的做法是大量的输入这个世界上职业棋手的棋谱,用来预测对手最有可能的落子位置。在这个网络中,完全不用去思考赢这件事,只需要能够预测对手的落子即可。目前AlphaGo预测对手落子位置的正确率是57%(这是刊登在Nature文章时的数据,现在想必更高了)。那各位可能认为AlphaGo的弱点是否应该就在策略网络,一方面是预测准确率不高,再者是如果下了之前他没看过的棋局是不是就有机会可以赢过他。可惜并不是,因为AlphaGo的策略网络有做了两个层面增强。
第一个层面是利用了名为增强策略网络(reinforced-learning (RL) policynetwork)的技术,他先使用部分样本训练出一个基础版本的策略网络,以及使用完整样本建立出来的进阶版策略网络,然后让两个网络对弈,后者进阶版策略网络等于是站在基础版前的高手,因此可以让基础网络可以快速的熟悉到高手可能落子的位置数据,进而又产生一个增强版,这个增强版又变成原有进阶版的高手,以此循环修正,就可以不断的提升对于对手(高手)落子的预测,RL网络80%赢了基础版本的策略网络。
第二个层面则是现在的策略网络不再需要在19 * 19的方格中找出最可能落子位置,改良过的策略网络可以先通过卷积核排除掉一些区域不去进行计算,然后再根据剩余区域找出最可能位置,虽然这可能降低AlphaGo策略网络的威力,但是这种机制却能让AlphaGo计算速度提升1000倍以上。也正因为AlphaGo一直是根据整体局势来猜测对手的可能落子选择,也因此人类耍的小心机像是刻意下几步希望扰乱计算机的落子位置,其实都是没有意义的。
4.3 评价网络
第二个大脑是评价网络。在评价网络中则是关注在目前局势的状况下,每个落子位置的最后胜率(这也是我所谓的整体棋局),而非是短期的攻城略地。也就是说策略网络是分类问题(对方会下在哪),评价网络是评估问题(我下在这的胜率是多少)。评价网络并不是一个精确解的评价机制,因为如果要算出精确解可能会耗费极大量的计算能力,因此它只是一个近似解的网络,而且通过卷积神经网络的方式来计算出卷积核范围的平均胜率(这个做法的目的主要是要将评价函数平滑化,同时避免过度学习的问题),最终答案他会留到最后的蒙利卡罗搜索树中解决。
当然,这里提到的胜率会跟向下预测的步数会有关,向下预测的步数越多,计算就越庞大,AlphaGo目前有能力自己判断需要展开的预测步数。但是如何能确保过去的样本能够正确反映胜率,而且不受到对弈双方实力的事前判断(可能下在某处会赢不是因为下在这该赢,而是这个人比较厉害)。
因此,这个部分它们是通过两台AlphaGo对弈的方式来解决,因为两台AlphaGo的实力可以当作是相同的,那么最后的输赢一定跟原来的两人实力无关,而是跟下的位置有关。也因此评价网络并不是通过这世界上已知的棋谱作为训练,因为人类对奕会受到双方实力的影响,通过两台对弈的方式,他在与欧洲棋王对弈时,所使用的训练组样本只有3000万个棋谱,但是在与李世石比赛时却已经增加到1亿。由于人类对奕动则数小时,但是AlphaGo间对弈可能就一秒完成数局,这种方式可以快速地累积出正确的评价样本。所以先前提到机器下围棋最大困难点评价机制的部分就是这样通过卷积神经网络来解决掉。
4.4 蒙特卡罗树搜索
- 选取:首先根据目前的状态,选择几种可能的对手落子模式。
- 展开:根据对手的落子,展开至我们胜率最大的落子模式(我们称之为一阶蒙地卡罗树)。所以在AlphaGo的搜索树中并不会真的展开所有组合。
- 评估:如何评估最佳行动(AlphaGo该下在哪?),一种方式是将行动后的棋局丢到评价网络来评估胜率,第二种方式则是做更深度的蒙地卡罗树(多预测几阶可能的结果)。这两种方法所评估的结果可能截然不同,AlphaGo使用了混合系数(mixing coefficient)来将两种评估结果整合,目前在Nature刊出的混合系数是50%-50%。
- 倒传导:在决定我们最佳行动位置后,很快地根据这个位置向下通过策略网络评估对手可能的下一步,以及对应的搜索评估。所以AlphaGo其实最恐怖的是,李世石在思考自己该下哪里的时候,不但AlphaGo可能早就猜出了他可能下的位置,而且正利用他在思考的时间继续向下计算后面的棋路。
5 对抗搜索总结
-
对抗搜索的适用范围
有完整信息的、确定性的、轮流行动的、两个游戏者的零和游戏,这时我们就可以用上对抗搜索算法。 -
对抗搜索的主要思想
对抗搜索的核心思想就是dfs遍历一遍博弈树。不难想到,如果博弈树非常庞大,在不加优化的情况下,对抗搜索的时间效率是十分低下的。因此,我们就需要对对抗搜索进行一定的优化。 -
对抗搜索算法
- 极小极大值算法
- α-β剪枝
- 蒙特卡罗树搜索算法
声明
本博客所有内容仅供学习,不为商用,如有侵权,请联系博主谢谢。
参考文献
[1] 斯图尔特·罗素,人工智能:一种现代的方法(第3版)[M],人民邮电出版社,2010
[2] Wu Fei,Adversarial Search–What To Do When Your “Solution” is Somebody Else’s Failure
[3] Wu Fei,Adversarial Search- Monte Carlo Tree Search selectively random sampling with simulations
[4] https://www.javatpoint.com/mini-max-algorithm-in-ai
[5] https://www.jiqizhixin.com/articles/monte-carlo-tree-search-beginners-guide
[6] http://jeffbradberry.com/posts/2015/09/intro-to-monte-carlo-tree-search/
[7] https://blog.csdn.net/chenxiaoran666/article/details/82809890
[8] https://blog.csdn.net/bitcarmanlee/article/details/82716641
[9] https://www.cnblogs.com/yifdu25/p/8303462.html
[10] https://www.cnblogs.com/neverguveip/p/9457226.html