做者:苏博览
html
商业转载请联系腾讯WeTest得到受权,非商业转载请注明出处。算法
原文连接:wetest.qq.com/lab/view/42…编程
本文内容包含如下章节:bash
Chapter 2 AI Methods网络
Chapter 2.1 General Notes数据结构
本书英文版: Artificial Intelligence and Games - A Springer Textbook框架
这个章节主要讨论了在游戏中常常用到的一些基础的人工智能算法。这些算法大部分都出如今一些人工智能和机器学习的入门书籍中。在讲解算法在游戏中的应用的时候,会以吃豆人(Ms Pac-Man)做为样例,讲解怎么用行为树算法,树搜索算法,监督学习算法,无监督学习算法,强化学习算法和进化算法来构建一个玩游戏的AI。dom
吃豆人机器学习
这些AI算法虽然形态各有不一样,可是本质上都是基于两个基本的要素来作文章。一个是算法的表示(Representation), 另一个是效用(Utility)。模块化
首先是怎么把学到的玩游戏的知识用某种数据结构来表示出来。这个数据结构也是和要用的算法强相关的。好比若是用文法演化算法(Grammatical Evolution),最后学到的就是一些文法(Grammars);若是用几率模型或者有限状态机,最后知识就表示成一个图(Graphs);而行为树和决策树还有遗传算法会学到一颗树(Trees),神经网络天然是联结主义的(Connectionism), 遗传算法和演化策略会带来一些基因编码(Genetic Representation), 而TD-learning 和 Q-learning则学到了一下状态转移的表格(Tabular)。
固然,寻找一个最优的算法表示一般是很难的,而且世界上没有免费的午饭,算法之间老是各有利弊的。不过通常来讲,咱们但愿选择的算法的表示尽量的简单,和占用更小的空间。而咱们须要有一些先验知识来找到一个较好的算法表示。
另一方面,咱们会用效用(Utility)这个来自博弈论的术语来指导算法的训练。不严格的来讲,能够把它看作一个函数,输入是当前状态和算法可能的动做(Action),输出是算法作出某个动做所可以得到的好处。理论上来讲,若是咱们能获得一个准备的Utility Function, 咱们的算法每次均可以找到最优的路径。但实际上,咱们只可以获得一个估计值,或者更确切的,在没有先验知识的状况下,咱们只能经过记住咱们探索过的状态和路径及其得到的回报来估算一个效用值来表示某个走法的好坏(Measure of Goodness)。若是游戏自己的状态空间比较小,咱们能够经过遍历全部的可能状况来获得一个准备的Utility Function。而一般咱们面对的问题都有着极大的搜索空间,所以咱们但愿可以尽量的探索到更多的路径,而后在探索到的数据上进行采样来获得一个估计的Utility。
Utility 在不一样的算法上的叫法会有所不一样,在含义上也有细微的差异。例如在一些树搜索算法上,咱们会用启发式的规则(Heuristic)来指导算法的收敛。而在遗传算法上,它又被叫作适应度函数(Fitting Function)。在优化算法上,咱们更经常使用的词语是Loss, Error, Cost; 而在强化学习,Reward是一个更经常使用的单词,这里最主要的缘由是:作RL的人因为成天面对着逆天难的问题,因此喜欢用reward(相对于loss)来激励本身。(大雾)
这样,咱们训练AI的过程就是寻找一套Representation最好的参数,能够最大化Utility。所以,可以学到一个好用的模型,取决于Utility Function是否设计的合理,和咱们的目标是否彻底一致。对于监督学习来讲,Utility等价于其Label;对于强化学习来讲,Utility来自于环境的反馈。而无监督学习的Utility则来自于数据自己的结构和共性。
实现一个NPC,最简单的方法当时就是写一些规则,但这样子显然比较low,不过在不少场景下其实也能知足须要了。若是咱们把规则(If, else 语句)抽象,就变成了有限状态机(Finite State Machine, FSM) 或者 行为树(Behavior Trees, BT)。
FSM直到21世纪的前十年都仍是普遍的应用到各类游戏之中。咱们能够把FSM理解为一个图(Graphs), 游戏中的状态是图的一个节点(Nodes), 能够相互转化的状态之间有连线(Edges),连线之间定义了状态转移(Transitions)的条件,而在每一个状态中,定义了一系列的动做(Actions),当AI处于该状态时,就执行具体的动做,如向左或向右或者更复杂的组合动做。
例如上面的一个基于FSM的吃豆人AI,首先定义了状态和状态转移的条件。当在寻找豆子的状态的时候,能够给AI编程具体在每一个状态的行为。好比在寻找豆子的状态,一开始随机游走,若是看到豆子就去吃掉它,若是看到Ghost,就进入到躲避Ghost的状态。下面是一个简单的3种状态下动做的伪代码:
def seek_pellet: while 1:
if ghost_in_sight:
return evade_ghost_state
if power_pill_eaten:
return chase_ghost_state
if pellet_in_sight:
go_and_eat_pellet() #using pathfinding algorithm find best action
else:
move_randomly()def evade_ghost:
while 1:
if not ghost_in_sight:
return seek_pellet_state
if power_pill_eaten:
return chase_ghost_state
leave_the_ghost() # using tree search to find best actiondef chase_ghost:
while 1:
if power_pill_expired:
return seek_pellet_state
find_the_ghost() # using tree search to find best action复制代码
能够看到FSM的AI的模式是很是固定的,玩家很容易发现其中的pattern,这个经过模糊逻辑(Fuzzy Logic)和增长几率能够获得必定缓解。另外,对于一些要完成比较难的任务的NPC,须要为其设计不少不一样的状态和状态转移方式,整个过程是很是复杂和难以调试的。所以人们定义了行为树(BT),经过模块化(Modularity)的设计,能够把复杂的行为拆解成简单的任务,从而减轻整个系统的复杂度和提升可维护性。所以,自光晕2(Halo 2)以后,BT就取代了FSM,成为游戏工业界最经常使用的NPC算法。
行为树是把FSM的图转变成为一颗树结构。所以行为树是有一个Root节点,而后往下有一些中间节点,最后是叶子节点。咱们从根节点遍历行为树,每个子节点被执行的时候都按预设的时间间隔回传三种信息给到父节点:
Run: 表示这个节点还在继续执行
Success:表示这个节点已经成功执行了
Failure: 表示这个节点执行失败了
而行为树的节点有3种类型:
Sequence: (如上图的蓝色方块)表示该父节点会顺序执行它的子节点,而且知道它的全部子节点都成功执行了,它才会回传Success给更上层的节点。
Selector:(如上图的红色方块)表示该父节点会从其子节点中选择其中一个执行,只要有一个子节点执行成功,该父节点就会返回Success。除非全部子节点都执行失败,该父节点才会返回失败。父节点选择子节点的顺序有两种方式:a. Probability:按几率选取子节点执行的顺序;b. Priority: 该预设的顺序选取子节点。
Decorator:(如上图紫色的方块)至关于节点执行增长一些条件,好比限定执行的时间,或者失败从新执行的次数。如图中是限定了一个条件,只有在看到Ghost的时候,吃豆子(Eat Next Pellet)这个节点才会返回Fail 状态。
能够看到,行为树的结构能够比较方便的把复杂的行为分解成层次的简单结构,方便维护。例如我能够在吃豆子(Eat Next Pellet)这个Node上设定新的很复杂的算法,但不会影响整个树的其余节点。同时测试起来也比较方便,咱们能够针对行为树的某个子树来进行测试,而不影响整个大的框架。
固然,行为树和FSM也有一样的问题,就是NPC的行为的可预见性仍是比较大的,整个行为的模式仍是受限于总体的行为树框架。虽然能够经过一些几率的方式来增长一些随机性,但总体来看仍是有不少局限性的。
在行为树里面,选择不一样子树的方式仍是稍显简单,经过必定的规则,或者预设的几率来选择不一样的子节点(子树)来执行。所以人们在上面添加了基于效用的方式(Utility-based)。简单说来,咱们定义一个Utility Function: u = F(S,a)。 根据当前游戏的环境状态S, 获得某一个行为a的效用值u。这个Utility Function是能够经过规则设定,也能够经过一些复杂的学习方法来获得。好比咱们能够用一个神经网络去预测在当前状态下,作哪一个动做更好。好比在吃豆人游戏中,可能咱们就不须要来写一些规则来判断该作什么动做(好比看到Ghost就中止吃豆子的子树执行),而能够用更动态的方式来控制(好比Ghost在多远的地方,往哪一个方向走,豆子和Ghost和NPC的位置关系怎么样)是否中止吃豆子的子树执行。固然更General的说,其实后续的强化学习,监督学习也好,都是在学一个Utility Function来控制NPC的动做。本质上,Utility-based AI是一种构建NPC的思想,能够应用到不一样的AI方法上。
更多推荐
“深度兼容测试”现已对外,腾讯专家为您定制自动化测试脚本,覆盖应用核心场景,对上百款主流机型进行适配兼容测试,提供详细测试报告。
点击:wetest.qq.com/cloud/deepc… 了解更多详情。
若是使用当中有任何疑问,欢迎联系腾讯WeTest企业QQ:2852350015