用强化学习玩转Chrome暗藏的小恐龙跳一跳,这儿有一份教程
什么!未连接到互联网!!
明明是联网状态,为什么我想访问的页面
无!法!打!开!
淡定。
作为一个GoogleChrome浏览器的用户,当你看到上面那个页面时,不要沮丧。换个角度一想,墙内还能有更多的Play时间哦~
你有没有注意到画面里那个小恐龙?
一个新世界开启了。
这个“恐龙跳一跳”其实是藏在Chrome浏览器里好多年的一个彩蛋。小恐龙是一只霸王龙(T-Rex)。
2013年Chrome开始用这个小恐龙的图像代替令人烦恼的404页面。2014年秋天,这只恐龙被正式改造成一个横版小游戏。以彩蛋的方式隐藏在新版Chrome浏览器里。
呐,如果你还不知道这个彩蛋,可以抓紧试一试。比方说——
访问一个不翻墙就看不了的网页
或者直接输入:chrome://dino
或者访问:(需翻墙)
后来,这个小游戏也成了不少AI练手的对象。
动图版:
速度已经快到飞起
总而言之,一句话,这个AI能轻松玩到2万多分……
你能玩到几分?大概率是玩不到这个成绩的吧。毕竟在页面上,人类玩家的历史最高分是18842。
例如,GitHub上就有一个开源的代码“IAMDinosaur”,同样也是利用神经网络+遗传算法,来搞定恐龙跳一跳。
地址在此:
美中不足,上面这个项目也没有配上太详尽的解读。然而好消息是,最近有个国外的小哥RaviMunde,列了一份非常详尽的教程。
这个教程用的方法是强化学习中的Q-learning,比较适合入门练手,而且对硬件的要求不高。
量子位搬运这份教程如下。
Q-learning了解/复习一下对动物来说,强化学习的能力是与生俱来的。拿儿童学步来举例,如果小朋友努力的迈出第一步,就会获得父母的鼓励——可能是鼓掌叫好,也可能是一块糖;但如果小朋友坚决不肯学习走路,那父母就不会给它糖吃了。强化学习就是依照这类激励行为而设置的。
而在这个游戏中,对我们的AI小恐龙来说,强化学习需要让他在无监督的情况下,先认识到做出不同动作的结果,并且以获得高分为最高激励。
一个典型的强化学习闭环
RaviMunde用Q-learning模拟了一个特殊函数,这个函数驱动AI在不同状况下做出正确的选择。
Q-learning是强化学习的一种无模型实现,根据Q值对每个状态进行判断此时如果采取行动,能获得怎样的奖励。一个样本Q表让我们了解数据的结构。在恐龙跑酷游戏中,状态是当前的游戏截图,能采取的行动是跳或不跳[0,1]
一个样本Q表
RaviMunde决定用深度神经网络来决定小恐龙何时起跳,而且要在最简单的强化学习实现基础上,引入不同参数来辅助它。
但之后,Munde小哥发现,他训练了一个倔强的模型——模型坚定的认为,跳,一定比不跳好。所以,为了让模型在训练时能在跳与不跳之间多尝试一下,他引入了一个函数ɛ来决定行动的随机性,然后再逐渐减小它的值来削减随机性,最终让模型去选择最有可能获得奖励的行动。
赞誉分布(CreditAssignment)问题可能会让模型陷入混乱——目前获得的奖励究竟来自于过去的哪个行为呢?在恐龙跑酷游戏中,小恐龙跳到半空中后无法再次跳跃,但模型可能会在恐龙处于半空中时发出跳跃指令,这种情况就让恐龙非常容易砸到仙人掌上。
在面临这种问题的情况下,可以引入贴现因子(DiscountFactor)γ来决定模型做出动作时看得多远。γ间接解决了赞誉分布问题,在这个游戏中,当γ=0.99时,模型认识到在无障碍时随便跳会导致真的遇到障碍时自己正在半空中,无法继续跳跃。
除了这两个参数之外,后面就几乎不需要任何参数了。
=50000.framesoverwhichtoannealepsilonFINAL_EPSILON=0.0001startingvalueofepsilonREPLAY_MEMORY=50000sizeofminibatchFRAME_PER_ACTION=1你需要准备的是
Selenium
OpenCV
PIL
ChromiumdriverforSelenium
Keras
略微解释一下这几个工具。
构建这个AI模型,需要用Python编程。而游戏是用JavaScript写成的。所以,得借助一些工具才能更好地沟通。
Selenium是一种流行的浏览器自动化工具,用于向浏览器发送操作指令,以及获取各种游戏参数。
接口的事情搞定了,还得想办法获得游戏截屏。用Selenium也行,但是速度很慢,截屏和处理一次大约得1秒钟。
用PIL和OpenCV能够更好地完成截屏和图像预处理,可以达到5fps的帧率。你可能觉得还是慢,但已经足够对付这个游戏了。
游戏模块下面这个模块,实现了Python和浏览器(使用Selenium)的沟通。
'''*Gameclass:Seleniuminterfacingbetweenthepythonandbrowser*__init__():Launchthebroswerwindowusingtheattributesinchrome_options*get_crashed():*get_playing():trueifgameinprogress,falseiscrashedorpaused*restart():ssasignaltobrowser-javascripttorestartthegame*press_up():ssasingletopressupgettothebrowser*get_score():getscurrentgamescorefromjavascriptvariables.*pause():pausethegame*resume():resumeapausedgameifnotcrashed*():closethebrowserandthegame'''classGame:def__init__(self,custom_config=True):chrome_options=Options()chrome__argument("disable-infobars")self._driver=(executable_path=chrome_driver_path,chrome_options=chrome_options)self.__window_position(x=-10,y=0)self.__window_size(200,300)self._((game_url))noactionsarepossibleskiplearningatthistimeandmakethemodelwaitdefpress_up(self):self.__element_by_tag_name("body").s_keys(_UP)defget_score(self):score_array=self.__script("_.")score=''.join(score_array)takesgameasinputfortakingactionsself._game=game;();noactioncanbeperformedforthefirsttimewhengamestartsdefis_running(self):returnself.__playing()defis_crashed(self):returnself.__crashed()defjump(self):self.__up()defduck(self):self.__down()游戏状态模块
神经网络直接使用这个模块,来执行操作并获取新的状态。
'''get_state():acceptsanarrayofactions,performstheactionontheagentreturns:newstate,rewardandifthegameed.'''classGame_sate:def__init__(self,agent,game):self._agent=agentself._game=gamedefget_state(self,actions):score=self.__score()reward=0.1*score/10gameoverifactions[1]==1:returntheExperiencetuple预处理
游戏修改
原始的游戏相对复杂,比如游戏速度会逐渐加快,障碍物会改变,还会出现云朵、星星、地面纹理等。一次同时学习这么多东西会消耗大量时间,甚至在训练过程中引入不必要的噪音。
为此作者修改了游戏的源代码、简化局面,去除了一些视觉元素(云、历史最佳成绩等),还有让恐龙的奔跑速度保持不变。
原图
修改后
图像处理
原始截图的分辨率为1200×300,包含三个通道。作者计划使用4个连续的屏幕截图作为模型的单一输入,也就是1200×300×3×4。
问题是,这个小哥只有一个i7的CPU可用,所以他的电脑没办法在处理这个尺寸输入的同时玩游戏。所以,还得继续用OpenCV的库调正截图大小、裁剪等。最终输入图像大小为40×20像素,单通道,并用Canny突出显示边缘。
defgrab_screen(_driver=None):processingimageasrequiredreturnimagedefprocess_img(image):resaleimagedimensionsimage=(image,(0,0),fx=0.15,fy=0.10)img[y:y+h,x:x+w]image=(image,threshold1=100,threshold2=200)modelhyperparametersLEARNING_RATE=1e-4img_rows,img_cols=40,20img_channels=420*40*4(Activation('relu'))(Conv2D(64,(4,4),strides=(2,2),padding='same'))(Activation('relu'))(Conv2D(64,(3,3),strides=(1,1),padding='same'))(Activation('relu'))(Flatten())(Dense(512))(Activation('relu'))(Dense(ACTIONS))adam=Adam(lr=LEARNING_RATE)(loss='mse',optimizer=adam)print("Wefinishbuildingthemodel")returnmodel开始训练
接下来,就是见证奇迹的时刻~~
也就是用一段代码来训练模型,这段代码的任务是:
从无操作开始,得到初始状态initialstate(s_t)
观察玩游戏的过程,代码中的OBSERVATION表示步数
预测一个操作的效果
在ReplayMemory中存储经验
训练阶段,从ReplayMemory里随机选择一组,用它来训练模型
如果gameover了,就重开一局
更详细的,可以看这段自带注释的代码:
'''Parameters:*model=KerasModeltobetrained*game_state=GameStatemodulewithaccesstogameenvironmentanddino*observe=flagtoindicatewhertherthemodelistobetrained(weightupdates),elsejustplay'''deftrainNetwork(model,game_state):loadfromfilesystem0=donothing,getnextstepafterperformingtheactions_t=((x_t,x_t,x_t,x_t),axis=2).reshape(1,20,40,4)lessrunningloss=0Q_sa=0action_index=0r_t=0actionattrandomlyexploreanactionprint("----------RandomAction----------")action_index=(ACTIONS)a_t[action_index]=1else:inputastackof4images,getthepredictionmax_Q=(q)o=donothing,1=jumpruntheselectedactionandobservednextstateandrewardx_t1,r_t,terminal=game__state(a_t)last_time=()x_t1=x_(1,x_[0],x_[1],1)appthenewimagetoinputstackandremovethefirstoneonlytrainifdoneobserving;sampleaminibatchtotrainontrainBatch((D,BATCH))iftOBSERVEs_t=s_t1t=t+1print("TIMESTEP",t,"/EPSILON",epsilon,"/ACTION",action_index,"/REWARD",r_t,"/Q_MAX",(Q_sa),"/Loss",loss)
将这个模型用到从ReplayMemory里随机选择的一批上:
deftrainBatch(minibatch):foriinrange(0,len(minibatch)):loss=0inputs=((BATCH,s_[1],s_[2],s_[3]))32,2state_t=minibatch[i][0]Thisisactionindexreward_t=minibatch[i][2]nextstateterminal=minibatch[i][4]predictedqvaluesQ_sa=(state_t1)ifterminated,onlyequalsrewardelse:targets[i,action_t]=reward_t+GAMMA*(Q_sa)loss+=_on_batch(inputs,targets)主体方法
调用下面的方法,就能启动上面的训练流程:
#argument:observe,onlyplaysiftrue,elsetrainsdefplayGame(observe=False):game=Game()dino=DinoAgent(game)game_state=Game_sate(dino,game)model=buildmodel()trainNetwork(model,game_state)结果
这个模型,小哥用一周的时间训练了200万帧,其中前100万帧用来调整游戏参数修补bug,后100万帧真正用来训练。
现在,这个模型的最好成绩是265分。从下面的得分和损失变化图里,能看出模型的loss在后100万帧逐渐稳定,比较低,但是会随时间波动。
游戏得分
后100帧的损失(loss)
目前的局限虽然这个模型后来表现还算可以了,但比人类还是差了一大截。
当然,别忘了这个小哥比较穷,他只有一个i7的CPU。
他认为,模型学得还不够快,得分还不够高,要怪这样几个因素:一是因为用CPU来学习,它总是掉帧;二是供这个AI来玩耍的图像实在是太小了,只有40×20,在当前的模型架构下就可能导致了特征的损失,还拖慢了学习速度。
如果改用GPU,说不定……
相关链接用GPU究竟会不会改善,你们可以拿这份代码来试试:
原文地址:
OneMoreThing其实嘛,让AI搞定小恐龙这件事,本质上跟让AI搞定FlappyBird是一样的。如果你想深入研究一下这件事,这里再推荐两篇。
机器学习玩转FlappyBird全书:六大“流派”从原理到代码
使用神经网络+遗传算法玩转FlappyBird|教程
就酱~
—完—
诚挚招聘
量子位正在招募编辑/记者,工作地点在北京中关村。期待有才气、有热情的同学加入我们!相关细节,请在量子位公众号(QbitAI)对话界面,回复“招聘”两个字。
վ'ᴗ'ի追踪AI技术和产品新动态
推荐阅读
-
寻找数字人源代码开发商、数字人直播系统的你,不妨看过来!
亳州易天科技是一家专注于数字人源代码开发和数字人直播系统的公司。我们拥有先进的人工智能技术,致力于为客户提供高质量的数字人产品和服务。亳州易天科技致力于成为数字人技术的领军企业,我们将继续不断努力,提供更高质量的数字人产品和服务,为客户创造更多价值。相信在我们的努力下,数字人技术将为人们的生活带来更...
-
用电脑畅玩地铁跑酷,体验刺激的地铁逃亡!
用电脑畅玩地铁跑酷,体验刺激的地铁逃亡!随着科技的不断发展,越来越多的人开始喜欢使用电脑来娱乐和放松自己。在游戏方面,跑酷游戏是一种非常受欢迎的游戏类型。而地铁跑酷作为跑酷游戏的代表作之一,受到了大众的广泛喜爱。今天,我将为大家推荐一款在电脑上畅玩地铁跑酷的游戏,带领大家体验刺激的地铁逃亡!这款游戏...
-
罕见!象棋比赛夫妻大战,朱少钧击败何媛,这事吕钦许银川没碰到
在象棋赛场中,夫妻相遇,会发生什么样的事。一般而言,比赛中很少有夫妻相碰的。这是多方面的原因。首先,男女一起比赛的,就少,除了少部分混合打的比赛,大部分都是男女分开战。其次,象棋夫妻也不多,前有吕钦许妙玲,许银川文静。后有洪智何静,赵鑫鑫赵雅倩等。其三,夫妻要水平差距不是很大,否则也碰不上,毕竟是积...
-
情侣吵架新模式:互相索要赠送衣物,女子怒将衣裤脱光!
要不要换个地方啊?你俩吵架归吵架,也不至于在光天化日之下,互相索要回送的衣物呀!在广州某座立交桥下的道路上,一对情侣发生了激烈的争吵,怒斥对方对自己的感情没有以前那么专一,更是在情绪激动之下,要求对方返还自己所赠送的衣物。都说冲动是魔鬼,这句话一点也没有说错。男人恐吓女子道:“把我送你的裤子脱了啊!...