還記得 Flappy Bird 麼?這篇文章教你如何用神經網絡破朋友圈紀錄...

2020-11-29 雷鋒網

雷鋒網(公眾號:雷鋒網)按:本文作者楊浩,原文載於作者個人博客,雷鋒網已獲授權。

以下內容來源於一次部門內部的分享,主要針對AI初學者,介紹包括CNN、Deep Q Network以及TensorFlow平臺等內容。由於筆者並非深度學習算法研究者,因此以下更多從應用的角度對整個系統進行介紹,而不會進行詳細的公式推導。

關於Flappy Bird 

Flappy Bird(非官方譯名:笨鳥先飛)是一款2013年鳥飛類遊戲,由越南河內獨立遊戲開發者阮哈東(Dong Nguyen)開發,另一個獨立遊戲開發商GEARS Studios發布。—— 以上內來自《維基百科》

Flappy Bird操作簡單,通過點擊手機屏幕使Bird上升,穿過柱狀障礙物之後得分,碰到則遊戲結束。由於障礙物高低不等,控制Bird上升和下降需要反應快並且靈活,要得到較高的分數並不容易,筆者目前最多得過10分。

本文主要介紹如何通過AI(人工智慧)的方式玩Flappy Bird遊戲,分為以下四個部分內容:

1. Flappy Bird 遊戲展示

2. 模型:卷積神經網絡

3. 算法:Deep Q Network

4. 代碼:TensorFlow實現

  一、Flappy Bird 遊戲展示

在介紹模型、算法前先來直接看下效果,上圖是剛開始訓練的時候,畫面中的小鳥就像無頭蒼蠅一樣亂飛,下圖展示的是在本機(後面會給出配置)訓練超過10小時後(訓練步數超過2000000)的情況,其最好成績已經超過200分,人類玩家已基本不可能超越。

訓練數小於10000步(剛開始訓練)

訓練步數大於2000000步(10小時後)

由於本機配置了 CUDA 以及 cuDNN,採用了 NVIDIA 的顯卡進行並行計算,所以這裡提前貼一下運行時的日誌輸出。

關於CUDA以及cuDNN的配置,其中有一些坑包括:安裝CUDA之後循環登錄,屏幕解析度無法正常調節等等,都是由於NVIDIA驅動安裝的問題,這不是本文要討論的主要內容,讀者可自行Google。

● 加載CUDA運算庫

加載CUDA運算庫

● TensorFlow運行設備 /gpu:0

TensorFlow運行設備/gpu:0

/gpu:0 這是TensorFlow平臺默認的配置方法,表示使用系統中的第一塊顯卡。

本機軟硬體配置:

系統:Ubuntu 16.04

顯卡:NVIDIA GeForce GTX 745 4G

版本:TensorFlow 1.0

軟體包:OpenCV 3.2.0、Pygame、Numpy、…


細心的朋友可能發現,筆者的顯卡配置並不高,GeForce GTX 745,顯存3.94G,可用3.77G(桌面佔用了一部分),屬於入門中的入門。對於專業做深度學習算法的朋友,這個顯卡必然是不夠的。知乎上有帖子教大家怎麼配置更專業的顯卡,有興趣的可以移步。

  二、模型:卷積神經網絡

神經網絡算法是由眾多的神經元可調的連接權值連接而成,具有大規模並行處理、分布式信息存儲、良好的自組織自學習能力等特點。人工神經元與生物神經元結構類似,其結構對比如下圖所示。

生物神經元

人工神經元

人工神經元的輸入(x1,x2...xm)類似於生物神經元的樹突,輸入經過不同的權值(wk1, wk2, ....wkn),加上偏置,經過激活函數得到輸出,最後將輸出傳輸到下一層神經元進行處理。

單神經元輸出函數

激活函數為整個網絡引入了非線性特性,這也是神經網絡相比於回歸等算法擬合能力更強的原因。常用的激活函數包括sigmoid、tanh等,它們的函數表達式如下:

sigmoid函數

tanh雙曲正切函數

這裡可以看出,sigmoid函數的值域是(0,1),tanh函數的值域是(-1,1)。

卷積神經網絡起源於動物的視覺系統,主要包含的技術是:

1. 局部感知域(稀疏連接);

2. 參數共享;

3. 多卷積核;

4. 池化。

● 1. 局部感知域(稀疏連接)

全連接網絡的問題在於:

1. 需要訓練的參數過多,容器導致結果不收斂(梯度消失),且訓練難度極大;

2. 實際上對於某個局部的神經元來講,它更加敏感的是小範圍內的輸入,換句話說,對於較遠的輸入,其相關性很低,權值也就非常小。

人類的視覺系統決定了人在觀察外界的時候,總是從局部到全局。

比如,我們看到一個美女,可能最先觀察到的是美女身上的某些部位(自己體會)。

因此,卷積神經網絡與人類的視覺類似,採用局部感知,低層的神經元只負責感知局部的信息,在向後傳輸的過程中,高層的神經元將局部信息綜合起來得到全局信息。

全連接與局部連接的對比(圖片來自網際網路)

從上圖中可以看出,採用局部連接之後,可以大大的降低訓練參數的量級。

● 2. 參數共享

雖然通過局部感知降低了訓練參數的量級,但整個網絡需要訓練的參數依然很多。

參數共享就是將多個具有相同統計特徵的參數設置為相同,其依據是圖像中一部分的統計特徵與其它部分是一樣的。其實現是通過對圖像進行卷積(卷積神經網絡命名的來源)。

可以理解為,比如從一張圖像中的某個局部(卷積核大小)提取了某種特徵,然後以這種特徵為探測器,應用到整個圖像中,對整個圖像順序進行卷積,得到不同的特徵。

卷積過程(圖片來自網際網路)

每個卷積都是一種特徵提取方式,就像一個篩子,將圖像中符合條件(激活值越大越符合條件)的部分篩選出來,通過這種卷積就進一步降低訓練參數的量級。

● 3. 多卷積核

如上,每個卷積都是一種特徵提取方式,那麼對於整幅圖像來講,單個卷積核提取的特徵肯定是不夠的,那麼對同一幅圖像使用多種卷積核進行特徵提取,就能得到多幅特徵圖(feature map)

不同的卷積核提取不同的特徵(圖片來自網際網路)

多幅特徵圖可以看成是同一張圖像的不同通道,這個概念在後面代碼實現的時候用得上。

● 4. 池化

得到特徵圖之後,可以使用提取到的特徵去訓練分類器,但依然會面臨特徵維度過多,難以計算,並且可能過擬合的問題。從圖像識別的角度來講,圖像可能存在偏移、旋轉等,但圖像的主體卻相同的情況。也就是不同的特徵向量可能對應著相同的結果,那麼池化就是解決這個問題的。

池化過程(圖片來自網際網路)

池化就是將池化核範圍內(比如2*2範圍)的訓練參數採用平均值(平均值池化)或最大值(最大值池化)來進行替代。

終於到了展示模型的時候,下面這幅圖是筆者手畫的(用電腦畫太費時,將就看吧),這幅圖展示了本文中用於訓練遊戲所用的卷積神經網絡模型。

卷積神經網絡模型

圖像的處理過程

1. 初始輸入四幅圖像80×80×4(4代表輸入通道,初始時四幅圖像是完全一致的),經過卷積核8×8×4×32(輸入通道4,輸出通道32),步距為4(每步卷積走4個像素點),得到32幅特徵圖(feature map),大小為20×20;

2. 將20×20的圖像進行池化,池化核為2×2,得到圖像大小為10×10;

3. 再次卷積,卷積核為4×4×32×64,步距為2,得到圖像5×5×64;

4. 再次卷積,卷積核為3×3×64*64,步距為2,得到圖像5×5×64,雖然與上一步得到的圖像規模一致,但再次卷積之後的圖像信息更為抽象,也更接近全局信息;

5. Reshape,即將多維特徵圖轉換為特徵向量,得到1600維的特徵向量;

6. 經過全連接1600×512,得到512維特徵向量;

7. 再次全連接512×2,得到最終的2維向量[0,1]和[1,0],分別代表遊戲屏幕上的是否點擊事件。

可以看出,該模型實現了端到端的學習,輸入的是遊戲屏幕的截圖信息(代碼中經過opencv處理),輸出的是遊戲的動作,即是否點擊屏幕。深度學習的強大在於其數據擬合能力,不需要傳統機器學習中複雜的特徵提取過程,而是依靠模型發現數據內部的關係。

不過這也帶來另一方面的問題,那就是深度學習高度依賴大量的標籤數據,而這些數據獲取成本極高。

  三、算法:Deep Q Network

有了卷積神經網絡模型,那麼怎樣訓練模型?使得模型收斂,從而能夠指導遊戲動作呢?機器學習分為監督學習、非監督學習和強化學習,這裡要介紹的Q Network屬於強化學習(Reinforcement Learning)的範疇。在正式介紹Q Network之前,先簡單說下它的光榮歷史。

2014年Google 4億美金收購DeepMind的橋段,大家可能聽說過。那麼,DeepMind是如何被Google給盯上的呢?最終原因可以歸咎為這篇論文:

Playing Atari with Deep Reinforcement Learning

DeepMind團隊通過強化學習,完成了20多種遊戲,實現了端到端的學習。其用到的算法就是Q Network。2015年,DeepMind團隊在《Nature》上發表了一篇升級版:

Human-level control through deep reinforcement learning

自此,在這類遊戲領域,人已經無法超過機器了。後來又有了AlphaGo,以及Master,當然,這都是後話了。其實本文也屬於上述論文的範疇,只不過基於TensorFlow平臺進行了實現,加入了一些筆者自己的理解而已。

回到正題,Q Network屬於強化學習,那麼先介紹下強化學習。

強化學習模型

這張圖是從UCL的課程中拷出來的,課程連結地址(YouTube):

https://www.youtube.com/watch?v=2pWv7GOvuf0 

強化學習過程有兩個組成部分:

● 智能代理(學習系統)

● 環境

如圖所示,在每步迭代過程中,首先智能代理(學習系統)接收環境的狀態st,然後產生動作at作用於環境,環境接收動作at,並且對其進行評價,反饋給智能代理rt。不斷的循環這個過程,就會產生一個狀態/動作/反饋的序列:(s1, a1, r1, s2, a2, r2.....,sn, an, rn),而這個序列讓我們很自然的想起了:

● 馬爾科夫決策過程

MDP:馬爾科夫決策過程

馬爾科夫決策過程與著名的HMM(隱馬爾科夫模型)相同的是,它們都具有馬爾科夫特性。那麼什麼是馬爾科夫特性呢?簡單來說,就是未來的狀態只取決於當前的狀態,與過去的狀態無關。

HMM(馬爾科夫模型)在語音識別,行為識別等機器學習領域有較為廣泛的應用。條件隨機場模型(Conditional Random Field)則用於自然語言處理。兩大模型是語音識別、自然語言處理領域的基石。

上圖可以用一個很形象的例子來說明。比如你畢業進入了一個公司,你的初始職級是T1(對應圖中的 s1),你在工作上刻苦努力,追求上進(對應圖中的a1),然後領導覺得你不錯,準備給你升職(對應圖中的r1),於是,你升到了T2;你繼續刻苦努力,追求上進......不斷的努力,不斷的升職,最後升到了sn。當然,你也有可能不努力上進,這也是一種動作,換句話說,該動作a也屬於動作集合A,然後得到的反饋r就是沒有升職加薪的機會。

這裡注意下,我們當然希望獲取最多的升職,那麼問題轉換為:如何根據當前狀態s(s屬於狀態集S),從A中選取動作a執行於環境,從而獲取最多的r,即r1 + r2 ……+rn的和最大 ?這裡必須要引入一個數學公式:狀態值函數

狀態值函數模型

公式中有個折合因子γ,其取值範圍為[0,1],當其為0時,表示只考慮當前動作對當前的影響,不考慮對後續步驟的影響,當其為1時,表示當前動作對後續每步都有均等的影響。當然,實際情況通常是當前動作對後續得分有一定的影響,但隨著步數增加,其影響減小。

從公式中可以看出,狀態值函數可以通過迭代的方式來求解。增強學習的目的就是求解馬爾可夫決策過程(MDP)的最優策略。

策略就是如何根據環境選取動作來執行的依據。策略分為穩定的策略和不穩定的策略,穩定的策略在相同的環境下,總是會給出相同的動作,不穩定的策略則反之,這裡我們主要討論穩定的策略。

求解上述狀態函數需要採用動態規劃的方法,而具體到公式,不得不提:

● 貝爾曼方程

貝爾曼方程

其中,π代表上述提到的策略,Q π (s, a)相比於V π (s),引入了動作,被稱作動作值函數。對貝爾曼方程求最優解,就得到了貝爾曼最優性方程

狀態值函數最優解

動作值函數最優解

求解該方程有兩種方法:策略迭代值迭代

● 策略迭代

策略迭代分為兩個步驟:策略評估策略改進,即首先評估策略,得到狀態值函數,其次,改進策略,如果新的策略比之前好,就替代老的策略。

策略迭代

● 值迭代

從上面我們可以看到,策略迭代算法包含了一個策略估計的過程,而策略估計則需要掃描(sweep)所有的狀態若干次,其中巨大的計算量直接影響了策略迭代算法的效率。而值迭代每次只掃描一次,更新過程如下:

值迭代

即在值迭代的第k+1次迭代時,直接將能獲得的最大的Vπ(s)值賦給Vk+1。

● Q-Learning

Q-Learning是根據值迭代的思路來進行學習的。該算法中,Q值更新的方法如下:

Q值更新方法

雖然根據值迭代計算出目標Q值,但是這裡並沒有直接將這個Q值(是估計值)直接賦予新的Q,而是採用漸進的方式類似梯度下降,朝目標邁近一小步,取決於α,這就能夠減少估計誤差造成的影響。類似隨機梯度下降,最後可以收斂到最優的Q值。具體算法如下:

Q-Learning算法

如果沒有接觸過動態規劃的童鞋看上述公式可能有點頭大,下面通過表格來演示下Q值更新的過程,大家就明白了。

Q-Learning算法的過程就是存儲Q值的過程。上表中,橫列為狀態s,縱列為Action a,s和a決定了表中的Q值。

● 第一步:初始化,將表中的Q值全部置0;

● 第二步:根據策略及狀態s,選擇a執行。假定當前狀態為s1,由於初始值都為0,所以任意選取a執行,假定這裡選取了a2執行,得到了reward為1,並且進入了狀態s3。根據Q值更新公式:

Q值更新公式

來更新Q值,這裡我們假設α是1,λ也等於1,也就是每一次都把目標Q值賦給Q。那麼這裡公式變成:

Q值更新公式

所以在這裡,就是

本次Q值更新

那麼對應的s3狀態,最大值是0,所以

Q值

Q表格就變成:

然後置位當前狀態s為s3。

● 第三步:繼續循環操作,進入下一次動作,當前狀態是s3,假設選擇動作a3,然後得到reward為2,狀態變成s1,那麼我們同樣進行更新:

Q值更新

所以Q的表格就變成:

● 第四步: 繼續循環,Q值在試驗的同時反覆更新,直到收斂。

上述表格演示了具有4種狀態/4種行為的系統,然而在實際應用中,以本文講到的Flappy Bird遊戲為例,界面為80*80個像素點,每個像素點的色值有256種可能。那麼實際的狀態總數為256的80*80次方,這是一個很大的數字,直接導致無法通過表格的思路進行計算。

因此,為了實現降維,這裡引入了一個價值函數近似的方法,通過一個函數表近似表達價值函數:

價值函數近似

其中,ω 與 b 分別為參數。看到這裡,終於可以聯繫到前面提到的神經網絡了,上面的表達式不就是神經元的函數嗎?

● Q-network

下面這張圖來自論文《Human-level Control through Deep Reinforcement Learning》,其中詳細介紹了上述將Q值神經網絡化的過程。(感興趣的可以點之前的連結了解原文~)

Q-network

以本文為例,輸入是經過處理的4個連續的80x80圖像,然後經過三個卷積層,一個池化層,兩個全連接層,最後輸出包含每一個動作Q值的向量。

現在已經將Q-learning神經網絡化為Q-network了,接下來的問題是如何訓練這個神經網絡。神經網絡訓練的過程其實就是一個最優化方程求解的過程,定義系統的損失函數,然後讓損失函數最小化的過程。

訓練過程依賴於上述提到的DQN算法,以目標Q值作為標籤,因此,損失函數可以定義為:

DQN損失函數(來源於論文)

上面公式是s',a'即下一個狀態和動作。確定了損失函數,確定了獲取樣本的方式,DQN的整個算法也就成型了!

DQN算法(來源於論文)

值得注意的是這裡的D—Experience Replay,也就是經驗池,就是如何存儲樣本及採樣的問題。


由於玩Flappy Bird遊戲,採集的樣本是一個時間序列,樣本之間具有連續性,如果每次得到樣本就更新Q值,受樣本分布影響,效果會不好。因此,一個很直接的想法就是把樣本先存起來,然後隨機採樣如何?這就是Experience Replay的思想。

算法實現上,先反覆實驗,並且將實驗數據存儲在D中;存儲到一定程度,就從中隨機抽取數據,對損失函數進行梯度下降。

  四、代碼:TensorFlow實現

終於到了看代碼的時候。首先申明下,當筆者從Deep Mind的論文入手,試圖用TensorFlow實現對Flappy Bird遊戲進行實現時,發現github已有大神完成demo。思路相同,所以直接以公開代碼為例進行分析說明了。

如有源碼需要,請移步github:Using Deep Q-Network to Learn How To Play Flappy Bird。

代碼從結構上來講,主要分為以下幾部分:

● GameState遊戲類,frame_step方法控制移動

● CNN模型構建

● OpenCV-Python圖像預處理方法

● 模型訓練過程

1. GameState遊戲類及frame_step方法

通過Python實現遊戲必然要用pygame庫,其包含時鐘、基本的顯示控制、各種遊戲控制項、觸發事件等,對此有興趣的,可以詳細了解pygame。frame_step方法的入參為shape為 (2,) 的ndarray,值域: [1,0]:什麼都不做; [0,1]:提升Bird。來看下代碼實現:

if input_actions[1] == 1:

    if self.playery > -2 * PLAYER_HEIGHT:

        self.playerVelY = self.playerFlapAcc

        self.playerFlapped = True

        # SOUNDS['wing'].play()

後續操作包括檢查得分、設置界面、檢查是否碰撞等,這裡不再詳細展開。

frame_step方法的返回值是:

return image_data, reward, terminal

分別表示界面圖像數據,得分以及是否結束遊戲。對應前面強化學習模型,界面圖像數據表示環境狀態 s,得分表示環境給予學習系統的反饋 r。

2. CNN模型構建

該Demo中包含三個卷積層,一個池化層,兩個全連接層,最後輸出包含每一個動作Q值的向量。因此,首先定義權重、偏置、卷積和池化函數:

# 權重

def weight_variable(shape):

    initial = tf.truncated_normal(shape, stddev=0.01)

    return tf.Variable(initial)

# 偏置

def bias_variable(shape):

    initial = tf.constant(0.01, shape=shape)

    return tf.Variable(initial)

# 卷積

def conv2d(x, W, stride):

    return tf.nn.conv2d(x, W, strides=[1, stride, stride, 1], padding="SAME")

# 池化

def max_pool_2x2(x):

    return tf.nn.max_pool(x, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")

然後,通過上述函數構建卷積神經網絡模型(對代碼中參數不解的,可直接往前翻,看上面那張手畫的圖)。

def createNetwork():

    # 第一層卷積

    W_conv1 = weight_variable([8, 8, 4, 32])

    b_conv1 = bias_variable([32])

    # 第二層卷積

    W_conv2 = weight_variable([4, 4, 32, 64])

    b_conv2 = bias_variable([64])

    # 第三層卷積

    W_conv3 = weight_variable([3, 3, 64, 64])

    b_conv3 = bias_variable([64])

    # 第一層全連接

    W_fc1 = weight_variable([1600, 512])

    b_fc1 = bias_variable([512])

    # 第二層全連接

    W_fc2 = weight_variable([512, ACTIONS])

    b_fc2 = bias_variable([ACTIONS])


    # 輸入層

    s = tf.placeholder("float", [None, 80, 80, 4])


    # 第一層隱藏層+池化層

    h_conv1 = tf.nn.relu(conv2d(s, W_conv1, 4) + b_conv1)

    h_pool1 = max_pool_2x2(h_conv1)

    # 第二層隱藏層(這裡只用了一層池化層)

    h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2, 2) + b_conv2)

    # h_pool2 = max_pool_2x2(h_conv2)

    # 第三層隱藏層

    h_conv3 = tf.nn.relu(conv2d(h_conv2, W_conv3, 1) + b_conv3)

    # h_pool3 = max_pool_2x2(h_conv3)

    # Reshape

    # h_pool3_flat = tf.reshape(h_pool3, [-1, 256])

    h_conv3_flat = tf.reshape(h_conv3, [-1, 1600])

    # 全連接層

    h_fc1 = tf.nn.relu(tf.matmul(h_conv3_flat, W_fc1) + b_fc1)

    # 輸出層

    # readout layer

    readout = tf.matmul(h_fc1, W_fc2) + b_fc2


    return s, readout, h_fc1

3. OpenCV-Python圖像預處理方法

在Ubuntu中安裝opencv的步驟比較麻煩,當時也踩了不少坑,各種Google解決。建議安裝opencv3。

這部分主要對frame_step方法返回的數據進行了灰度化和二值化,也就是最基本的圖像預處理方法。

x_t, r_0, terminal = game_state.frame_step(do_nothing)

# 首先將圖像轉換為80*80,然後進行灰度化

x_t = cv2.cvtColor(cv2.resize(x_t, (80, 80)), cv2.COLOR_BGR2GRAY)

# 對灰度圖像二值化

ret, x_t = cv2.threshold(x_t, 1, 255, cv2.THRESH_BINARY)

# 四通道輸入圖像

s_t = np.stack((x_t, x_t, x_t, x_t), axis=2)

4. DQN訓練過程

這是代碼部分要講的重點,也是上述Q-learning算法的代碼化。

i. 在進入訓練之前,首先創建一些變量:

# define the cost function

a = tf.placeholder("float", [None, ACTIONS])

y = tf.placeholder("float", [None])

readout_action = tf.reduce_sum(tf.multiply(readout, a), axis=1)

cost = tf.reduce_mean(tf.square(y - readout_action))

train_step = tf.train.AdamOptimizer(1e-6).minimize(cost)


# open up a game state to communicate with emulator

game_state = game.GameState()


# store the previous observations in replay memory

D = deque()

在TensorFlow中,通常有三種讀取數據的方式:Feeding、Reading from files和Preloaded data。Feeding是最常用也最有效的方法。即在模型(Graph)構建之前,先使用placeholder進行佔位,但此時並沒有訓練數據,訓練是通過feed_dict傳入數據。

這裡的a表示輸出的動作,即強化學習模型中的Action,y表示標籤值,readout_action表示模型輸出與a相乘後,在一維求和,損失函數對標籤值與輸出值的差進行平方,train_step表示對損失函數進行Adam優化。

賦值的過程為:

# perform gradient step

train_step.run(feed_dict={

    y: y_batch,

    a: a_batch,

    s: s_j_batch}

)

ii. 創建遊戲及經驗池 D

# open up a game state to communicate with emulator

game_state = game.GameState()


# store the previous observations in replay memory

D = deque()

經驗池 D採用了隊列的數據結構,是TensorFlow中最基礎的數據結構,可以通過dequeue()和enqueue([y])方法進行取出和壓入數據。經驗池 D用來存儲實驗過程中的數據,後面的訓練過程會從中隨機取出一定量的batch進行訓練。


變量創建完成之後,需要調用TensorFlow系統方法tf.global_variables_initializer()添加一個操作實現變量初始化。運行時機是在模型構建完成,Session建立之初。比如:

# Create two variables.

weights = tf.Variable(tf.random_normal([784, 200], stddev=0.35),

                      name="weights")

biases = tf.Variable(tf.zeros([200]), name="biases")

...

# Add an op to initialize the variables.

init_op = tf.global_variables_initializer()


# Later, when launching the model

with tf.Session() as sess:

  # Run the init operation.

  sess.run(init_op)

  ...

  # Use the model

  ...

iii. 參數保存及加載

採用TensorFlow訓練模型,需要將訓練得到的參數進行保存,不然一關機,就一夜回到解放前了。TensorFlow採用Saver來保存。一般在Session()建立之前,通過tf.train.Saver()獲取Saver實例。

saver = tf.train.Saver()

變量的恢復使用saver的restore方法:

# Create some variables.

v1 = tf.Variable(..., name="v1")

v2 = tf.Variable(..., name="v2")

...

# Add ops to save and restore all the variables.

saver = tf.train.Saver()


# Later, launch the model, use the saver to restore variables from disk, and

# do some work with the model.

with tf.Session() as sess:

  # Restore variables from disk.

  saver.restore(sess, "/tmp/model.ckpt")

  print("Model restored.")

  # Do some work with the model

  ...

在該Demo訓練時,也採用了Saver進行參數保存。

# saving and loading networks

saver = tf.train.Saver()

checkpoint = tf.train.get_checkpoint_state("saved_networks")

if checkpoint and checkpoint.model_checkpoint_path:

    saver.restore(sess, checkpoint.model_checkpoint_path)

    print("Successfully loaded:", checkpoint.model_checkpoint_path)

else:

    print("Could not find old network weights")

首先加載CheckPointState文件,然後採用saver.restore對已存在參數進行恢復。

在該Demo中,每隔10000步,就對參數進行保存:

# save progress every 10000 iterations

if t % 10000 == 0:

    saver.save(sess, 'saved_networks/' + GAME + '-dqn', global_step=t)

iv. 實驗及樣本存儲

首先,根據ε 概率選擇一個Action。

# choose an action epsilon greedily

readout_t = readout.eval(feed_dict={s: [s_t]})[0]

a_t = np.zeros([ACTIONS])

action_index = 0

if t % FRAME_PER_ACTION == 0:

    if random.random() <= epsilon:

        print("----------Random Action----------")

        action_index = random.randrange(ACTIONS)

        a_t[random.randrange(ACTIONS)] = 1

    else:

        action_index = np.argmax(readout_t)

        a_t[action_index] = 1

else:

    a_t[0] = 1  # do nothing

這裡,readout_t是訓練數據為之前提到的四通道圖像的模型輸出。a_t是根據ε 概率選擇的Action。

其次,執行選擇的動作,並保存返回的狀態、得分。

# run the selected action and observe next state and reward

x_t1_colored, r_t, terminal = game_state.frame_step(a_t)

x_t1 = cv2.cvtColor(cv2.resize(x_t1_colored, (80, 80)), cv2.COLOR_BGR2GRAY)

ret, x_t1 = cv2.threshold(x_t1, 1, 255, cv2.THRESH_BINARY)

x_t1 = np.reshape(x_t1, (80, 80, 1))

# s_t1 = np.append(x_t1, s_t[:,:,1:], axis = 2)

s_t1 = np.append(x_t1, s_t[:, :, :3], axis=2)


# store the transition in D

D.append((s_t, a_t, r_t, s_t1, terminal))

經驗池D保存的是一個馬爾科夫序列。(s_t, a_t, r_t, s_t1, terminal)分別表示t時的狀態s_t,執行的動作a_t,得到的反饋r_t,以及得到的下一步的狀態s_t1和遊戲是否結束的標誌terminal。

在下一訓練過程中,更新當前狀態及步數:

# update the old values

s_t = s_t1

t += 1

重複上述過程,實現反覆實驗及樣本存儲。

v. 通過梯度下降進行模型訓練

在實驗一段時間後,經驗池D中已經保存了一些樣本數據後,就可以從這些樣本數據中隨機抽樣,進行模型訓練了。這裡設置樣本數為OBSERVE = 100000.。隨機抽樣的樣本數為BATCH = 32。

if t > OBSERVE:

    # sample a minibatch to train on

    minibatch = random.sample(D, BATCH)


    # get the batch variables

    s_j_batch = [d[0] for d in minibatch]

    a_batch = [d[1] for d in minibatch]

    r_batch = [d[2] for d in minibatch]

    s_j1_batch = [d[3] for d in minibatch]


    y_batch = []

    readout_j1_batch = readout.eval(feed_dict={s: s_j1_batch})

    for i in range(0, len(minibatch)):

        terminal = minibatch[i][4]

        # if terminal, only equals reward

        if terminal:

            y_batch.append(r_batch[i])

        else:

            y_batch.append(r_batch[i] + GAMMA * np.max(readout_j1_batch[i]))


    # perform gradient step

    train_step.run(feed_dict={

        y: y_batch,

        a: a_batch,

        s: s_j_batch}

    )

s_j_batch、a_batch、r_batch、s_j1_batch是從經驗池D中提取到的馬爾科夫序列(Java童鞋羨慕Python的列表推導式啊),y_batch為標籤值,若遊戲結束,則不存在下一步中狀態對應的Q值(回憶Q值更新過程),直接添加r_batch,若未結束,則用折合因子(0.99)和下一步中狀態的最大Q值的乘積,添加至y_batch。

最後,執行梯度下降訓練,train_step的入參是s_j_batch、a_batch和y_batch。差不多經過2000000步(在本機上大概10個小時)訓練之後,就能達到本文開頭動圖中的效果啦。

以上。

雷鋒網相關閱讀:

用深度學習快速人臉建模

圖像風格遷移 (Neural Style) 簡史

雷鋒網版權文章,未經授權禁止轉載。詳情見轉載須知。

相關焦點

  • 一篇文章教你用11行Python代碼實現神經網絡
    聲明:本文是根據英文教程 (用 11 行 Python 代碼實現的神經網絡)學習總結而來,關於更詳細的神經網絡的介紹可以參考我的另一篇博客:。A Neural Network in 11 lines of Python從感知機到人工神經網絡如果你讀懂了下面的文章,你會對神經網絡有更深刻的認識,有任何問題,請多指教。
  • 從零開始:教你如何訓練神經網絡
    原標題:從零開始:教你如何訓練神經網絡 選自TowardsDataScience 作者:Vitaly此外,本系列將在後面介紹 Adam 和遺傳算法等其它重要的神經網絡訓練方法。 I. 簡介 本文是作者關於如何「訓練」神經網絡的一部分經驗與見解,處理神經網絡的基礎概念外,這篇文章還描述了梯度下降(GD)及其部分變體。
  • 如何用張量分解加速深層神經網絡?(附代碼)
    Tensorly的作者也寫了於Tensor的基礎內容非常棒的notebook。這幫助我很好的開始學習這塊內容,建議你閱讀一下這些內容。加上裁剪(pruning),張量分解是加快現有深度神經網絡的實用工具,我希望這篇文章能讓這些內容更加容易理解。這些方法需要將一個層分解成幾個更小的層。儘管在分解後會有更多的層,但是浮點運算次數和權重的總數會變小。
  • 大腦網絡的朋友圈三定律
    這些細胞形態各異,通過神經纖維和神經突觸,構成了一張複雜而精細的網,網中隱藏著一個個「朋友圈」,分別負責視覺、聽覺、觸覺、運動、記憶、語言等重要腦功能。顯然這張網不是雜亂無章的,我們的基因和後天經歷都是這張網的「架構師」,而我們每時每刻的腦活動也在不斷改變這些朋友圈內外的連接關係。我們用最快速最精準的的觀測手段,發現這個腦網絡的朋友圈遵循簡單的三定律。
  • 人工智慧神經網絡你知道是什麼嗎
    大家現在感興趣的應該是——如何實現人工智慧? 從1956年夏季首次提出「人工智慧」這一術語開始,科學家們嘗試了各種方法來實現它。這些方法包括專家系統,決策樹、歸納邏輯、聚類等等,但這些都是假智能。直到人工神經網絡技術的出現,才讓機器擁有了「真智能」。 為什麼說之前的方法都是假智能呢?
  • 看懂這篇指南,包你掌握神經網絡的「黑匣子」
    全文共4327字,預計學習時長20分鐘或更長「人類的神經網絡是如何運行的?」這個問題讓很多數據科學家感到困惑。解釋某個簡單神經網絡的工作機制非常容易,但是當某個計算機視覺項目中的層數增加1000倍時,該怎麼辦呢?終端用戶想要了解模型是如何得到最終結果時,僅用紙和筆來解釋深度神經網絡的工作機制是行不通的。
  • 你的神經網絡不work? 這37個原因總有一款適合你!
    沒有一點點防備,就在剛才,突然提示:全部預測為零,一點有用的信息都沒有!「到底哪裡出問題了?」 ——我自言自語,很是鬱悶。「該如何檢查神經網絡模型輸出的信息是否有用(例如,預測所有輸出的平均值,還是看看準確度是不是很糟糕)」?
  • 如何用Python和深度神經網絡識別圖像?
    因此我們需要用匯總採樣的方式模糊某個特徵的位置,將其從「某個具體的點」,擴展成「某個區域」。如果這樣說,讓你覺得不夠直觀,請參考下面這張動圖。一個有用的規律是,隨著層數不斷向右推進,一般結果圖像(其實正規地說,應該叫做矩陣)會變得越來越小,但是層數會變得越來越多。只有這樣,我們才能把圖片中的規律信息抽取出來,並且儘量掌握足夠多的模式。如果你還是覺得不過癮,請訪問這個網站。它為你生動解析了卷積神經網絡中,各個層次上到底發生了什麼。
  • 神經網絡如何完成表徵?
    假設你了解前向和後向傳播的一點基礎,其旨在藉助梯度和網絡中的錯誤傳播來近似函數。讓我們通過另一種視覺解釋來理解神經網絡的近似能力。其中涉及基礎數學和圖形分析。 在數學上,我們將研究給定神經網絡的表徵能力,以便提供近似的函數。表徵能力與神經網絡的能力相關,神經網絡會為特定實例分配適當標籤並為該類創建明確定義的準確決策邊界。
  • AI也會犯錯:如何欺騙神經網絡看見一些不存在的東西?
    而在Facebook、Google和微軟這類網際網路龍頭企業內部,這種趨勢早已變成現實。馬克·扎克伯格和他的公司在世界最受歡迎的社交網絡上用數百萬的圖片訓練神經網絡去識別人臉。Google使用大量的口語詞彙訓練神經網絡去識別安卓手機的語言指令。在未來,我們將創造智慧機器人和無人駕駛汽車。
  • 2015刷屏江西的那些網絡熱詞 你還記得幾個
    徒勞感嘆並沒有什麼用,用一個矯情的話說:時光的流逝本身並沒有意義,所有的意義都是你賦予它的!   過去的一年,你要賦予它什麼意義?你曾經用過哪些詞語記載過它?頭條君整理了一批關鍵詞,讓我們一起跟著這些詞語來看下那些年,我們刷過的屏......
  • 如何刷朋友圈不交「智商稅」?——論微信朋友圈的正確打開方式
    新華社北京4月12日新媒體專電 題:如何刷朋友圈不交「智商稅」?——論微信朋友圈的正確打開方式    新華社「中國網事」記者張墨成 吳慧珺 張玉潔    近日,一篇題為《北大博士:退朋友圈保智商》的文章「刷屏」微信朋友圈。
  • 如果你還相信《xx教你月入5萬》,那你真的需要讀一下這篇文章
    而只要人類獲得知識的途徑沒有根本性改變,比如通過植入記憶晶片或者吃藥,仍然只能通過艱苦的重複訓練在大腦神經元之間建立固定的反應。那麼,獲取知識的永遠只會是少部分人,正如考上清華北大的永遠是一小部分人。這意味著知識付費的商業模式要面臨大量的失望與抱怨,差評率很高。
  • 如果看了這篇文章你還不懂傅立葉變換,那就過來掐死我吧(下)
    上一篇文章發出來之後,為了掐死我,大家真是很下工夫啊,有拿給姐姐看的,有拿給妹妹看的,還有拿給女朋友看的,就是為了聽到一句「完全看不懂啊」。幸虧我留了個心眼,不然就真的像標題配圖那樣了。我的文章題目是,如果看了這篇文章你「還」不懂就過來掐死我,潛臺詞就是在你學了,但是沒學明白的情況下看了還是不懂,才過來掐死我。
  • 代碼詳解:使用NumPy,教你9步從頭搭建神經網絡
    Photo by Alina Grubnyak on Unsplash如果你是個對神經網絡有所了解的初級數據科學家,或是個對深度學習略有耳聞的機器學習愛好者,一定要讀一讀這篇文章。本文介紹了使用NumPy從頭搭建神經網絡的9個步驟,即從數據預處理到反向傳播這一「必經之路」。對機器學習、人工神經網絡、Python語法和編程邏輯有些基本理解最好,(但這也不是必需條件,你可以邊讀邊學)。1. 初始化導入NumPy。
  • 手把手教你用PyTorch實現圖像分類器(第一部分)
    當我接近完成的時候,我決定與大家分享一些在未來對他人有益的建議和見解。通過3篇短文,介紹如何實現圖像分類器的概念基礎——這是一種能夠理解圖像內容的算法。本文的目標不是提供手把手的指導,而是幫助理解整個過程。如果你正在考慮學習機器學習或人工智慧,你將不得不做類似的項目,並理解本系列文章中介紹的概念。
  • 帶你讀懂神經網絡
    因此,神經網絡的參數與網絡產生的誤差有關,當參數變化時,網絡產生的誤差也隨之變化。使用一種叫做梯度下降法的優化算法來改變參數,這種算法對於尋找函數的最小值很有用。我們正在尋求最小化的誤差,這也被稱為損失函數或目標函數。那麼剛剛做的這些有什麼意義呢?這和神經網絡有什麼關係?
  • 看了這篇文章,了解深度卷積神經網絡在目標檢測中的進展
    一個圖形中可以得到大約 2000 個不同大小、不同類別的候選區域,他們需要被變換到同一個尺寸以適應 CNN 所處理的圖像大小(227x227)。該文章中使用的 CNN 結構來自 AlexNet, 已經在 ImageNet 數據集上的 1000 個類別的分類任務中訓練過,再通過參數微調使該網絡結構適應該文章中的 21 個類別的分類任務。
  • 如何用這幾款人工神經網絡晶片打造機械姬
    此模型沿用至今,並且直接影響著這一領域研究的進展。 (心理學家W·Mcculloch和數理邏輯學家W·Pitts)1945年馮·諾依曼領導的設計小組試製成功存儲程序式電子計算機,標誌著電子計算機時代的開始。1948年,他在研究工作中比較了人腦結構與存儲程序式計算機的根本區別,提出了以簡單神經元構成的再生自動機網絡結構。