自TensorFlow官方發(fā)布其2.0版本新性能以來(lái),不少人可能對(duì)此會(huì)有些許困惑。因此博主Roman Ring寫了一篇概述性的文章,通過實(shí)現(xiàn)深度強(qiáng)化學(xué)習(xí)算法來(lái)具體的展示了TensorFlow 2.0的特性。
正所謂實(shí)踐出真知。
TensorFlow 2.0的特性公布已經(jīng)有一段時(shí)間了,但很多人對(duì)此應(yīng)當(dāng)還是一頭霧水。
在本教程中,作者通過深度強(qiáng)化學(xué)習(xí)(DRL)來(lái)展示即將到來(lái)的TensorFlow 2.0的特性,具體來(lái)講就是通過實(shí)現(xiàn)優(yōu)勢(shì)actor-critic(演員-評(píng)判家,A2C)智能體來(lái)解決經(jīng)典的CartPole-v0環(huán)境。
雖然作者本文的目標(biāo)是展示TensorFlow 2.0,但他先介紹了DRL方面的內(nèi)容,包括對(duì)該領(lǐng)域的簡(jiǎn)要概述。
事實(shí)上,由于2.0版本的主要關(guān)注點(diǎn)是簡(jiǎn)化開發(fā)人員的工作,即易用性,所以現(xiàn)在正是使用TensorFlow進(jìn)入DRL的好時(shí)機(jī)。
本文完整代碼資源鏈接:GitHub:https://github.com/inoryy/tensorflow2-deep-reinforcement-learning
Google Colab:https://colab.research.google.com/drive/12QvW7VZSzoaF-Org-u-N6aiTdBN5ohNA
安裝
由于TensorFlow 2.0仍處于試驗(yàn)階段,建議將其安裝在一個(gè)獨(dú)立的(虛擬)環(huán)境中。我比較傾向于使用Anaconda,所以以此來(lái)做說(shuō)明:
>condacreate-ntf2python=3.6>sourceactivatetf2>pipinstalltf-nightly-2.0-preview#tf-nightly-gpu-2.0-previewforGPUversion
讓我們來(lái)快速驗(yàn)證一下,一切是否按著預(yù)測(cè)正常工作:
>>>importtensorflowastf>>>print(tf.__version__)1.13.0-dev20190117>>>print(tf.executing_eagerly())True
不必?fù)?dān)心1.13.x版本,這只是一個(gè)早期預(yù)覽。此處需要注意的是,默認(rèn)情況下我們是處于eager模式的!
>>>print(tf.reduce_sum([1,2,3,4,5]))tf.Tensor(15,shape=(),dtype=int32)
如果讀者對(duì)eager模式并不熟悉,那么簡(jiǎn)單來(lái)講,從本質(zhì)上它意味著計(jì)算是在運(yùn)行時(shí)(runtime)被執(zhí)行的,而不是通過預(yù)編譯的圖(graph)來(lái)執(zhí)行。讀者也可以在TensorFlow文檔中對(duì)此做深入了解:
https://www.tensorflow.org/tutorials/eager/eager_basics
深度強(qiáng)化學(xué)習(xí)
一般來(lái)說(shuō),強(qiáng)化學(xué)習(xí)是解決順序決策問題的高級(jí)框架。RL智能體通過基于某些觀察采取行動(dòng)來(lái)導(dǎo)航環(huán)境,并因此獲得獎(jiǎng)勵(lì)。大多數(shù)RL算法的工作原理是最大化智能體在一個(gè)軌跡中所收集的獎(jiǎng)勵(lì)的總和。
基于RL的算法的輸出通常是一個(gè)策略—一個(gè)將狀態(tài)映射到操作的函數(shù)。有效的策略可以像硬編碼的no-op操作一樣簡(jiǎn)單。隨機(jī)策略表示為給定狀態(tài)下行為的條件概率分布。

Actor-Critic方法
RL算法通常根據(jù)優(yōu)化的目標(biāo)函數(shù)進(jìn)行分組。基于值的方法(如DQN)通過減少預(yù)期狀態(tài)-動(dòng)作值(state-action value)的誤差來(lái)工作。
策略梯度(Policy Gradient)方法通過調(diào)整其參數(shù)直接優(yōu)化策略本身,通常是通過梯度下降。完全計(jì)算梯度通常是很困難的,所以通常用蒙特卡洛(monte-carlo)方法來(lái)估計(jì)梯度。
最流行的方法是二者的混合:actor- critical方法,其中智能體策略通過“策略梯度”進(jìn)行優(yōu)化,而基于值的方法則用作期望值估計(jì)的引導(dǎo)。
深度actor- critical方法
雖然很多基礎(chǔ)的RL理論是在表格案例中開發(fā)的,但現(xiàn)代RL幾乎完全是用函數(shù)逼近器完成的,例如人工神經(jīng)網(wǎng)絡(luò)。具體來(lái)說(shuō),如果策略和值函數(shù)用深度神經(jīng)網(wǎng)絡(luò)近似,則RL算法被認(rèn)為是“深度的”。

異步優(yōu)勢(shì)(asynchronous advantage) actor- critical
多年來(lái),為了解決樣本效率和學(xué)習(xí)過程的穩(wěn)定性問題,已經(jīng)為此做出了一些改進(jìn)。
首先,梯度用回報(bào)(return)來(lái)進(jìn)行加權(quán):折現(xiàn)的未來(lái)獎(jiǎng)勵(lì),這在一定程度上緩解了信用(credit)分配問題,并以無(wú)限的時(shí)間步長(zhǎng)解決了理論問題。
其次,使用優(yōu)勢(shì)函數(shù)代替原始回報(bào)。收益與基線(如狀態(tài)行動(dòng)估計(jì))之間的差異形成了優(yōu)勢(shì),可以將其視為與某一平均值相比某一給定操作有多好的衡量標(biāo)準(zhǔn)。
第三,在目標(biāo)函數(shù)中使用額外的熵最大化項(xiàng),以確保智能體充分探索各種策略。本質(zhì)上,熵以均勻分布最大化,來(lái)測(cè)量概率分布的隨機(jī)性。
最后,并行使用多個(gè)worker來(lái)加速樣品采集,同時(shí)在訓(xùn)練期間幫助將它們?nèi)ハ嚓P(guān)(decorrelate)。
將所有這些變化與深度神經(jīng)網(wǎng)絡(luò)結(jié)合起來(lái),我們得到了兩種最流行的現(xiàn)代算法:異步優(yōu)勢(shì)actor- critical算法,或簡(jiǎn)稱A3C/A2C。兩者之間的區(qū)別更多的是技術(shù)上的而不是理論上的:顧名思義,它歸結(jié)為并行worker如何估計(jì)其梯度并將其傳播到模型中。

有了這些,我將結(jié)束我們的DRL方法之旅,因?yàn)檫@篇博客文章的重點(diǎn)是TensorFlow 2.0特性。如果您仍然不確定主題,不要擔(dān)心,通過代碼示例,一切都會(huì)變得更加清晰明了。
使用TensorFlow 2.0實(shí)現(xiàn)Advantage Actor-Critic
讓我們看看實(shí)現(xiàn)各種現(xiàn)代DRL算法的基礎(chǔ)是什么:是actor-critic agent,如前一節(jié)所述。為了簡(jiǎn)單起見,我們不會(huì)實(shí)現(xiàn)并行worker,盡管大多數(shù)代碼都支持它。感興趣的讀者可以將這作為一個(gè)練習(xí)機(jī)會(huì)。
作為一個(gè)測(cè)試平臺(tái),我們將使用CartPole-v0環(huán)境。雖然有點(diǎn)簡(jiǎn)單,但它仍然是一個(gè)很好的選擇。
通過Keras模型API實(shí)現(xiàn)的策略和價(jià)值
首先,讓我們?cè)趩蝹€(gè)模型類下創(chuàng)建策略和價(jià)值預(yù)估神經(jīng)網(wǎng)絡(luò):
importnumpyasnpimporttensorflowastfimporttensorflow.keras.layersasklclassProbabilityDistribution(tf.keras.Model):defcall(self,logits):#samplearandomcategoricalactionfromgivenlogitsreturntf.squeeze(tf.random.categorical(logits,1),axis=-1)classModel(tf.keras.Model):def__init__(self,num_actions):super().__init__('mlp_policy')#notf.get_variable(),justsimpleKerasAPIself.hidden1=kl.Dense(128,activation='relu')self.hidden2=kl.Dense(128,activation='relu')self.value=kl.Dense(1,name='value')#logitsareunnormalizedlogprobabilitiesself.logits=kl.Dense(num_actions,name='policy_logits')self.dist=ProbabilityDistribution()defcall(self,inputs):#inputsisanumpyarray,converttoTensorx=tf.convert_to_tensor(inputs,dtype=tf.float32)#separatehiddenlayersfromthesameinputtensorhidden_logs=self.hidden1(x)hidden_vals=self.hidden2(x)returnself.logits(hidden_logs),self.value(hidden_vals)defaction_value(self,obs):#executescall()underthehoodlogits,value=self.predict(obs)action=self.dist.predict(logits)#asimpleroption,willbecomeclearlaterwhywedon'tuseit#action=tf.random.categorical(logits,1)returnnp.squeeze(action,axis=-1),np.squeeze(value,axis=-1)
然后驗(yàn)證模型是否如預(yù)期工作:
importgymenv=gym.make('CartPole-v0')model=Model(num_actions=env.action_space.n)obs=env.reset()#nofeed_dictortf.Session()neededatallaction,value=model.action_value(obs[None,:])print(action,value)#[1][-0.00145713]
這里需要注意的是:
模型層和執(zhí)行路徑是分別定義的
沒有“輸入”層,模型將接受原始numpy數(shù)組
通過函數(shù)API可以在一個(gè)模型中定義兩個(gè)計(jì)算路徑
模型可以包含一些輔助方法,比如動(dòng)作采樣
在eager模式下,一切都可以從原始numpy數(shù)組中運(yùn)行
Random Agent
現(xiàn)在讓我們轉(zhuǎn)到 A2CAgent 類。首先,讓我們添加一個(gè) test 方法,該方法運(yùn)行完整的episode并返回獎(jiǎng)勵(lì)的總和。
classA2CAgent:def__init__(self,model):self.model=modeldeftest(self,env,render=True):obs,done,ep_reward=env.reset(),False,0whilenotdone:action,_=self.model.action_value(obs[None,:])obs,reward,done,_=env.step(action)ep_reward+=rewardifrender:env.render()returnep_reward
讓我們看看模型在隨機(jī)初始化權(quán)重下的得分:
agent=A2CAgent(model)rewards_sum=agent.test(env)print("%doutof200"%rewards_sum)#18outof200
離最佳狀態(tài)還很遠(yuǎn),接下來(lái)是訓(xùn)練部分!
損失/目標(biāo)函數(shù)
正如我在DRL概述部分中所描述的,agent通過基于某些損失(目標(biāo))函數(shù)的梯度下降來(lái)改進(jìn)其策略。在 actor-critic 中,我們針對(duì)三個(gè)目標(biāo)進(jìn)行訓(xùn)練:利用優(yōu)勢(shì)加權(quán)梯度加上熵最大化來(lái)改進(jìn)策略,以及最小化價(jià)值估計(jì)誤差。
importtensorflow.keras.lossesasklsimporttensorflow.keras.optimizersaskoclassA2CAgent:def__init__(self,model):#hyperparametersforlosstermsself.params={'value':0.5,'entropy':0.0001}self.model=modelself.model.compile(optimizer=ko.RMSprop(lr=0.0007),#defineseparatelossesforpolicylogitsandvalueestimateloss=[self._logits_loss,self._value_loss])deftest(self,env,render=True):#unchangedfromprevioussection...def_value_loss(self,returns,value):#valuelossistypicallyMSEbetweenvalueestimatesandreturnsreturnself.params['value']*kls.mean_squared_error(returns,value)def_logits_loss(self,acts_and_advs,logits):#atricktoinputactionsandadvantagesthroughsameAPIactions,advantages=tf.split(acts_and_advs,2,axis=-1)#polymorphicCElossfunctionthatsupportssparseandweightedoptions#from_logitsargumentensurestransformationintonormalizedprobabilitiescross_entropy=kls.CategoricalCrossentropy(from_logits=True)#policylossisdefinedbypolicygradients,weightedbyadvantages#note:weonlycalculatethelossontheactionswe'veactuallytaken#thusunderthehoodasparseversionofCElosswillbeexecutedactions=tf.cast(actions,tf.int32)policy_loss=cross_entropy(actions,logits,sample_weight=advantages)#entropylosscanbecalculatedviaCEoveritselfentropy_loss=cross_entropy(logits,logits)#heresignsareflippedbecauseoptimizerminimizesreturnpolicy_loss-self.params['entropy']*entropy_loss
我們完成了目標(biāo)函數(shù)!注意代碼非常緊湊:注釋行幾乎比代碼本身還多。
Agent Training Loop
最后,還有訓(xùn)練環(huán)路。它有點(diǎn)長(zhǎng),但相當(dāng)簡(jiǎn)單:收集樣本,計(jì)算回報(bào)和優(yōu)勢(shì),并在其上訓(xùn)練模型。
classA2CAgent:def__init__(self,model):#hyperparametersforlosstermsself.params={'value':0.5,'entropy':0.0001,'gamma':0.99}#unchangedfromprevioussection...deftrain(self,env,batch_sz=32,updates=1000):#storagehelpersforasinglebatchofdataactions=np.empty((batch_sz,),dtype=np.int32)rewards,dones,values=np.empty((3,batch_sz))observations=np.empty((batch_sz,)+env.observation_space.shape)#trainingloop:collectsamples,sendtooptimizer,repeatupdatestimesep_rews=[0.0]next_obs=env.reset()forupdateinrange(updates):forstepinrange(batch_sz):observations[step]=next_obs.copy()actions[step],values[step]=self.model.action_value(next_obs[None,:])next_obs,rewards[step],dones[step],_=env.step(actions[step])ep_rews[-1]+=rewards[step]ifdones[step]:ep_rews.append(0.0)next_obs=env.reset()_,next_value=self.model.action_value(next_obs[None,:])returns,advs=self._returns_advantages(rewards,dones,values,next_value)#atricktoinputactionsandadvantagesthroughsameAPIacts_and_advs=np.concatenate([actions[:,None],advs[:,None]],axis=-1)#performsafulltrainingsteponthecollectedbatch#note:noneedtomessaroundwithgradients,KerasAPIhandlesitlosses=self.model.train_on_batch(observations,[acts_and_advs,returns])returnep_rewsdef_returns_advantages(self,rewards,dones,values,next_value):#next_valueisthebootstrapvalueestimateofafuturestate(thecritic)returns=np.append(np.zeros_like(rewards),next_value,axis=-1)#returnsarecalculatedasdiscountedsumoffuturerewardsfortinreversed(range(rewards.shape[0])):returns[t]=rewards[t]+self.params['gamma']*returns[t+1]*(1-dones[t])returns=returns[:-1]#advantagesarereturns-baseline,valueestimatesinourcaseadvantages=returns-valuesreturnreturns,advantagesdeftest(self,env,render=True):#unchangedfromprevioussection...def_value_loss(self,returns,value):#unchangedfromprevioussection...def_logits_loss(self,acts_and_advs,logits):#unchangedfromprevioussection...
訓(xùn)練&結(jié)果
我們現(xiàn)在已經(jīng)準(zhǔn)備好在CartPole-v0上訓(xùn)練這個(gè)single-worker A2C agent!訓(xùn)練過程應(yīng)該只用幾分鐘。訓(xùn)練結(jié)束后,你應(yīng)該看到一個(gè)智能體成功地實(shí)現(xiàn)了200分的目標(biāo)。
rewards_history=agent.train(env)print("Finishedtraining,testing...")print("%doutof200"%agent.test(env))#200outof200

在源代碼中,我包含了一些額外的幫助程序,可以打印出正在運(yùn)行的episode的獎(jiǎng)勵(lì)和損失,以及rewards_history。

靜態(tài)計(jì)算圖
eager mode效果這么好,你可能會(huì)想知道靜態(tài)圖執(zhí)行是否也可以。當(dāng)然是可以!而且,只需要多加一行代碼就可以啟用靜態(tài)圖執(zhí)行。
withtf.Graph().as_default():print(tf.executing_eagerly())#Falsemodel=Model(num_actions=env.action_space.n)agent=A2CAgent(model)rewards_history=agent.train(env)print("Finishedtraining,testing...")print("%doutof200"%agent.test(env))#200outof200
有一點(diǎn)需要注意的是,在靜態(tài)圖執(zhí)行期間,我們不能只使用 Tensors,這就是為什么我們需要在模型定義期間使用CategoricalDistribution的技巧。
One More Thing…
還記得我說(shuō)過TensorFlow在默認(rèn)情況下以eager 模式運(yùn)行,甚至用一個(gè)代碼片段來(lái)證明它嗎?好吧,我騙了你。
如果你使用Keras API來(lái)構(gòu)建和管理模型,那么它將嘗試在底層將它們編譯為靜態(tài)圖。所以你最終得到的是靜態(tài)計(jì)算圖的性能,它具有eager execution的靈活性。
你可以通過model.run_eager標(biāo)志檢查模型的狀態(tài),還可以通過將此標(biāo)志設(shè)置為True來(lái)強(qiáng)制使用eager mode,盡管大多數(shù)情況下可能不需要這樣做——如果Keras檢測(cè)到?jīng)]有辦法繞過eager mode,它將自動(dòng)退出。
為了說(shuō)明它確實(shí)是作為靜態(tài)圖運(yùn)行的,這里有一個(gè)簡(jiǎn)單的基準(zhǔn)測(cè)試:
#createa100000samplesbatchenv=gym.make('CartPole-v0')obs=np.repeat(env.reset()[None,:],100000,axis=0)
Eager Benchmark
%%timemodel=Model(env.action_space.n)model.run_eagerly=Trueprint("EagerExecution:",tf.executing_eagerly())print("EagerKerasModel:",model.run_eagerly)_=model(obs)########Results#######EagerExecution:TrueEagerKerasModel:TrueCPUtimes:user639ms,sys:736ms,total:1.38s
Static Benchmark
%%timewithtf.Graph().as_default():model=Model(env.action_space.n)print("EagerExecution:",tf.executing_eagerly())print("EagerKerasModel:",model.run_eagerly)_=model.predict(obs)########Results#######EagerExecution:FalseEagerKerasModel:FalseCPUtimes:user793ms,sys:79.7ms,total:873ms
Default Benchmark
%%timemodel=Model(env.action_space.n)print("EagerExecution:",tf.executing_eagerly())print("EagerKerasModel:",model.run_eagerly)_=model.predict(obs)########Results#######EagerExecution:TrueEagerKerasModel:FalseCPUtimes:user994ms,sys:23.1ms,total:1.02s
正如你所看到的,eager模式位于靜態(tài)模式之后,默認(rèn)情況下,模型確實(shí)是靜態(tài)執(zhí)行的。
結(jié)論
希望本文對(duì)理解DRL和即將到來(lái)的TensorFlow 2.0有所幫助。請(qǐng)注意,TensorFlow 2.0仍然只是預(yù)覽版的,一切都有可能發(fā)生變化,如果你對(duì)TensorFlow有什么特別不喜歡(或喜歡:))的地方,請(qǐng)反饋給開發(fā)者。
一個(gè)總被提起的問題是,TensorFlow是否比PyTorch更好?也許是,也許不是。兩者都是很好的庫(kù),所以很難說(shuō)是哪一個(gè)更好。如果你熟悉PyTorch,你可能會(huì)注意到TensorFlow 2.0不僅趕上了它,而且還避免了PyTorch API的一些缺陷。
無(wú)論最后誰(shuí)勝出,對(duì)于開發(fā)者來(lái)說(shuō),這場(chǎng)競(jìng)爭(zhēng)給雙方都帶來(lái)了凈積極的結(jié)果,我很期待看到這些框架未來(lái)會(huì)變成什么樣子。
-
智能體
+關(guān)注
關(guān)注
1文章
476瀏覽量
11604 -
強(qiáng)化學(xué)習(xí)
+關(guān)注
關(guān)注
4文章
270瀏覽量
11967 -
tensorflow
+關(guān)注
關(guān)注
13文章
334瀏覽量
62174
原文標(biāo)題:詳解深度強(qiáng)化學(xué)習(xí)展現(xiàn)TensorFlow 2.0新特性(代碼)
文章出處:【微信號(hào):AI_era,微信公眾號(hào):新智元】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
有效的TensorFlow理解靜態(tài)和動(dòng)態(tài)形狀
TensorFlow是什么
TensorFlow的特點(diǎn)和基本的操作方式
以Go綁定實(shí)例理解TensorFlow
TensorFlow的2.0 版本將來(lái)臨
Keras和TensorFlow究竟哪個(gè)會(huì)更好?
TensorFlow和Keras哪個(gè)更好用?
機(jī)器學(xué)習(xí)框架Tensorflow 2.0的這些新設(shè)計(jì)你了解多少
TensorFlow 2.0馬上要來(lái)了,還不速來(lái)了解下新架構(gòu)?
TensorFlow 2.0最佳實(shí)踐及主要變化
TensorFlow 2.0 將包含許多 API 變更
TensorFlow2.0終于問世,Alpha版可以搶先體驗(yàn)
TensorFlow 2.0 alpha提供即將發(fā)生的變化的預(yù)覽
TensorFlow的11個(gè)使用技巧整理說(shuō)明
更好的理解TensorFlow 2.0的新特性
評(píng)論