我对 MCTS 的具体细节感到困惑。
为了说明我的问题,让我们以井字游戏为例。在选择阶段之后,当到达叶节点时,树在所谓的扩展阶段中被扩展。假设一个特定的叶节点有 6 个孩子。扩展阶段是否会扩展所有孩子并在他们身上运行模拟?或者扩展阶段是否只会随机选择一个子节点并运行模拟,并且仅在选择策略稍后到达它们时才扩展其他子节点?
或者,如果这两个都是可接受的变体,那么每个的优点/缺点是什么?
我对 MCTS 的具体细节感到困惑。
为了说明我的问题,让我们以井字游戏为例。在选择阶段之后,当到达叶节点时,树在所谓的扩展阶段中被扩展。假设一个特定的叶节点有 6 个孩子。扩展阶段是否会扩展所有孩子并在他们身上运行模拟?或者扩展阶段是否只会随机选择一个子节点并运行模拟,并且仅在选择策略稍后到达它们时才扩展其他子节点?
或者,如果这两个都是可接受的变体,那么每个的优点/缺点是什么?
到目前为止,最常见(也可能也是最简单/直接)的实现是在扩展阶段仅扩展一个节点;具体来说,对应于播放阶段随机选择(半)的第一个状态的节点。如果你想要任何形式的树生长(你这样做),这也是你必须做的最低限度的事情。
其他变体也是可能的,但不太常见。您在问题中建议的变体是扩展在选择阶段遇到的最终节点的所有子节点,并为所有节点运行 Play-Out。我真的不熟悉任何关于这种策略的文献,我自己从未尝试过。直觉上,我希望它的表现非常相似,也许略有不同更差。本质上,这将做的是将搜索算法的“行为”稍微更倾向于广度优先搜索行为,而不是最佳优先搜索行为。您在选择阶段花费的计算时间要少一些,因为每个选择阶段都会跟进例如 6 个(或您拥有的任何分支因子)播放,而不仅仅是一个。平均而言,我预计这会稍差一些,因为选择阶段是算法“最佳优先搜索”行为的主要来源。我当然不希望这样的变化会导致性能上的巨大差异,如果有的话。它也可能依赖于域;在某些情况下更糟,在其他情况下更好。
我曾经使用过的另一种变体是在完整的播放线中扩展每个节点,然后是播放阶段。您可以将其可视化为非常“细”但“深”的扩展,而您上面讨论的建议将被可视化为“浅”但“宽”的扩展(并且单个节点的常规扩展策略将是“瘦”和“浅”)。
对于此策略,与标准策略相比,更容易清楚地定义其优势和劣势。主要优点是您可以从 Play-Outs 中保留更多信息,而丢弃的信息更少。这是因为反向传播阶段,在 Play-Out 终止后,只能将信息存储在存在的节点中。如果您立即扩展播放阶段中遵循的完整播放线,您可以将结果(终端状态下的评估)存储在所有这些节点中。如果您不展开完整的播放(例如只展开第一个节点),您将不得不“跳过”所有您尚未展开的节点(它们不存在),并且您还不能在其中存储结果。
这种方法的主要缺点是它需要更多的内存,树的生长速度更快。
如果您对计算时间有非常严格的限制,如果您希望只能运行很少的 MCTS 算法迭代,我个人会推荐这种方法。例如,我个人在我的通用视频游戏 AI 代理中使用了这个;这是一款实时游戏,您必须每40 毫秒做出一次决定。在如此短的时间内,您无法运行许多 MCTS 模拟。这意味着:
相比之下,如果您正在开发一个代理来玩棋盘游戏,并且它每回合有数分钟的思考时间,那么每个扩展阶段仅扩展单个节点的标准方法会变得更具吸引力。如果您能够运行数万次或更多次迭代,那么“忘记”树深处的一点信息真的没有什么坏处。如果您运行多次迭代,内存不足的风险也会变得更加严重,因此您不想太快地增长树。