循环神经网络除了制造“新”汉字之外,还玩起了软泥排球,你能打败它吗?
软泥排球
软泥排球是一个古老的浏览器游戏,两团软泥(有一只眼睛的半圆形)分居一张网的两侧,排球落在对方场地得1分,首先拿到6分的玩家获胜。软泥排球支持双人对战,也支持单人游戏(与AI对战)。在Java applets盛行的年代,软泥排球曾经很流行。尽管这个游戏的物理可能有些问题,但人们被它的简单性所吸引,我也不例外。曾几何时,我在晚上花了很多时间在寝室打软泥排球,一点正事也没干。
除了古旧的Java applet版本,我在网上没找到什么软泥排球的版本。因此我打算自己做一个基于JavaScript和HTML5 Canvas的版本(搭配非现实的arcade风格的“物理”系统)。我尝试训练一个简单的循环神经网络来玩软泥排球。我想看看简单传统的神经演化技术能否将神经网络训练成这个游戏的专家级玩家,如果不行的话,我可能会尝试NEAT(增强拓扑神经演化)之类更高级的方法。
首先需要做的是编写一个简单的物理引擎,实现球从地上弹起、触网、碰撞玩家之类的功能。我基于p5.js完成了图形部分,并使用一些简单常规的物理、数学实现了这个引擎。然后我加上了键盘和触摸控制,这样玩家就可以移动和跳跃了。
然后就到了有趣而激动人心的部分,创建AI模型来控制软泥,看看这个模型能不能逐渐打好软泥排球。基于convnet.js,我使用基本的CNE(传统神经演化)方法训练了一个标准的循环神经网络。
网络的输入是软泥的位置和速度,球的位置和速度,当然还有对手的位置和速度。网络的输出是前进、后退和跳跃。除此以外,还有4个隐藏层作为隐藏状态和输入反馈。本质上这是一个无限深度的前馈神经网络,潜在地自动记忆先前的事件和状态,希望能形成更复杂的游戏策略。值得注意的是,激活函数只会在超过阈值(0.75)时生效。
软泥的状态与它位于网的左边还是右边无关,因为软泥的位置取的是以网为参照的相对位置,球的位置也据此相应进行调整。这样,经训练的角色可以使用相同的神经网络在网的任一边游戏。
激活函数我最后没有选择sigmoid,而是选择了convntet.js支持的tanh。
tanh函数定义如下:
对于神经网络而言,tanh是一个合理的激活函数,当输入往两个相反方向偏移时,tanh趋近于+1或-1。
所有速度和球的位置可以是正值,也可以是负值,相比sigmoid这也许是一个更有效也更自然的选择。
为了训练这样一个循环神经网络,我最后编写了一个训练函数,使训练中的每一个角色和其他角色对抗。如果角色获胜,给它加一分。如果角色失败,给它扣一分。平手的话(游戏时长换算到模拟时间后大于20秒),既不加分,也不扣分。在训练循环中,每个角色会和10个随机选择的角色对抗。保留排名在前20%的角色,丢弃剩余的角色。进行交叉和突变后进入下一代。这个训练角色进行一对一游戏的方法被称为“军备禁赛”。
使用这种方法,角色不需要手工编程任何游戏的规则和启发,而是简单地探索游戏并摸索出制胜之道。最终结果表明,经过几百代的演化,看起来角色很擅长这个游戏!
下一步要做的工作可能是应用NEAT之类更高级的方法,或者将ESP应用到AI,但是对于一个小球游戏而言,这可能有点大材小用了。另外一个选择是应用convnetjs内置的深度Q学习,因为游戏的玩法是相当简单的。目前来说,我觉得我已经创造了一个足够强健的软泥排球玩家,几乎不可能被人家玩家持续击败。
你可以试试这个游戏,看看是否能持续地击败AI。你可以在桌面电脑上使用键盘控制游戏,也可以在智能手机/平板上通过触摸控制游戏。不管是使用键盘的方向键还是通过鼠标拖曳,桌面版本控制起来更容易。你也可以查看github上的代码,不过,这些代码更多地是作为一个原型而不是一个正确实现的程序,因此代码结构可能不是特别整齐。
这个游戏一度曾被推上Hacker News的首页,根据上面的评论反馈,我又开发了一个不带预训练角色的版本,可以展现AI是如何从懵懂无知演化为职业选手的。
这个新版本配备一百个带有随机权重的角色。每个角色会与8个其他随机角色对战20秒(假定每秒30帧)。大致上,100代的模拟实际上模拟了18小时的真实游戏,在我的机器上需要20-30秒。跑一晚上的话,基本上相当于模拟了几十年的真实游戏。
原文 Neural Slime Volleyball
感谢原作者hardmaru授权论智编译,未经授权禁止转载。详情见转载须知