歡迎訪問集智主站:集智,通向智能時代的引擎git
教會機器經過深度學習和自我博弈學習玩《四子連珠》遊戲(Connect4)。github
在本文,我(做者 David Foster——譯者注)會主要講到如下三件事:算法
AlphaGo → AlphaGo Zero → AlphaZero數據庫
2016 年 3 月,在 2 百萬人眼前,DeepMind 的 AlphaGo 以 4-1 擊敗了世界圍棋冠軍李世石。一臺機器學到了人類頂尖的圍棋策略,這在之前是不可思議的事情。後端
就其自身而言,這已是了不得的成就了,然而 2017 年 10 月,DeepMind 又往前邁了一大步。bash
在其發佈的《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 誕生了——一種無需預先得到人類專業知識就能迅速掌握某些領域技能的通用算法。app
對於這項成就,有兩個方面很奇妙:dom
1.AlphaZero 無需任何人類專業知識做爲輸入
這一點的重要性,再強調也不爲過。這意味着若是有完善的信息(若是自始至終雙方都徹底知道下棋狀態),AlphaGo Zero 的根本方法能夠用到任何棋類遊戲中,由於除了該種棋類的規則以外,AI 無需預先學習任何專業知識。
這就是爲什麼 DeepMind 在發佈初篇 AlphaGo Zero 論文後不到 48 天就能發佈戰勝國際象棋和將棋人類冠軍的論文。簡單說,所需的改變就只有描述棋類機制的輸入文件,以及調整與神經網絡和蒙特卡洛樹搜索相關的高參數。
算法很是優雅
即使 AlphaZero 使用了超級複雜的算法,當今世界只有一小部分人能理解,那麼它依然算的上是了不得的成就。然而,它的非凡之處就在於論文中的不少理念實際上遠比以前的版本簡單。其核心思想,就是遵循這些簡單的學習口訣同樣的東西:
這和你學習下棋的過程是否是很像?當你下了一步壞棋,要麼是由於你誤判了走這步棋的將來狀況,要麼你誤判了對手可能會怎麼下,所以沒有考慮到這中可能性。而正是從這兩個方面訓練 AlphaZero 學習下棋。
怎樣搭建你本身的 AlphaZero
本文主要是講解如何搭建AlphaZero,所以假定你已經對AlphaZero的原理有了大體瞭解。若是不太熟悉的,可預先查閱一下相關資料,能夠參考我製做的這篇速查表或這篇文章。
代碼
將 Github 上的代碼庫複製下來
https://github.com/AppliedDataSciencePartners/DeepReinforcementLearning
我後面會引用這裏面的代碼。
要開始學習過程,首先在 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 類,它定義如何構建神經網絡的實例。
其採用 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 Game
from funcs import playMatchesBetweenVersions
import loggers as lg
env = 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 遊戲。
換言之,經過這種方式,咱們搭建的模型能夠學習任何一種博弈遊戲。