車栗子 發自 凹非寺

量子位 出品 | 公眾號 QbitAI

要了解機器學習、了解神經網路,一種非常有趣的方式,就是找個小遊戲,自己實現一下。

遊戲里的每一位AI玩家 (智能體) ,都是一個小小的神經網路。

△ 訓練前

一開始,它們什麼都不懂,剛開局就GG。但有了進化演算法 (Evolution) ,AI可以在一代一代更迭中,掌握強大的遊戲技能。

△ 成效顯著

比如,在這個賽車遊戲里,萌新車手跑出去不久便撞上了馬路牙子。不過,用不了幾代進化,就有AI車手可以毫髮無損地跑完一周。

進化的賽車手

AI賽車手如何快速煉成?

首先,要有一個龐大的車隊。

賽車AI的開發者,是一位叫做Johan Eliasson的程序猿。他的訓練計劃里,有650輛車同時訓練。

第二,AI開車需要一些空間信息。

這5條黃線代表5個距離,指示離馬路牙子還有多遠;

除此之外,AI還需要知道自己當前的速率,以及方向

這樣算來,神經網路一共會接受7個輸入

第三,就是讓神經網路不斷進化。

輸入七個值,處理一下,輸出兩個值

一個代表方向盤,按照數值大小,分為左轉右轉方向不變三種操作;

一個代表油門/剎車,按照數值大小,分成加速減速速率不變三種操作。

最開始,誰不知道遊戲規則,輸出值很隨機。

△ 第一代,死得快

650輛車衝出去沒多久,路邊就出現了大批車輛的屍體。

但重要的是,依然有碩果僅存的汽車,不止通過了第一次的右轉考驗,也機智地發現下一處彎道應該猛烈左轉

雖然,它並沒有成功掉頭,但依然是下一代的希望:進化演算法就是要在每一代里,選出最優秀的一隻或者幾隻智能體,繁育出色的後代。

(這裡,程序猿沒有找到一種很好的方法,讓系統自動選擇出優質的個體,於是就手動馬克了,反正也沒有訓練很多代。)

所以,第二代的650輛車,全是這一隻智能體的子嗣,各自有些輕微的變異:神經網路的權重發生小小的變化。

變異是為了保持車隊的多樣性,期待從中生產出更加優秀的個體,繁育下一代。

△ 第二代,馬克三隻

由於繼承了優良傳統,第二代汽車大部分都完成了第一次右轉,還有一小部分掉頭成功。

這一次,把衝到最前面的3輛車馬克一下,它們差一點就能達成兩次連續掉頭的S形操作。

既然,第三代的父母有3位,那麼繁育過程中除了變異之外,還涉及雜交:就是把不同的神經網路揉到一起:

第三代的表現更加精進,有的智能體完成了多次連續轉彎,勝利在望。

第四代,便有智能體跑完一周,值得紀念:

程序猿說:這效果比想像的好多了,之前我還有點懷疑,現在只能說機器學習好厲害。

第四代車隊中的佼佼者,已經不太撞到路肩,只是速度還很慢,就像一大波殭屍。

車隊的主人表示,後面的主要任務就是訓練速度。畢竟,這是賽車。

到了第十代,速度已經有了明顯的提升,不過依然不算快:

△ 第十代

不知訓練了多少代,現在把每一代的優質選手放在一起跑。你看,好快:

△ 這才是賽車

成果斐然之餘,程序猿還請大家注意一個重點:

AI不知道自己在開車,不知道有跑道。它只接收七個輸入的數值,不了解它們代表什麼意思,也不知道自己輸出的每一個決策,產生了怎樣的效果。

就算這樣,它還是學會了怎樣在遊戲世界裡更好地生存。

不想開車?還有其他遊戲

雖然,賽車遊戲的視頻,沒有講到程序猿用了怎樣簡單的神經網路。不過,可以通過另一個簡單的遊戲,來感受一下:

Flappy Bird

這個HTML 5實現, 也是進化演算法和神經網路共同的結晶。而且開源了。

它的作者ssusnic說,神經網路部分,用的是突觸神經網路 (Synaptic Neural Network) 庫。

沒有650輛車那麼多,種群里只有10隻小鳥。每一隻,都是一個三層的神經網路:

輸入層:兩個神經元

隱藏層:六個神經元輸出層:一個神經元

輸入兩個值,代表小鳥當前距離下一個障礙物的相對位置,分成水平距離 (x) 和豎直距離 (y) 。

經過隱藏層的處理,輸出一個0-1之間的數值,決定下一步要不要扇翅膀:

如果大於0.5,就扇翅膀,反之就不操作。

△ 第一代

第一代的小鳥,都是隨機神經網路 (Random Neural Networks) ,集體見光死。

全部陣亡之後,要選出四隻最優質的小鳥去繁殖。問題來了,肉眼看去相差無幾,要選哪幾隻?

並不需要手動選擇,而是用一個適應度函數 (Fitness Function) :

適應度 = 小鳥存活的最遠距離 - 小鳥到下一個障礙物的距離

△ 這裡,討論水平距離

適應度分數排名前四的小鳥,按下面的規則繁殖10個後代:

· 前兩名,雜交出一個後代

· 4隻中隨機選兩隻,雜交出三個後代· 4隻中隨機選兩隻,分別直接複製,生成兩個 (和上代一樣的) 後代· 給每個後代加入一些變異

就這樣,來到第11代,已經有小鳥飛出很遠且毫髮無傷:

第23代,完全碾壓,可以換個遊戲了:

吃豆豆

當然,不是所有遊戲都像小鳥扇翅膀這樣簡單。

吃豆人 (Pacman) 就是個更複雜的栗子。比如,前面要躲避的障礙物都是靜止的,Pacman的敵人是移動的,窮追不捨。

重點是,為了抓到Pacman,四個敵人還有各自不同的運動規則:

紅色鬼,直接瞄準Pacman的位置進發;

粉色鬼,瞄準Pacman前方的第四格;藍色鬼,利用Pacman和紅色鬼的位置來搞伏擊;橙色鬼,原本和紅色鬼一樣,但當它和Pacman的距離近到8格以內,就會朝一個角落退縮,那是它出發的地方。

並且,Pacman吃到無敵大豆豆的時候,敵人還會從追擊模式轉成逃跑模式。

複雜的遊戲,自然也需要更加精密的演算法,來幫智能體進化。

名叫Code Bullet的程序猿,就用了一種叫做NEAT的神經進化演算法。

這種方法很特別,神經網路在迭代過程中,不止權重會變化,網路結構也會變複雜

而網路結構越複雜,就可以支持越複雜的行為,讓Pacman在險惡的世界裡存活。

雖有強大的演算法,訓練還是要由淺入深

先不加無敵大豆豆,也不加敵人,給AI一個簡單的世界。

這樣它就能吃光所有豆豆?不存在的。

第一代最優秀的智能體,也只會右轉不會左轉,還把自己困在一處,永遠走不出去。

第二代,有的選手已經學會了左轉,但依然會困住。

……

第十八代,眼看快要吃光豆豆,AI還是困死了自己。

在平靜中訓練20代之後,把敵人放出來,AI又要從手忙腳亂開始重新適應:

不過好在,智能體學以很快便學會了躲避敵人:

又過了40代,是時候加入無敵大豆豆了。

這一層防護令AI如有神助,就像在經歷了40代卧薪嘗膽之後,開啟了復仇模式,瘋狂追擊。

終於,有智能體在第七十三代通關成功:

視頻的畫外音里,程序猿的聲音都激昂了起來,這場戰役的勝利他期待已久。

除了發表獲獎感言,謝過各路親友的支持,他也沒忘在GitHub上分享代碼 (傳送門見文底) 。

動手吧,少年

同學,你也去搭個神經網路打遊戲吧,呆萌的遊戲也能打出熱血的氣質。

以後,神經網路可能就是你女朋友了。

(友情提示:雖然賽車遊戲沒有開源代碼,但OpenAI Gym裡面有賽車場,也可以去試試。)

賽車遊戲視頻傳送門:

youtube.com/watch?

OpenAI Gym賽車場:

Gym: A toolkit for developing and comparing reinforcement learning algorithms

Flappy Bird代碼傳送門:

ssusnic/Machine-Learning-Flappy-Bird

Pacman代碼傳送門:

Code-Bullet/PacNeat (NEAT演算法)Code-Bullet/PacmanGame (搭建遊戲環境)

量子位 · QbitAI

?? ? 追蹤AI技術和產品新動態

戳右上角「+關注」獲取最新資訊↗↗

如果喜歡,請分享or點贊吧~比心?


推薦閱讀:
相关文章