束搜索算法 BEAM Search

  1384人阅读  评论(0)  收藏  举报

目录(?)


最近搜了几篇BEAM SEARCH 束搜索的文章,这篇最直白易懂,并有示例的详细步骤图解,比维基百科的更为合适,因此拿在这里,供参考。

原文链接:Beam Search Algorithm (Draft by Andrew Jungwirth)

束搜索算法

本文目标:

1.演示了如何在存储有限的情况下进行类似的宽度优先的图搜索算法,即束搜索,使用启发式函数和限定的束宽度beam width .

2.强调在搜索空间很大的情况下对图搜索进行存储限制的重要性

3.展示了书搜索的优缺点

所需背景知识:

要了解束搜索,先要熟悉图的概念,如边和结点;知道搜索树如何表示图的搜索过程。除此之外,必须要了解宽度优先搜索算法,因为束搜索是对该算法的改进。

束搜索算法:

尽管宽度优先搜索能保证在 unweighted graph无向图中找到起始结点和终止节点之间的最短路径,但由于该算法对存储的消耗是指数级的,因此对于搜索空间大的问题,BFS几乎无用武之地,在算法周到最优解之前,存储就已经耗尽了。为对BFS进行改进,就有了束搜索算法。束搜索旨在消耗有限存储的情况下进行宽度优先遍历,找到最优解。

为此,束搜索要借助一个启发式代价函数heuristic cost function,h,来估计当前节点到目标节点的代价的大小。并用束宽度beam width,B,来限制在每层遍历时存储的该层节点的个数。因此,BFS存储的是下一层的所有节点,而束搜索仅根据h,存储B个最优的下层节点。利用启发式代价函数h是一个寻优的过程,而B又限制仅存储有限个重要的节点,避免了在达到最优解之前存储耗尽的情况。

在BFS搜索借助一个Openlist,在BS中则借助BEAM来存储将继续展开的节点。此外,还有一个hash table来存储已经访问过的节点,与BFS中的closed list作用类似。初始化时,把起始节点加入BEAM 和 hash table。 然后,在算法的每个主循环中,将在BEAM中的节点的所有后继节点加入SET中,并在SET中选取最优的B个节点加入BEAM和hash table中。注意,已经在hash table中的节点是不会再加入BEAM中的,因为到达改点的更近的路径已经找到了。直至目标节点加入到SET,或者hash table满了(表明存储耗尽),或者BEAM为空(表明搜索无解),则算法终止。

束搜索的伪码如下。该伪码是对于无向图而言,因此变量g表示的是搜索的深度,即到达该节点的代价大小。

束搜索的伪码

/*初始化 */

g = 0;//步数
hash_table = { start };//hash表,用于标记所有已经访问过的节点。类似于close表
BEAM = { start };//BEAM 一个容量受限的open表,也就是在初始化时,需要指定open表的容量


while(BEAM ≠ ∅){// 循环直到BEAM为空,也就是没有需要考察的节点了
  SET = ∅;// 设置集合为空


  for(each state in BEAM){ //对于BEAM中的每个状态state
    for(each successor of state){ // 对于state的每个后继successor
      if(successor == goal) return g + 1;// 如果后继就是目标节点,那么找到了一个路径。
      SET = SET ∪ { successor }; // 否则,后继加入到集合中
    }
  }//for


  BEAM = ∅; // 因为open表中的内容已经处理完毕,清空open表
  g = g + 1; // 又访问了一层


  /* fill the BEAM for the next loop */
  while((SET ≠ ∅) AND (B > |BEAM|)){ // 集合不空并且open表没有满 BEAM是容量为B的open表
    state = successor in SET with smallest h value; //从集合中选出最好的点 h参考备注1
    SET = SET \ { state }; // 从集合中删除该节点
    if(state ∉ hash_table){ // 该状态还没有考察过 则state不在hash_table中
      if(hash_table is full) return ∞; // hash表满了 算法已经没法执行下去 当然没能找到路径
      hash_table = hash_table ∪ { state }; //state已经考虑过 添加到hash_table中
      BEAM = BEAM ∪ { state }; //state添加到BEAM中等待判断
    }//if
  }//while




// 注意 有可能集合不空 但是BEAM已经满了
// 根据算法 集合会被清空 集合中的点将不再考虑
// 因此该算法不是完备的
// 也就是说 有可能原问题有解,但是由于这里舍弃了一些中间过程
// 导致最终无法获得解




}//while


// goal was not found, and BEAM is empty - Beam Search failed to find the goal
return ∞;//没能找到路径 

束搜索的搜过过程示例

下面的算法步骤解析中,对每个main loop中的数据有两行表示:第一行为该次循环中加入SET的节点,这些节点按照启发式函数值排序,如果h值大小相同,则按照字母瞬息排序。由于该存储结果是数学集合,因此对于有多个前节点的节点,只出现在SET中一次;第二行数据给出从SET中留下存储到BEAM中的节点,即main loop中的第二部分。两行中都给出了hash table的值,即当前的状态。注意,在该例子中,hash table大小是7,哈希函数是简单的线性焊锡,即键值的ASCII值模7。每个节点以 节点名(前继节点)的方式表示。


图1

Trace 1, B = 1

loop numberSet(first row per numbered loop)
BEAM(second row per numbered loop)
hash_table
 BEAM = { I(null) }hash_table = { _, I(null), _, _, _, _, _ }
1SET = { G(I), J(I), E(I), H(I) }hash_table = { _, I(null), _, _, _, _, _ }
1BEAM = { G(I) }hash_table = { _, I(null), _, _, _, _, G(I) }
2SET = { D(G), J(G), I(G) }hash_table = { _, I(null), _, _, _, _, G(I) }
2BEAM = { D(G) }hash_table = { _, I(null), _, D(G), _, _, G(I) }
3SET = { G(D) }hash_table = { _, I(null), _, D(G), _, _, G(I) }
3BEAM = { }hash_table = { _, I(null), _, D(G), _, _, G(I) }

搜索树如下图所示:


图2


此时,BEAM已经为空,搜索无解。G的邻节点D已经在close table 中了,因此搜索无法再继续下去,导致BEAM为空。该例说明了束搜索的一个致命弱点:如果启发式函数不正确,可能使算法找不到最优路径,即使该最优路径确实是存在的。如果增大B值呢?一方面,使得算法找打最优路径的概率增大,另一方面,它也增大了存储空间。因此,B的选择极大的影响了束搜索的性能。图2即为失败的搜索路径示例。

下面我们改变B的值,再看看结果如何,待搜索的图还是图1,下下面是搜索过程:

Trace 2, B = 2

loop numberSet(first row per numbered loop)
BEAM(second row per numbered loop)
hash table
 BEAM = { I(null) }hash_table = { _, I(null), _, _, _, _, _ }
1SET = { G(I), J(I), E(I), H(I) }hash_table = { _, I(null), _, _, _, _, _ }
1BEAM = { G(I), J(I) }hash_table = { _, I(null), J(I), _, _, _, G(I) }
2SET = { A(J), D(G), G(J), J(G), E(J), I(G) }hash_table = { _, I(null), J(I), _, _, _, G(I) }
2BEAM = { A(J), D(G) }hash_table = { A(J), I(null), J(I), D(G), _, _, G(I) }
3SET = { C(A), G(D), J(A) }hash_table = { A(J), I(null), J(I), D(G), _, _, G(I) }
3BEAM = { C(A) }hash_table = { A(J), I(null), J(I), D(G), C(A), _, G(I) }
4SET = { B(C) [goal found - algorithm returns], A(C) }hash_table = { A(J), I(null), J(I), D(G), C(A), _, G(I) }


图3


这次搜索过程中,路径IJACB找到了解。然而,尽管找到了一条通路,但是该解并不是最优的。这里,不精确的启发式函数又影响了搜索的性能。图3即为搜索过程的搜索树。注意,在第三层节点中,只有一个节点A进入了搜索树,这证明了,该搜索算法并不是将每一层的最优节点都被放入BEAM中。

下面再将B设为3,看看结果如何:

Trace 3, B = 3
loop numberSet(first row per numbered loop)
BEAM(second row per numbered loop)
hash_table
 BEAM = { I(null) }hash_table = { _, I(null), _, _, _, _, _ }
1SET = { G(I), J(I), E(I), H(I) }hash_table = { _, I(null), _, _, _, _, _ }
1BEAM = { G(I), J(I), E(I) }hash_table = { _, I(null), J(I), _, E(I), _, G(I) }
2SET = { A(J), C(E), D(G), F(E), G(J), J(E), E(J), H(E), I(E) }hash_table = { _, I(null), J(I), _, E(I), _, G(I) }
2BEAM = { A(J), C(E), D(G) }hash_table = { A(J), I(null), J(I), C(E), E(I), D(G), G(I) }
3SET = { B(C) [goal found - algorithm returns], A(C), C(A), J(A) }hash_table = { A(J), I(null), J(I), C(E), E(I), D(G), G(I) }

搜索树如下图:


图4

当B=3时,束搜索找到了最优解。然而,同时hashtable 的空间也被填满。


Trace 4, B = 4
loop
number
SET (first row per numbered loop)
BEAM (second row per numbered loop)
hash_table
 BEAM = { I(null) }hash_table = { _, I(null), _, _, _, _, _ }
1SET = { G(I), J(I), E(I), H(I) }hash_table = { _, I(null), _, _, _, _, _ }
1BEAM = { G(I), J(I), E(I), H(I) }hash_table = { H(I), I(null), J(I), _, E(I), _, G(I) }
2SET = { A(J), C(E), D(G), F(E), G(J), J(E), E(H), H(E), I(E) }hash_table = { H(I), I(null), J(I), _, E(I), _, G(I) }
2BEAM = { A(J), C(E), D(G) [not enough memory - algorithm returns] }hash_table = { H(I), I(null), J(I), A(J), E(I), C(E), G(I) }
搜索树如下:


图5

当B=4时,该算法很快就存储不够了。这展示了束搜索的一个重要缺陷:当B很大时,它也会想BFS一样耗尽存储。


注:原文还有关于效率和正确性的一些分析,以及一个小练习,在此未翻。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值