在2016年3月,Deepmind研發的AlphaGo以4:1的成績,擊敗了曾榮獲18次世界冠軍的圍棋選手,李世石(Lee Sedol)。超過2億觀眾見證了這一歷史時刻。一臺機器已經學會了一種超越人類的圍棋策略。這在以前被認為是一項不可能完成的任務,或者至少需要十年之功。
AlphaGo與李世石的第3場比賽
這已是一項了不起的成就。然而,在2017年10月18日,DeepMind又再次取得了突破。
論文《無需人類知識就能稱霸圍棋》(Mastering the Game of Go without Human Knowledge),揭示了一種新的演算法——AlphaGo Zero,它以100:0的驚人成績打敗了AlphaGo。更令人難以置信的是,它從零開始,透過自我博弈,逐漸學會了能打敗自己之前的策略。至此,開發一個超級AI不再需要依賴人類專家的遊戲資料庫了。
僅48天后的2017年12月5日,DeepMind又釋出了另一篇論文《透過一種通用的強化學習演算法稱霸國際象棋和日本象棋》(Mastering Chess and Shogi by Self-Play with a General Reinforcement Learning Algorithm),它展示了AlphaGo Zero如何能夠學會國際象棋(StockFish和Elmo)和象棋。整個學習過程,從第一次參與遊戲到成為世界上最厲害的計算機程式,只用了24小時。
就這樣,AlphaZero華麗麗地誕生了——它無需儲備任何人類棋譜,就可以以通用演算法完成快速自我升級。
關於這個成就,有兩點最讓人稱奇:
AlphaZero對人類遊戲經驗根本就不需要
這點的重要性怎麼說都不過分。也就是說,對於任何有充分資訊的遊戲(對陣雙方對遊戲狀態都全程掌握),AlphaGo Zero的方法論都可以得到完美應用!因為除了遊戲規則之外,人類任何遊戲經驗值都是不需要的。
AlphaGo Zero的基礎方法可以應用於任何具有完美資訊的遊戲(遊戲狀態在任何時候,雙方玩家都完全知道的),因為在遊戲規則之外,不需要事先的專家知識。
這就是DeepMind能在發表AlphaGo Zero論文48天后,馬上就能發表第二篇論文。毫不誇張地說,所需要改變的僅僅是新遊戲規則,及與神經網路和蒙特卡羅樹搜尋相關的超引數。
這個演算法的優雅程度秒殺眾生
即便AlphaZero使用的是世界上只有極少數人能夠看懂的超複雜演算法,它仍然是項了不起的成就。同它相比,之前的演算法可謂不復雜不成活,這才是它真正的魅力。究其核心,無非是以下極簡而美的學習邏輯:
腦補各種場景,挑能贏的路走,想想別人會怎麼應對,並不斷探索未知。
在思考未來可能的情景時,優先考慮有前途的路徑,同時考慮其他人最有可能如何對你的行動作出反應,並繼續探索未知。
遇到不熟悉的狀況,評估它的利害程度,把它同之前的各種讓你走到今天這一步的場景作比較。
窮盡你對未來的想象,用你試過最多的招數來應對。
在你考慮了未來的可能性之後,採取你已經探索過的行動。
遊戲結束時,回頭看看在哪裡犯過錯,然後洗心革面、更新認知。
在遊戲結束時,回過頭來評估你在哪裡錯誤地判斷了未來的位置,並相應地更新你的理解。
這聽起來是不是很像你學玩遊戲的方式? 當做錯一個動作時,要麼是因為你誤判了這個動作會帶來的結果,要麼是你誤判了對手可能會採取的行動。這兩點正是AlphaZero學會如何玩遊戲的法門。
如何構建自己的AlphaZero
首先,我們需要學習和理解AlphaGo Zero的原理。我之前寫過一篇AlphaGo Zero的知識點速查手冊可供參考:
https://medium.com/applied-data-science/alphago-zero-explained-in-one-diagram-365f5abf67e0
Tim Wheeler的部落格中一篇文章也講的很詳細:
http://tim.hibal.org/blog/alpha-zero-how-and-why-it-works/
程式碼
基於下面這個程式碼庫進行講解:
https://github.com/AppliedDataSciencePartners/DeepReinforcementLearning
從執行Jupyter notebook中run.ipynb的前兩個panel開始。一旦它完成了遊戲的足夠回合,那麼神經網路將開始訓練。透過隨後的自我對弈和訓練,它將逐漸在預測勝率和下一步行動上做得越來越好,從而做出更好的決策。
現在,我們需要更詳細地看看面前的程式碼,並且展示下AI是怎樣隨著時間的增加變得越來越厲害的。
四子連珠(Connect4)
我們的演算法將要學習如何玩這個遊戲。雖然不如圍棋那樣複雜,但也有4531985219092種遊戲走位。
四子連珠
遊戲規則很簡單。玩家輪流在任何一欄的頂部佈置自己的顏色。最先在垂直、水平或對角線上放置一排同一種顏色棋子的玩家獲勝,如果這種情況沒有出現,那遊戲就是平局。
下面是組成程式碼庫的關鍵檔案:
game.py——這個檔案包含四子連珠的遊戲規則
每個正方形都被分配了一個從0到41的數字,如下圖所示:
game.py檔案給出了從一種遊戲狀態到另一種狀態的邏輯,並且給出了一個選擇的動作。比如,考慮到empty board和38號動作,takeAction方法返回到一個新的遊戲狀態,也就是底部一行的中心位置。
你可以將game.py檔案用任何符合相同API和演算法的遊戲檔案替換掉,根據你給它的規則,透過自我對弈的方法學習。
run.ipynb——這個檔案包含開啟學習過程的程式碼
它透過演算法中的主要環節載入遊戲規則,並且由三個階段組成:
1、自我對弈
2、重新訓練神經網路
3、評估神經網路
有兩個智慧體也參與到這個環節中,他們分別為best_player和current_player。
best_player包含執行最佳的神經網路,並且可以用於生成自我對弈的記憶。然後,current_player在這些記憶上重新訓練它的神經網路,然後再與best_player對弈。如果它贏了,best_player內部的神經網路被轉換為current_player內部的神經網路,然後迴圈再次啟動。
agent.Py——這個檔案包含遊戲中的一個玩家Agent class
在遊戲中,每個玩家都是用自己的神經網路和蒙特卡羅搜尋樹進行初始化的。
我們需要用模擬的辦法執行蒙特卡羅樹搜尋過程。具體地說,智慧體移動到樹的葉節點,用它的神經網路對節點進行評估,然後透過樹將節點的值返回。
之後,我們還需要用act method多次重複模擬,讓智慧體理解從當前位置出發的最有利的移動。然後它將最終選擇的動作返回到遊戲中,以執行動作。
最後,replay method利用以前遊戲的記憶,重新訓練神經網路。
model.py——這個檔案包括residual_cnn類,它定義瞭如何建立神經網路的例項
用Keras搭建殘差卷積網路示例
它採用的是AlphaGoZero論文中濃縮版的神經網路結構——即一個卷積層,接著是許多剩餘層,然後分成一個數值和指揮中樞。
可以在config檔案中指定卷積篩選器的深度和數量。
Keras庫是用來與後臺的tensorflow建立網路。
檢視個人的卷積濾波器和濃密連線層的神經網路,在run.ipynb筆記本執行以下程式碼:
current_player.model.viewLayers()
神經網路中的卷積核
MCTS.py——這個檔案包含節點(Node),邊(Edge)和MCTS類,構成了蒙特卡洛樹搜尋
MCTS類包含了前文提到的 moveToLeaf 和backFill 方法,以及Edge類的例項儲存有關每個潛在移動的統計資訊。
config.py——這是你設定影響演算法的關鍵引數的地方
調整這些變數會影響執行時間,神經網路的準確性和整體演算法的成功。以上引數產生一個高品質的四子連珠選手,但要花很長時間才能做到。為了加快演算法的速度,請嘗試以下引數。
funcs.py——包含可以在兩個智慧體之間進行比賽的playMatches和playMatchesBetweenVersions函式
如果你想挑戰之前建立的智慧演算法,可以執行下面的程式碼(在run.ipynb筆記本)
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——當你執行該演算法,所有的模型和儲存檔案儲存在 runfolder的根目錄下
稍後要從此檢查點重新執行演算法,請將執行資料夾傳輸到run_archive資料夾,並將執行編號附加到資料夾名稱。然後,將執行編號,型號版本號和記憶體版本號輸入到initialise.py檔案中,對應於run_archive資料夾中相關檔案的位置。像往常一樣執行演算法,然後從這個檢查點開始。
memory.py
Memory類的一個例項儲存以前遊戲的記憶,該演算法用於重新訓練current_player的神經網路。
loss.py
該檔案包含一個自定義損失函式,在傳遞到交叉熵損失函式之前,遮蔽了來自非法移動的預測。
settings.py
run和run_archive資料夾的位置。
loggers.py
日誌檔案儲存到執行資料夾內的日誌資料夾中。
要開啟日誌記錄,請在此檔案中將logger_disabled變數的值設定為False。
檢視日誌檔案將幫助你瞭解該演算法的工作原理,並在其“頭腦”中檢視。 例如,下面是logger.mcts檔案中的示例。
logger.mcts檔案的輸出
同樣從logger.tourney檔案,你可以在評估階段看到每個移動的機率:
logger.tourney檔案的輸出
訓練出的結果讓人驚喜
透過幾天的訓練,得到以下小批次迭代次數與損失的關係圖:
小批次迭代次數與損失的關係圖
最上面的線是策略頭中的誤差(MCTS移動機率的交叉熵,相對於神經網路的輸出)。底部的線是價值頭(實際遊戲數值和神經網路預測值之間的均方誤差)。中間的線是兩者的平均值。
顯然,神經網路在預測每個遊戲狀態的值以及可能的下一步移動方面正在變得更好。為了說明這個結果如何變得越來越強大,我讓17個參與者組成聯賽,從神經網路的第1次迭代到第49次。每一組比賽兩次,兩個玩家都有機會先玩。
這是最後的排名:
顯然,神經網路的最新版本比早期版本更勝一籌,贏得了大部分的遊戲。 這也似乎表明學習過程沒有達到極限 - 隨著訓練時間的進一步延長,玩家將會繼續變得更強大,學習越來越複雜的策略。
作為一個例子,隨著時間的推移,一個神經網路挑選的策略較早的佔據了中間列。觀察演算法的第一個版本與第三十個版本之間的區別:
第一個神經網路版本
第三十個神經網路樣本
這是一個很好的策略,因為很多線路都需要中間列 – 儘早佔領這一列可以確保你的對手無法利用這一優勢。 神經網路已經在沒有人類指導下,學到了這一點。
學習其他遊戲
在遊戲檔案中有一個稱為“Metasquares” 的game.py檔案。其中的X和O用於形成不同大小的正方形。較大的方格意味著要落更多的棋子,當棋盤佈滿時,落子多的一方獲勝。
如果你將Connect4 (四子連珠) 的game.py檔案替換成Metasquares的game.py檔案,同樣演算法將會用於學習翫Metasquares遊戲。
趕緊自己來動手試試吧!