用Python和Keras搭建你自己的AlphaZero

原文:

用Python和Keras搭建你自己的AlphaZero - 集智專欄jizhi.im


教會機器通過深度學習和自我博弈學習玩《四子連珠》遊戲(Connect4)。

在本文,我(作者 David Foster——譯者注)會主要講到以下三件事:

  • AlphaZero 邁入人工智慧一大步的兩個原因。
  • 你怎樣可以搭建一個 AlphaZero 一樣的AI玩《四子連珠》遊戲。
  • 你怎樣可以將代碼適用到其它遊戲中。

AlphaGo → AlphaGo Zero → AlphaZero

2016 年 3 月,在 2 百萬人眼前,DeepMind 的 AlphaGo 以 4-1 擊敗了世界圍棋冠軍李世石。一台機器學到了人類頂尖的圍棋策略,這在以前是難以想像的事情。

就其自身而言,這已經是了不起的成就了,然而 2017 年 10 月,DeepMind 又往前邁了一大步。

在其發布的《Mastering the Game of Go without Human Knowledge》(無需人類知識掌握圍棋)中,DeepMind 展示了一種新演算法 AlphaGo Zero,它以 100-0 的戰績擊敗的自己的舊版本 AlphaGo。令人難以置信的是,AlphaGo Zero 完全是通過自我博弈學習,從「白板」開始,逐漸找到了能打敗 AlphaGo 的策略。創建一個這樣的超級人工智慧已經完全不需要任何人類專業知識構成的資料庫進行訓練。

僅僅 48 天后的 2017 年 12 月 5 日,DeepMind 又發表了另一篇論文《Mastering Chess and Shogi by Self-Play with a General Reinforcement Learning Algorithm》(用通用強化學習演算法自我對弈,掌握國際象棋和將棋),顯示 AlphaGo Zero 也能打敗國際象棋世界冠軍 StockFish 和日本將棋冠軍 Elmo。而整個學習過程,從展示給 AlphaGo Zero 這些棋類開始到它成為這兩種棋的世界頂尖高手,只用了不到 24 小時。

在這種情況下,AlphaZero 誕生了——一種無需預先獲得人類專業知識就能迅速掌握某些領域技能的通用演算法。

對於這項成就,有兩個方面很奇妙:

1.AlphaZero 無需任何人類專業知識作為輸入

這一點的重要性,再強調也不為過。這意味著如果有完善的信息(如果自始至終雙方都完全知道下棋狀態),AlphaGo Zero 的根本方法可以用到任何棋類遊戲中,因為除了該種棋類的規則之外,AI 無需預先學習任何專業知識。

這就是為何 DeepMind 在發布初篇 AlphaGo Zero 論文後不到 48 天就能發布打敗國際象棋和將棋人類冠軍的論文。簡單說,所需的改變就只有描述棋類機制的輸入文件,以及調整與神經網路和蒙特卡洛樹搜索相關的高參數。

演算法非常優雅

即便 AlphaZero 使用了超級複雜的演算法,當今世界只有一小部分人能理解,那麼它依然算的上是了不起的成就。然而,它的非凡之處就在於論文中的很多理念實際上遠比之前的版本簡單。其核心思想,就是遵循這些簡單的學習口訣一樣的東西:

  • 從內心先將所有可能會出現的場景過一遍,優先選擇有希望的路徑,同時也思考對手對你的行動最可能做出怎樣的反應,並繼續探索未知情境。
  • 抵達不熟悉的狀態後,評估一下你認為當前情形對自己是否有利,關聯一下前幾步的得分,分析走到當前這一步的心理路徑。
  • 在考慮完將來所有的可能性後,採取探索最多的行動。
  • 在比賽結束時,回溯並評估當時對未來場景出現了哪些誤判,相應地優化對這些場景的理解。

這和你學習下棋的過程是不是很像?當你下了一步壞棋,要麼是因為你誤判了走這步棋的未來情況,要麼你誤判了對手可能會怎麼下,因此沒有考慮到這中可能性。而正是從這兩個方面訓練 AlphaZero 學習下棋。

怎樣搭建你自己的 AlphaZero

本文主要是講解如何搭建AlphaZero,因此假定你已經對AlphaZero的原理有了大致了解。如果不太熟悉的,可預先查閱一下相關資料,可以參考我製作的這篇速查表(medium.com/applied-data)或這篇文章(tim.hibal.org/blog/alph)。

代碼

將 Github 上的代碼庫複製下來

AppliedDataSciencePartners/DeepReinforcementLearninggithub.com圖標

我後面會引用這裡面的代碼。

要開始學習過程,首先在 run.ipynb Jupyter notebook 中運行前兩個面板。一旦它創建了足夠的博弈情景,神經網路就開始訓練了。

再通過自我博弈和訓練,它會越來越擅長在任何位置預測博弈值和下一步棋的動作,從而做出更好的決策,越來越聰明。

現在我們更詳細地看看代碼,並展示一些結果,證明 AI 隨著時間推移越來越強。

注意:這是我自己根據 DeepMind 所發論文對 AlphaZero 的理解,如有不當之處,敬請指正。

《四子連珠》

我們的演算法要學習玩的遊戲是《四子連珠》(Connect4)。雖然它不像圍棋那麼複雜,但是仍然總共有 4,531,985,219,092 個遊戲位置。

遊戲的規則很直接:玩家輪流在任何一欄的頂部放置自己的顏色的棋子。誰最先在垂直、水平或對角線上都放置了同一種顏色,則獲勝。如果全部網格都被填滿,仍然沒有出現同一顏色的棋子出現在同一條線上,則平局。

以下是組成代碼庫的關鍵文件的總結:

game.py

該文件包含《四子連珠》的遊戲規則。

每個方格分配一個從0到41的數字,如圖:

此文件給出了根據給定動作,從一種遊戲狀態轉移至另一種的邏輯。例如,給定空棋盤和 38 號動作,takeAction 方法返回到一個新的遊戲狀態,起始玩家的位置則位於中間列的底部。

你可以用任何符合相同 API 的遊戲文件替換 game.py 文件,原則上演算法將根據你給它的規則通過自我博弈學習遊戲策略。

run.ipynb

它包含了開始學習過程的代碼。它會載入遊戲規則,然後迭代演算法的主循環,其中包含三個階段:

  • 自我博弈
  • 再訓練神經網路
  • 評估神經網路

在這一循環中有兩個 agent:best_player 和 current_player。

其中 best_player 包含了性能最好的神經網路,用於生成自我博弈記憶。Current_player 然後會根據這些記憶再訓練其神經網路,接著與 best_player 進行對弈。如果它贏了, best_player 中的神經網路就會換成 current_player 中的神經網路,循環再次開始。

agent.py

它包含 Agent類(遊戲中的一個玩家)。每個玩家都用自己的神經網路和蒙特卡羅搜索樹進行初始化。

Simulate 方法運行蒙特卡羅樹搜索過程。具體說來,agent 移動至樹的一個葉節點,用其神經網路評估該節點,然後通過樹回填(backfill)該節點的值。

Act 方法多次重複 simulate 方法,以理解從當前位置移動至哪個位置是最有利的。然後它將選定的動作返回給遊戲,以執行該遊戲。

replay 方法使用之前的遊戲記憶再訓練神經網路。

Model.py

該文件包含了 Residual_CNN 類,它定義如何構建神經網路的實例。

用Keras搭建的一個殘留卷積神經網路樣例

其採用 AlphaGo Zero 論文中的神經網路架構的壓縮版本——即一個卷積層,接著是一些殘留層,然後分解成值端(value head)和策略端(policy head)。

卷積過濾器的深度和數量可以在 config 文件中設置。

Keras 程序庫用於搭建神經網路,使用 TensorFlow 後端。

要在神經網路中查看單個卷積過濾和密集連接的層,可在 run.ipynb notebook 中運行以下代碼:

current_player.model.viewLayers()

神經網路中的卷積過濾器

MCTS.py

它包含節點、邊緣和 MCTS 類,它們構成了一個蒙特卡洛搜索樹。

MCTS 類包含前面提到的 moveToLeaf 和 backFill 方法,並且邊緣類的實例存儲每個可能的移動的統計數據。

config.py

這是你設置影響演算法的關鍵參數的地方。

調整這些變數將影響演算法的運行時間、神經網路的準確性和演算法的整體成功。上面的參數產生了一個高質量的《四子連珠》玩家,但是要花很長時間才能完成。為了加快演算法的速度,請嘗試以下參數。

funcs.py

它包含了將兩個 agent 進行匹配的 playMatches 和 playMatchesBetweenVersions 函數。

如果要和你創建的玩家對戰,請運行以下代碼(它也在 run.ipynb notebook 中):

from game import Gamefrom funcs import playMatchesBetweenVersionsimport loggers as lgenv = Game()playMatchesBetweenVersions(env, 1 # the run version number where the computer player is located, -1 # the version number of the first player (-1 for human), 12 # the version number of the second player (-1 for human), 10 # how many games to play, lg.logger_tourney # where to log the game to, 0 # which player to go first - 0 for random)

initialise.py

當你運行該演算法時,所有的模型和內存文件都保存在 run 文件夾中,在根目錄中。

稍後要從這個檢查點重新啟動演算法,將 run 文件夾轉移到 run_archive 文件夾中,將一個運行編號(run number)附加到文件夾名字上。然後,將運行編號、模型版本號和 memory 版本號輸入到 initialise.py 文件中,run_archive 文件夾中相關文件的位置對應。然後從這個檢查點開始,像往常一樣運行該演算法。

memory.py

這是 Memory class 的一個實例,用以存儲之前遊戲的記憶,該演算法會用它們重新訓練 current_player 的神經網路。

loss.py

此文件包含一個自定義損失函數,用以在傳遞到交叉熵損失函數之前對非法移動的預測進行掩碼處理。

settings.py

run和run_archive 文件夾的位置。

logger.py

這個文件包含一個自定義的損失函數,它在傳遞到交叉熵損失函數之前,掩蓋了非法移動的預測。

settings.py

run 和 run_archive 文件夾的位置。

loggers.py

日誌文件被保存到 run 文件夾中的 log 文件夾。要打開日誌記錄,可將該文件中 logger_disabled 變數的值設置為「False」。查看日誌文件將幫助你了解演算法的工作原理,並了解它的「思想」。例如,下面是 logger.mcts 文件中的一個樣例:

同樣來自 logger.tourney 文件的一個樣例,你可以在評估階段看到每個與移動相關的概率:

結果

經過幾天的訓練,小批量迭代次數後得出以下損失圖表:

最上面的線是策略端的誤差(MCTS的交叉熵移動概率與神經網路的輸出相對應)。下面的線是值端的誤差(實際博弈值與神經網路值之間的均方差)。中間的線是兩者的平均值。

很明顯,神經網路在預測每個博弈狀態的價值和可能的下一步動作方面做得越來越好。為了展示這一結果如何變得更加強大,我在17個玩家之間進行了一場聯賽,從首次迭代的神經網路到第 49 次迭代,每對搭檔都對戰了兩次,兩名玩家都有機會先玩。

以下是最終排名:

顯然,後期版本的神經網路優於早期版本,贏得了它們之間的大部分比賽。另外,學習似乎並沒有達到飽和,因為隨著訓練時間增加,玩家變得越來越強大,並且學習的策略越來越複雜。

例如,隨著時間的推移,神經網路所偏愛的一個明確策略就是儘早槍戰中心欄。觀察演算法的第 1 個版本和第 30 個版本之間的差別:

神經網路的第一個版本

神經網路的第三十個版本

這是一個很好的策略,因為很多下棋的線路都需要中間欄——要求盡量不要讓對手利用這一點。而神經網路在沒有任何人類知識輸入的情況下,已經學會了這一點。

學習一種不同的博弈遊戲

在 games 文件夾里有個 game.py 文件,用於一個叫做 Metasquares 的遊戲。這個遊戲是在網格中放置 X 和 O 標記,以嘗試形成不同大小的方塊。方塊越大,玩家分數越高。當網格被填滿時,得分最多的玩家獲勝。

如果你將《四子連珠》的 game.py 文件替換為 Metasquare 的 game.py 文件,那麼我們上面使用的演算法就會學習玩 Metasquares 遊戲。

換言之,通過這種方式,我們搭建的模型可以學習任何一種博弈遊戲。


向你推薦:

一文讀懂CNN如何用於NLP - 集智專欄

邊看邊練的簡明機器學習教程 Part II - 集智專欄

是直是彎?爆照判斷 - 集智專欄

參考資料: medium.com/applied-data


推薦閱讀:

如何將Python和R整合進一個數據分析流程
Python學習筆記
Python · 樸素貝葉斯(三)· GaussianNB
我用到的一個Python Shell
用爬蟲抓取崑崙決所有選手信息並保存為PDF檔案!(淺談搏擊運動數據分析)

TAG:Python | 景略集智 | Keras |