去年,DeepMind的AlphaGo以4-1击败了世界围棋冠军李世石。超过2亿观众观看了强化学习走上世界舞台。几年前,DeepMind创造了一个可以玩Atari游戏的机器人,引起了不小的轰动。此后,该公司很快被谷歌收购。许多研究人员认为,强化学习是我们创造通用人工智能的最佳方式。这是一个令人兴奋的领域,有许多未解决的挑战和巨大的潜力。强化学习乍一看似乎非常具有挑战性,但实际上上手并不难。在本文中,我们将创建一个简单的基于Keras的机器人,它可以玩Catch游戏。CatchGames最初的Catch游戏界面Catch是一款非常简单的街机游戏,您可能在小时候玩过。游戏规则如下:水果从屏幕上方掉落,玩家必须用篮子接住;玩家每抓到一个水果就得一分;每错过一个水果扣一分。这里的目标是让计算机自己玩Catch游戏。但是,我们不会使用如此漂亮的游戏界面。相反,我们将使用游戏的简单版本来简化任务:简化的接球游戏界面要玩接球游戏,玩家必须在三个可能的动作之间做出决定。玩家可以向左、向右移动篮筐或保持不动。这个决定取决于游戏的当前状态。也就是说,取决于水果落在哪里和篮子的位置。我们的目标是创建一个模型,根据游戏屏幕的内容,选择导致最高分的动作。这个任务可以看作是一个简单的分类问题。我们可以让游戏高手多次玩游戏并记录他们的动作。然后可以通过选择类似于游戏专家的“正确”动作来训练模型。但这实际上不是人类学习的方式。人类可以在没有指导的情况下自学像Catch这样的游戏。这非常有用。想象一下,每次您想学习像Catch这样简单的东西时,都必须聘请专家团队来玩该游戏一千次!这必然非常昂贵且缓慢。在强化学习中,模型不是根据标记数据训练的,而是根据过去的经验训练的。深度强化学习强化学习受到行为心理学的启发。我们不为模型提供“正确”的行为,而是提供奖励和惩罚。该模型接受有关环境当前状态的信息(例如电脑游戏屏幕)。然后,它会输出一个动作,就像游戏手柄一样。环境将响应此操作,提供下一个状态以及奖励和惩罚操作。由此,模型学习并寻找最大化奖励的行动。实际上,有很多方法可以做到这一点。接下来,让我们看一下Q-Learning。Q-Learning在用于训练计算机玩Atari游戏时引起了轰动。现在,Q-Learning仍然是一个具有重要意义的概念。大多数现代强化学习算法都是Q-Learning的一些改进。理解Q-Learning理解Q-Learning的一个好方法是将接球游戏比作下象棋。在这两种游戏中,你都会得到一个状态S。在国际象棋中,这代表棋子在棋盘上的位置。在Catch游戏中,这表示水果和篮子的位置。然后玩家采取一个动作,称为A。在国际象棋中,玩家移动一个棋子。在Catch游戏中,这意味着将篮筐向左、向右移动或保持在当前位置。据此,将获得一些奖励R和一个新的状态S'。接球游戏和国际象棋的一个共同点是奖励不会立即跟随动作。在Catch游戏中,只有当水果掉进篮子或掉到地板上时,您才会获得奖励。然而,在国际象棋中,只有在整场比赛获胜或失败后才会颁发奖励。也就是说,奖励是稀疏分布的。大多数时候,R保持为零。由此产生的奖励并不总是先前行动的结果。也许,很久以前采取的某些行动是胜利的关键。找出哪个动作对最终奖励负责通常被称为信用分配问题。由于奖励的延迟性质,优秀的国际象棋棋手不会仅根据最直接可见的奖励来选择他们的动作。相反,他们会考虑预期的未来回报并做出相应的选择。例如,他们不必只考虑下一步棋是否会消灭对方的一颗棋子。他们还考虑从长远来看有益的行为。在Q-Learning中,我们根据最高的预期未来奖励来选择行动。我们使用Q函数进行计算。这个数学函数有两个变量:游戏的当前状态和给定的动作。因此,我们可以将其表示为Q(state,action)。在状态S中,我们将估计每个可能的动作A的奖励。我们假设在采取行动A并进入下一个状态S'之后,一切都是完美的。对于给定状态S和动作A,预期未来奖励Q(S,A)计算为立即奖励R加上后续预期未来奖励Q(S',A')。我们假设下一个动作A'是最优的。由于未来的不确定性,我们将Q(S',A')乘以γ因子来表示折扣:Q(S,A)=R+γ*maxQ(S',A')善于在心里预估未来的回报。换句话说,他们的Q函数Q(S,A)非常精确。大多数国际象棋训练围绕开发更好的Q函数展开。玩家使用游戏记录来了解某些动作是如何发生的,以及给定动作导致胜利的可能性有多大。但是机器如何评估Q函数的好坏呢?这就是神经网络发挥作用的地方。当我们最终返回玩游戏时,会产生很多“经验”,包括以下几个部分:初始状态,S采取的动作,A获得的奖励,R的下一个状态,S'这些经验是我们的训练数据。我们可以将估计Q(S,A)的问题定义为回归问题。为了解决这个问题,我们可以使用神经网络。给定一个由S和A组成的输入向量,神经网络需要能够预测Q(S,A)等于目标的值:R+γ*maxQ(S',A')。如果我们可以很好地预测不同状态S和不同动作A的Q(S,A),我们就可以很好地逼近Q函数。请注意,我们通过与Q(S,A)相同的神经网络来估计Q(S',A')。训练过程给定一批经验,训练过程如下:对于每一个可能的动作A'(左,右,不动),用神经网络预测预期的未来奖励Q(S',A');选择3个预期未来奖励的最大值作为maxQ(S',A');计算r+γ*maxQ(S',A'),即神经网络的Target值;使用损失函数来训练神经网络。损失函数可以计算预测值与目标值的距离。在这里,我们使用0.5*(predicted_Q(S,A)—target)2作为损失函数。游戏过程中,所有的经验都会储存在回放记忆(replaymemory)中。它就像一个简单的缓存存储对。这些回放类也可用于准备训练数据。让我们看看下面的代码:classExperienceReplay(object):"""Duringgameplayalltheexperiencesarestoredinareplaymemory.Intraining,batchesofrandomlydrawnexperiencesareusedtogeneratetheinputandtargetfortraining.""def__init__(self,max_memory=100,discount=.9):"""Setupmax_memory:themaximumnumberofexperienceswewanttostorememory:alistofexperiencesdiscount:thediscountfactorforfutureexperienceInthememorytheinformationwhetherthegameendedatthestateisstoreperatelyinanestedarray[...[experience,game_over][experience,game_over]...]""self.max_memory=max_memoryself.memory=discount(self,def()self.discount)states,game_over):#Saveastatetomemoryself.memory.append([states,game_over])#Wedon’twanttostoreinfinitememories,soifwehavetoomany,wejustdeletetheoldestoneiflen(self.memory)>self.max_memory:delself.memory[0]defget_batch(自我,模型,batch_size=10):#Howmanyexperiencesdowehave?len_memory=len(self.memory)#Calculatethenumberofactionsthatcanpossiblybetakeninthegamenum_actions=model.output_shape[-1]#Dimensionsofthegamefieldenv_dim=self.memory[0][0][0].shape[1]#Wewanttoreturnaninputandtargetvectorwithinputsfromanobservedstate...inputs=np.zeros((分钟(len_memory,batch_size),env_dim))#...andthetargetr+gamma*maxQ(s',a')#Notethatourtargetisamatrix,withpossiblefieldsnotonlyfortheactiontakenbutalso#fortheotherpossibleactions.Theactionsnottakethesamevalueasthepredictiontonotaffectthemtargets=np.zeros((inputs.shape[0],num_actions))#Wedrawstatesttolearnfromrandomlyfori,idxinenumerate(np.random.randint(0,len_memory,size=inputs.shape[0])):"""Hereweloadonetransitionfrommemorystate_t:initialstatesaction_t:actiontakenareward_t:rewardearnedrstate_tp1:thestatethatfolloweds'"""state_t,action_t,reward_t,state_tp1=self.memory[idx][0]#Wealsoneedtoknowwhetherthegameendedatthisstategame_over=self.memory[idx][1]#addthestatestotheinputs[i:i+1]=state_t#Firstwefillthetargetvalueswiththepredictionsofthemodel.#Theywillnotbeaffectedbytraining(sincethetraininglossforthemis0)targets[i]=model.predict(state_t)[0]"""ward,Ifthegameed(s,a)应该是最终的rewardr。否则目标值是r+gamma*maxQ(s',a')"""#这里Q_saismax_a'Q(s',a')Q_sa=np.max(model.predict(state_tp1)[0])#如果游戏结束,rewardisthefinalrewardifgame_over:#ifgame_overisTruetargets[i,action_t]=reward_telse:#r+gamma*maxQ(s',a')targets[i,action_t]=reward_t+self.discount*Q_sareturninputs,targets现在定义模型让我们定义这个使用Q-Learning来学习Catchgame的模型我们使用Keras作为Tensorflow的前端。我们的基线模型是一个简单的三层密集网络。该模型适用于简单版本的Catch游戏。你可以在GitHub上找到它的完整实现。你也可以尝试更复杂的模型,测试它是否能达到更好的性能。num_actions=3#[move_left,stay,move_right]hidden_??size=100#Sizeofthehiddenlayersgrid_size=10#Sizeoftheplayingfielddefbaseline_model(grid_size,num_actions,hidden_??size):#settingupthemodelwithkerasmodel=Sequential_smodel()model.add(密集(hidden_??shape=输入**2),activation='relu'))model.add(Dense(hidden_??size,activation='relu'))model.add(Dense(num_actions))model.compile(sgd(lr=.1),"mse")returnmodel探索最终成分Q-Learning的本质是探索。日常经验告诉我们,有时你必须做一些奇怪或随机的事情,才能发现是否有比日常行动更好的事情。Q-Learning也是如此。总是选择最好的选择意味着你可能会错过你从未探索过的道路。为了避免这种情况,学习者有时会添加一个随机术语,而不是总是使用最好的术语。我们可以确定训练方法如下:deftrain(model,epochs):#Train#Resetingthewincounterwin_cnt=0#WewanttokeeptrackoftheprogressoftheAIovertime,sowesaveitswincounthistorywin_hist=[]#Epochsthenumberofgamesweplayforeinrange(epochs):loss=0.#Resettingthegameinputital=infreset()env.observe()whilenotgame_over:#Thelearnerisactingonthelastobservedgamescreen#input_tisavectorcontainingrepresentingthegamescreeninput_tm1=input_t#Takearandactionwithprobabilityepsilonifnp.random.rand()<=epsilon:#Eatsomethingrandomfromthemenuaction=np.random.randint(0,num_actions,size=1)else:#Chooseyour模型反应.predict(input_tm1)#Wepicktheactionwiththehighestexpectedrewardaction=np.argmax(q[0])#applyaction,getrewardsandnewstateinput_t,reward,game_over=env.act(action)#Ifwemanagedtocatchthefruitweadd1toourwincounterifreward==1:win_cnt+=1#Uncommentthistorenderthegamehere#display_screen(action,3000,)输入[0])"""Theexperienceswemadeduringgameplayareourtrainingdata.Herewefirstsavethelastexperience,andthenloadabatchofexperiencestotrainourmodel"""#storeexperienceexp_replay.remember([input_tm1,action,reward,input_t],game_over)#Loadbatchofexperiencesinputs,targets.reatch(=batch_size)#trainbatchmodelonexperi记忆([input_tm1,action,reward,input_t],game_over)#Loadbatchofexperiencesinputs,targets.reatch(=batch_size)#trainbatchmodelonexperi=model.train_on_batch(inputs,targets)#sumuplossoverallbatchesinanepochloss+=batch_losswin_hist.append(win_cnt)returnwin_hist我训练了这个游戏机器人5000个epochs,结果非常好!如图所示,机器人可以接住从天空。为了可视化这个模型的学习过程,我绘制了每个epoch胜利的移动平均线,结果如下:Whattodonext?现在,你已经对强化学习有了基本的直觉。我推荐查看本教程的完整代码。您也可以尝试使用它。
