1、启发式搜索“启发“( heuristic)是关于发现和发明规则及方法的研究。在状态空间搜索中, 启发式被定义成一系列规则, 它从状态空间中选择最有希望到达问题解的路径。 人工智能问题求解者在两种基本情况下运用启发式策略:1.一个问题由于在问题陈述和数据获取方面固有的模糊性可能使它没有一个确定的解。医疗诊断即是一例。所给出的一系列症状可能有多个原因; 医生运用启发搜索来选择最有可能的论断并依此产生治疗的计划。视觉问题又是一例。看到的景物经常是模糊的, 各个物体在其连接、范围和方向上可以有多个解释。光所造成的幻觉加大了这些模糊性, 视觉系统可运用启发式策略选择一给定景象的最有可能解释。2.一个问题
2、可能有确定解, 但是求解过程中的计算机代价令人难以接受。在很多问题(如国际象棋)中, 状态空间的增长特别快, 可能的状态数随着搜索的深度呈指数级增长、分解。在这种情况下, 穷尽式搜索策略, 诸如深度优先或广度优先搜索,在一个给定的较实际的时空内很可能得不到最终的解。 启发式策略通过指导搜索向最有希望的方向前进降低了复杂性。通过仔细考虑, 删除某些状态及其延伸, 启发式算法可以消除组合爆炸, 并得到令人能接受的解。然而, 和发明创造的所有规则一样, 启发式策略也是极易出错的。在解决问题过程中启发仅仅是下一步将要采取措施的一个猜想。它常常根据经验和直觉来判断。由于启发式搜索只有有限的信息,诸如当前
3、Open表中状态的描述,要想预测进一步搜索过程中状态空间的具体的行为很难办到。一个启发式搜索可能得到一个次最佳解, 也可能一无所获。这是启发式搜索固有的局限性。这种局限性不可能由所谓更好的 启发式策略或更有效的搜索算法来消除。启发式策略及算法设计一直是人工智能的核心问题。博奕和定理证明是两个最古老的应用: 二者都需要启发式知识来剪枝以减少状态空间。显然, 检查数学领域中每一步推理或棋盘上每一步可能的移动是不可行的。启发式搜索常常仅是实践中的解答。近来, 专家系统的研究把启发式策略作为问题求解的一个重要部分。当一个专家解决问题时, 他检查所获取的信息并作出决定。实际上, 专家用来解决问题的“拇指
4、法则“很大程度上是启发式的。 这些启发性知识被专家系统的设计者提取出来并形成规则。通常启发式算法由两部分组成: 启发方法和使用该方法搜索状态空间的算法。本章先介绍最好优先搜索的算法, 再讨论启发式算法的设计和评估。在一字棋游戏中(图 4.5), 穷尽搜索的组合数很大。第一步移动共有九种移法 , 每一种又有八种对应走法依次类推, 这个问题在穷尽搜索策略下需考虑 9!个状态。根据对称性可以减少搜索空间的数目。棋盘上很多构造是等价的。譬如, 第一步实际上只有三种移法, 角、边的中央以及网络正中。在状态空间的第二层上, 由对称性可进一步减少到 127!种。在图 5.1 中可见到该状态空间比最初的状态空
5、间要小, 但它在扩展过程中还要继续分解。然而, 一个简单的启发式策略几乎可以整个地消除复杂的搜索过程。首先, 将棋子移到棋盘上有最多的赢线的点。最初的三种状态显示在图 5.2中。 若两种状态有相等的赢的机率, 取其中的第一个。这样的话,可设计一种算法(完全实现启发式搜索), 它选择并移到具有最高启发值的状态。在这种情况下, 占椐网络的中间点, 其它的各种状态都不再考虑, 它们的延伸状态同时也给消除了。如图 5.3 所示三分之二的状态空间就这样给剪枝了。第一步走完后, 对方只能有两种走法(见图 5.3)。无论选择哪种走法,我方均可以通过启发式搜索选择下一步可能的走法。在搜索过程中, 每一步只需估
6、价一下单个节点的子结点; 不需要强力搜索。图 5.3 显示了游戏前三步简化了的搜索过程。每种状态都标记了它的启发值。要精确地计算待检查的状态的数目比较难, 但可以大致计算它的上限。一盘棋最多走九步, 每步的下一步平均有四、五种走法。这样大约就是 4.59, 近 40 种状态, 比 9!改善了很多。5.1 启发信息和估计函数人工智能的核心课题是问题求解。所谓“问题求解“就是在广义图中寻找一条从初始状态出发, 到达目标状态的解树。例如旅行问题是解决从出发点到达目的地的路线和工具问题; 机器人装配机器, 就是给出把一堆零件变成一台机器的一系列操作; 定理证明就是寻找一条从前提条件到达结论的通路等等。
7、在实际解决一个具体问题时, 人们常常把一个具有复杂联系的实际问题抽象化,保留某些主要因素, 忽略掉大量次要因素, 从而将这个实际问题转化成具有明确结构的有限状态空间问题, 这个空间中的状态和变化规律都是已知的有限集合, 因此可以找到一个求解该问题的算法。然而, 在智能活动中使用最多的不是具有完备性的算法, 而是不一定完备的启发式方法。其原因有二:首先, 大多数情况下, 智能系统不知道与实际问题有关的全部信息, 因而无法知道该问题的全部状态空间, 不可能用一套算法来求解其中的所有问题, 这样就只能依靠部分状态空间和一些特殊的经验性规则来求解其中的部分问题。其次, 有些问题在理论上存在求解算法,
8、但是在工程实践中, 这些算法不是效率太低, 就是根本无法实现, 为了提高解题的效率, 不得不放弃使用这些算法, 而求助于一些经验性的启发式规则。例如在博弈问题中, 计算机为了保证最后胜利, 可以将所有可能的走法都试一遍, 然后选择最佳走步。这样的算法是可以找到的, 但计算所需的时空代价十分惊人。就可能有的棋局数讲, 一字棋是 9!=3.6105, 西洋跳棋是 1078, 国际象棋是 10120, 围棋是 10761。假设每步可能选择一种棋局, 用极限并行速度(10-104 年/步)计算, 国际象棋的算法也得 1016 年即 1 亿亿年才可以算完, 而我们已知的宇宙史才 100 亿年!由此看来,
9、 启发式的问题求解, 不仅在实践上是需要的, 而且在理论上也是必不可少的。对问题空间进行搜索时, 提高搜索效率需要有和被解问题的解有关的大量控制性知识作为搜索的辅助性策略。有两种极端的情况: 一种是没有任何这种控制性知识作为搜索的依据, 因而搜索的每一步完全是随意的, 如随机搜索; 另一种是有充分控制性知识作为依据, 因而搜索的每步选择都是正确的, 这种搜索叫最佳搜索。一般情况是介于二者之间, 这些控制性信息反映在估价函数之中。估价函数的任务就是估计待搜索结点的重要程度, 给它们排定次序。估价函数f(x)可以是任意一种函数, 如有的定义它是结点x处于最佳路径上的概率, 或是x结点和目标结点之间
10、的距离, 或是x格局的得分等等。一般来说, 估价一个结点的价值, 必须综合考虑两方面的因素: 已经付出的代价和将要付出的代价。在此, 我们把估价函数f(n)定义为从初始结点经过n 结点到达目标结点的最小代价路径的代价估计值, 它的一般形式是: f(n)=g(n)+h(n)其中g(n)是从初始结点到n的实际代价, h(n)是从n到目标结点的最佳路径的估计代价, 主要是h(n)体现了搜索的启发信息。因为实际代价g(n)可以根据生成的搜索树实际计算出来, 而估计代价h(n)却依赖于某种经验估计, 它来源于我们对问题的解的某些特性的认识, 这些特性可以帮助我们更快地找到问题的解。一般地, 在f(n)中
11、, g(n)的比重越大, 越倾向于广度优先搜索方式; h(n)的比重越大, 越倾向于深度优先搜索方式。g(n)的作用一般是不可忽略的, 因为它代表了从初始结点经过n 到达目标结点的总代价估值中实际已付出的那一部分。保持g(n)项就保持了搜索的广度优先趋势, 这有利于搜索的完备性, 但影响搜索的效率。在特殊情况下, 如果只希望找到达到目标结点的路径而不关心已付出的代价, 则g(n)的作用可以忽略。另外, h(n) g(n)时, 也可以忽略g(n), 这时有f(n)=h(n), 这有利于搜索的效率, 但影响搜索的完备性。给定一个问题后, 根据问题的特性和解的特性, 可以有多种方法定义估价函数, 用
12、不同的估价函数指导搜索, 其效果可以相差很远。因此,必须尽可能选择最能体现问题特性的, 最佳的估价函数。5.2 启发式搜索算法5.2.1 局部择优搜索法(瞎子爬山法)实现启发式搜索最简单的方法是瞎子爬山法(hill climbing)。 瞎子爬山法在搜索过程中扩展当前结点并估价它的子结点。最优的子结点被选择并进一步扩展; 该子结点的兄弟结点和父结点都不再保留。当搜索达到一种状态, 该状态比它的所有子结点都要好, 则搜索停止。瞎子爬山法可以这样理解一个盲人急切地想登上山顶, 他总是沿着最陡的山路向上爬, 直到再不能找到新的路径。瞎子爬山法有这样一个缺陷: 一个错误的启发知识可能导致搜索无法沿着正
13、确的路径前进, 从而增加了搜索的深度, 甚至是无穷尽地搜索。由于瞎子爬山法不保存所走过的结点信息, 故瞎子爬山算法无法修正错误的路径。瞎子爬山法还可能在一个局部的最佳点上停止。当搜索到一个结点, 它的估计代价比任一个子结点都要小, 则算法结束。如果此时并不是目标状态, 而只是一个局部最优结点, 则该算法就不能得到目标解。因此, 在一个限定的环境下, 瞎子爬山法可能会极大地提高搜索效率, 但是对于整个搜索空间, 就有可能无法得到最佳解。重排九宫游戏就是一个突出的例子。为了将一个特定的格局移到它的目标位置上, 常常需要移动已经在其目标位置上的将牌。这对于完成拼图是必要的, 但它显然暂时恶化了拼板上
14、的状态。由于“更好“并不是“最好“, 瞎子爬山法无法区别局部和全局最优解。处理这个问题时有许多种方法, 譬如随时地修正估价函数来突破局部最优的限制。但是总的来说, 没有一种方法能保证瞎子爬山法的最佳效率。下面 介绍一个瞎子爬山法的例子跳棋程序。在人工智能中, Samuel的跳棋程序最早应用该方法。在跳棋程序中, 不仅运用了启发式搜索, 还实现了简单的学习功能。跳棋程序中根据几个不同启发值的总和来估算棋局的状态: aixii其中xi是棋局的一系列特征, 如残局优势、残局棋子力量分布, 中心点位置的控制等。这些xi的系数由它在整个估值中所处的重要性来确定。也就是说, 如果残局优势比控制中心点重要,
15、 则残局优势的系数要大。该程序将搜索空间扩展到一定局数并根据多项式估值函数估算该局中所有状态值。根据 5.4.2 节介绍的极大极小法, 程序可倒推出图中所有状态的估值。 游戏者根据结点的最佳状态走棋; 对手走棋后, 根据新的棋局状态, 整个过程将再来一遍。若多项式估值函数导向一系列不能取胜的移动, 程序将调整其系数以提高能力。具有较大系数的因素由于在输棋原因中占很大比重, 它的系数将减小, 而较小的系数将增 大以提高相关因素的影响力。如果取胜则情况相反。 通过与人或其自身的不同版本对抗, 程序不断训练学习。可以看出, 跳棋游戏在学习过程中采用的是瞎子爬山法, 通过对多项式估值函数的局部的改进来
16、提高自身的性能。该程序能不断改进到水平很高为止。然而, 由于算法依靠瞎子爬山法, 它不可避免地具有某些限制。例如, 由于采用的不是全局的策略, 程序容易被对手利用某种启发策略导向陷阱。同样, 程序的自学习功能容易被对手的随手棋所迷惑; 例如, 老对手灵活地采用多种策略, 或故意乱下棋, 这就会使多项式估值函数的系数随意性很大, 从而全面降低了程序的能力。上例表明, 尽管瞎子爬山法有其局限性, 但是若估价函数选取得当并能够避免局部最优解和无穷搜索时, 它就会充分发挥搜索的高效率。总之, 启发式搜索需要一个具有很多启发信息的算法, 而最好优先搜索就提供了这一算法。5.2.2 最好优先搜索法(有序搜
17、索法)和第四章中所提到的深度优先及广度优先搜索算法一样, 最好优先搜索算法也使用了两张表来记录结点信息: 在Open表中保留所有已生成而未考察的结点; 在Closed表中记录已访问过的结点。算法中有一步是根据某些启发信息, 按结点距离目标状态的长度大小重排Open表中的结点这样。循环中的每一步只考虑Open表中状态最好的结点, 这就是最好优先搜索算法,又称为有序搜索法。其数据结构(Open表)既不同于广度优先使用的队(先进先出), 也不同于深度优先使用的栈(后进先出) , 而是一个按结点的启发估计函数值的大小为序排列的一个表, 有时也称为“优先队“。进入优先队的结点不是简单地排在队尾(或队首)
18、, 而是根据其估值的大小插入队中 合适的位置, 每次从队中优先取出估值最小的结点加以扩展。最好优先搜索的算法描述如下:PROCEDURE BEST-FIRST-SEARCHINITIALIZE:OPEN=START;CLOSED= ;WHILE OPEN DOBEGINREMOVE THE NEXT STATE FROM OPEN, CALL IT X;IF X IS A GOAL THEN RETURN THE SOLUTION PATH THAT LED TO X;PROCESS X,GENERATING ALL ITS CHILDREN;FOR EACH CHILD OF XDO CAS
19、ETHE CHILD IS NOT ALREADY ON OPEN OR CLOSED:BEGINASSIGN A HEURISTIC VALUE TO THE CHILD STATE;ADD THE CHILD STATE TO OPEN;END;THE CHILD IS ALREADY ON OPEN:IF THE CHILD WAS REACHED ALONG A SHORTER PATH THANTHE STATE CURRENLTY ON OPENTHEN GIVE THE STATE ON OPEN THIS SHORTER PATH VALUETHE CHILD IS ALREA
20、DY ON CLOSED:IF THE CHILD WAS REACHED ALONG A SHORTER PATH THANTHE STATE CURRENLTY ON CLOSEDTHENBEGINGIVE THE STATE ON CLOSED THIS SHORTER PATH VALUE;MOVE THIS STATE FROM CLOSED TO OPENENDEND;PUT X ON CLOSED;RE-ORDER STATES ON OPEN ACCORDING TO HEURISTIC MERIT(BEST VALUES FIRST)END;RETURN(FAILURE);
21、%OPEN IS EXHAUSTEDEND.在每一次重复中, 最好优先搜索算法从Open表中取出第一个元素, 如果该元素满足目标条件, 则算法返回到达该元素的搜索路径。在这里, 每个结点都保留父结点的信息, 以保证返回完整的搜索路径。若Open表的第一个元素不是目标结点, 则算法应用相应的规则进行一系列操作来产生它的子结点。如果子结点的状态已在Open(或Closed表)中, 则算法保证新的状态记录两个求解路径中花费小的一个, 不保留重复的状态。这样, 当Open表(或Closed表)中的结点再一次被发现时, 通过刷新它的祖先结点的历史记录, 算法就极有可能得到到达目标结点的更短的路径。接着,
22、 最好优先搜索法估算Open表中每个结点的状态的启发值, 按照值的大小重新排序, 将值最小的状态放在表头。图 5.4 是一个层次式状态空间, 有些结点旁边标上了相应的启发值。 标上值的那些状态都是在最好优先搜索中实际生成的。在这张图中, 启发搜索算法扩展的状态都已显示; 算法无需搜索所有的状态空间。最好优先搜索算法的目标是尽可能地减小搜索空间而得到解, 启发信息给得越多, 处理的状态就越少。下面给出了这张图的最好优先搜索算法的运行过程。假定P是目标状态, 则到P 的路径上的结点状态有较低的启发值。在这里, 启发信息难免会有错误; 状态O比P的值小而先被检查。然而, 不象瞎子爬山法, 该算法本身
23、有纠错功能, 能从此状态返回并找到正确的目标状态。1. Open=A5; Closed= 2. 估算A5; Open=B4,C4,D6; Closed=A53. 估算B4; Open=C4,E5,F5,D6; Closed=B4,A54. 估算C4; Open=H3,G4,E5,F5,D6; Closed=C4,B4,A55. 估算H3; Open=O2,P3,G4,E5,F5,D6; Closed=H3,C4,B4,A56. 估算O2; Open=P3,G4,E5,F5,D6; Closed=O2,H3,C4,B4,A57. 估算P3; 已得到解!图 5.5 是算法执行了五次循环后的状态空间
24、图。Open表和Closed 表中的状态以不同的亮度显示。Open表中记录搜索的当前结点, Closed表中保存已考察过的状态。最好优先搜索算法总是从Open表中选取最“好“的状态进行扩展。但是, 由于启发信息有时可能出错, 故算法并不丢弃其它的状态而把它们保留在Open表中。当某一个启发信息将搜索导向错误路径时, 算法可以从Open表中检索先前产生的“ 次最好“状态, 并且将考察方向转向空间的另一部分上。如图 5.4, 当算法发现状态B 的子结点有很差的启发值时, 搜索转移到C, 但B的子结点都保留在Open表中, 以防算法在未来的某一步再一次转向它们。在最好优先搜索算法中, 就象第四章中的
25、算法一样, 当某一路径无法到达目标解时, 可使搜索转到另一条路径上。5.2.3 启发估计函数的实现不同的启发策略对解决九宫问题有不同的影响。图 5.6 显示了九宫问题的起始状态、目标状态以及搜索过程中产生的前三个状态。最简单的启发策略是计算每种格局下与目标结点的格局相比时位置不符的将牌数目。从感觉上来说, 这种策略很有效, 因为在其它条件相同的情况下, 位置不符将牌数目越少, 它看上去和最终目标越近, 因而是检验的下一个状态。但是, 这种策略并没有充分利用所能获得的信息, 它没有考虑将牌所需移动的距离。一个“较好“的启发策略是将牌移到目标位置上时所需移动距离的总和相加作为启发值。这两种策略都没
26、有考虑将牌逆转时的情况, 也就是, 如果两块将牌相邻但是和目标格局相比位置相反, 这至少需要移动两次才能将它们移到正确的位置上, 将这一点加以考虑的启发策略对每一对逆转将牌乘以一个小倍数(如 2)。图 5.8 显示的就是将这三种策略运用到图 5.6 的三个子状态情况下所得到的结果。 在图 5.8 中, “距离总和“ 策略看上去比仅仅计算位置不符将牌数目的策略提供了一个更精确的估算。而且, 由于在这些状态中, 没有直接给出逆位数, 故都给予估值。第四种策略克服了仅计算将牌逆转数目策略的局限, 它将位置不符将牌数目总和与 2 倍将牌逆转数目相加。这个例子说明, 设计一个好的启发策略具有相当的难度。
27、设计算法的目标就是利用有限的信息作出一个明智的选择。上述策略都忽略了一些重要的信息, 需加以改进。好的启发策略的设计是一个经验问题, 判断和直觉是很重要的因素, 但是衡量的最终尺度则是具体应用时的效果。由于所有的启发策略都可能出错, 每一种搜索算法都可能导向错误的路径, 但是在深度优先搜索中, 可用深度计数探查无效路径来解决这个问题。这个思想也可运用到启发式搜索中。如果两种状态具有相等的启发值, 通常先考察离根较近的那个状态。这个状态极有可能就处在到达目标状态的最佳路径上。可用一个深度计数来记录从起始状态到其子孙状态的距离。计数起始值为0, 每搜索一层计数值加 1。 这个值可加到启发值上, 层
28、数越浅的状态越优先。这样, 就得到了估计函数f, 它由两个因素所组成: f(n)=g(n)+h(n)其中g(n)是状态n到达起始状态的路径的实际长度, h(n)是状态n到目标状态的最佳路径的启发值。在九宫问题中, 可令h(n)为位置不符的将牌数目。若将这个估计函数值运用到 图 5.6 的子状态中, 它们的f值分别是 6,4,6(见图 5.9)。各个状态的f(n)值 这里f(n)=g(n)+h(n)g(n)=从n到初始状态的实际长度 h(n)=位置不符的将牌数目 图 5.9 九宫图的估计函数f值在图 5.10 中, 使用上面所定义的f函数得到一个完整的搜索树。 每种状态都以一个字母及它的估计函数
29、值f来标记。每种状态头部的数字显示该状态从Open 表中取出时的顺序。有些状态没有数字标记, 这是因为当算法结束时, 这些状态仍在Open表中。图 5.10 启发式搜索产生的九宫图状态空间产生图 5.10 的一系列过程如下:1.open=a4; closed=2.open=c4,b6,d6; closed=a43.open=e5,f5,g6,b6,d6; closed=a4,c44.open=f5,h6,g6,b6,d6,i7; closed=a4,c4,e55.open=j5,h6,g6,b6,d6,k7,i7; closed=a4,c4,e5,f56.open=l5,h6,g6,b6,d6
30、,k7,i7; closed=a4,c4,e5,f5,j57.open=m5,h6,g6,b6,d6,n7,k7,i7; closed=a4,c4,e5,f5,j5,l58.成功,m=目标状态!在第 3 步中, e和f都具有相等的启发值 5。先检查状态e并产生它的子结点h和i。尽管h同f一样具有相等的位置不符的将牌数目, 但它在整个状态空间中所处层数要深。深度函数g(n)使算法在第 4 步中选择f作为考察对象。此时, 算法回退一层并继续搜索过程。此时的状态空间图以及相应的Open表、Closed表见图 5.11。事实上, 估计函数f中的g使搜索具有广度优先的性质, 这就使整个搜索免于被一个错误
31、的估计值所误导。当算法沿着一条不断返回“好“估值但实际上是错误的路径搜索时, g值将不断增加并最终在f中占主导地位, 从而迫使搜索回退到一个具有较小f值的路径。这就保证算法不会永远沿着一条路径搜索下去。在 5.3 节中, 将讨论在何种条件下, 最好优先算法使用f一定能得到一条最短的路径。当估计函数f运用到最好优先搜索算法上时, 它提供了启发式搜索的一般规则。总结如下:1.根据产生式规则和一些其它的操作生成当前考察结点的子状态。2.检查每个状态以前是否已经考察过(已在Open表或Closed表中), 以防止循环。3.每个状态n都赋以f(n)值。其中f=g+h, h 值使搜索沿着具有较好启发值的状
32、态所处路径前进; g值防止搜索在一条无效的路径上无限继续下去。4.Open表中的状态按f值排序。 这些状态在未被考察或未找到到目标状态时一直保存, 通过保存这些状态,算法能随时从一无效路径上返回。Open 表中可能保存有状态空间中不同层次的状态, 以充分保证能随时转移搜索方向。5.通过设计Open表和Closed表的存贮方式, 可提高算法的效率。例如, 将Open表处理为一个堆栈能够缩短排序的时间。最好优先搜索算法是启发式搜索的一个较常用算法。它支持多种估计函数的使用, 既可用于目标驱动搜索, 又可用于数据驱动搜索, 它是检验启发式搜索行为的一个基础。因为它的普遍性, 最好优先搜索可和多种启发策略一起使用。应用启发策略的另一个有趣的方法是可信度的运用。它在专家系统中被用来衡量一条规则所产生的结果的可信程度。当一个专家考虑一个问题时, 他经常给出所得结论正确的可能程度。同样, 专家系统使用可信度方法来选择具有最高可信度的结果作为最终结论, 而具有较小可信度的状态不予考虑。在下节中将讲述这种方法。