程序员 Windows Ubuntu java shell apache Android Python 编程 微软 wordpress nginx 云计算 linux Firefox php mysql 开源 google centos

用神經網絡實現能夠自主避讓障礙的生物

這篇文章是我去年看到的一個很有趣的項目,還試著模仿它的代碼寫一個類似的項目出來,不過一直沒有完成。這裏把原作者的一篇相關博客翻譯過來,說不定有更多的人對此感興趣。

項目演示: 原作者用JavaScript實現的demo

原文地址: creatures avoiding planks

譯文地址: 用神經網絡實現能夠自主避讓障礙的生物

翻譯: 吳鍇(noiron)

註意:原文中引用了一些墻外鏈接,請配合梯子食用

以下為譯文內容:

具有神經網絡大腦的agent為了生存而進化

這裏是javascript的演示

最近我看到了一個模擬 視頻 ,展示了使用進化技術來訓練agent,讓它們能夠避開移動的障礙物。 這裏使用的方法 似乎是 NEAT 算法的變種。NEAT算法用於神經網絡拓撲結構的進化,使其能夠正確完成特定的任務。它是為了 Unity 5 遊戲引擎而寫的,想被整合進綜合的遊戲AI中,這引起了我的興趣。

這個結果很酷而且動起來似乎很優雅,所以我想試著用javascript實現一個類似的demo,這樣就可以在瀏覽器中運行了。在玩了一下基本的實現後,我發現對於障礙躲避問題,一個簡單的神經網絡就可以高效的完成了,甚至於一個完全連接的神經網絡都算是殺雞用牛刀了。最後我也意識到就算是一個簡單的類 感知器(perceptron) 網絡都能夠很好地完成任務,而在之前提到的障礙躲避demo中,隱藏單元也並不能夠增加多少好處。

簡單的感知器圖解(維基百科)

因為agent可以在探測到障礙物的瞬間自由地向任意方向移動,而且agent之間不會產生相互作用,因此這個任務變得太簡單了,使用NEAT算法的殺傷力過大了。我們使用一個簡單的類感知器網絡(即單神經元網絡),就能讓agent有效地完成躲避障礙的任務了。

讓agent的生活變得艱難,因為生活是艱難的

我想讓事情有趣點,所以加了幾個額外的條件讓任務更困難。

運動被限制在嚴格版本的 Reynolds轉向 下,如 這篇論文 中概述的創建逼真的模擬行為這樣,與之相對應的是可以向任意方向自由移動。

Agent可以選擇向左或向右轉向,但不能夠直行。就像一輛沒有動力的車轉彎一樣,它也必須在轉彎時朝著所轉的方向前進。我想看看agent能否發展出這樣一種轉向模式,即通過快速地在左轉和右轉之間切換從而向前移動。這樣事情變得更加困難了,你可以想象駕駛一輛汽車時,為了能向前直行,只能不斷地向左或向右打死方向盤。

Agent之間會互相碰撞,如果適應度函數是按這種方式設置的話,它們也許需要發展出一種策略來避開對方,要不然我內心的邪惡面會希望它們一起跑向木板。

我發現有了這些限制,agent就不能依靠一個簡單的單神經元完成這一任務了。我仍然認為這一任務不應當依靠類似ESP或NEAT等高級的方法,我想用現成的 convnet.js 庫來生成神經網絡,所以我選擇了在 neural slime volleyball 項目中使用過的同樣超級簡單的神經網絡結構。下面是我的 第一次嘗試 。

每一個agent的大腦由十個神經元組成,每個神經元都和所有的輸入及其余的神經元相連接,也許就像真實大腦的中一個小區域的切片一樣。下面是大腦的原理圖:

神經網絡的基本圖解——每個大腦有269個權重值

這種網絡結構被稱作 全連接的遞歸網絡(fully connected recurrent network) 。每一個agent都有一組將送入遞歸網絡中的感知輸入。10個神經元中的2個將控制agent的動作,其它的是用於計算和思考的“隱藏神經元單元”。所有的神經元輸出信號又將送回輸入層,所以每一個神經元都與其它的神經元完全連接起來了,這中間會有一幀(~1/30s)的時間延遲。

輸出層的第一個神經元用於控制agent是向左還是向右轉,取決於輸出的信號。我們使用 雙曲正切 函數來啟動神經元,因為神經元的輸出值在-1至1之間,所以做這樣的一個二元選擇(左/右)是很自然的。第二個神經元控制agent是移動還是保持靜止,也取決於輸出信號。

訓練網絡

100個初始化為隨機權重值的agent被用於訓練,它們會在模擬中四處跑動直到它們被一塊木板殺死。在模擬的最後所有人都死了,這種感覺很糟糕,但是人固有一死……

當所有的agent在一次模擬中全都死亡了之後,我們保留在模擬中存活了最長時間的30個agent的基因用於下一代,丟棄其余的70個agent。最好的30個基因,即神經連接的權值和偏置(bias)的向量,將會進行交叉變異以傳遞給下一代中新產生的70個agent。這個過程(將在下面的繁殖部分解釋)將會持續進行,直到最好的agent能夠熟練地躲開木板並存活五分鐘以上。

下面是一個運行中的進化模擬 demo ,它的第一代是完全隨機的網絡(我將這個demo縮減為50個agent而不是100個,這樣在大部分電腦甚至是智能手機上都能夠運行)。起初,大部分的agent都不會試圖存活下去(或者直接放棄了!),但是也許一個或兩個知道該幹些什麽並且做的好了些,所以它們能夠進入下一代並且進行繁殖。在幾代過後,你會看到種群的能力增加了,它們全都開始躲避移動的木板了。我驚訝地發現,在30代後結果就不錯了。如果你感興趣,可以看一下這個 訓練demo 中它們是如何從開始時完全不知道如何生存進化到這一步的。註意這些結果是每十代更新一次的。因為我希望它們盡可能快的進化,而不是將進化限制在每秒30幀,所以把模擬運行到電腦能允許的最快速度,而每隔十代運行一次作為展示的模擬,因此你可以品評實時的進度——而實際的進化是在屏幕之後以光速進行的。

訓練的草圖——觀看agent如何從一無所知進化而來

Agent周圍的線條是它的知覺傳感器,就像視覺輸入一樣,它們給每一個agent提供了周圍世界的感知能力。Agent感知到的物體越近則線條的強度越大。每個agent能夠看到周圍的8個方向,探測距離最大為其身體半徑的12倍。我是這樣決定信號值的,agent探測到的物體越近,信號越接近一,反之,若沒有探測到物體,信號為零。如果agent看到的物體距離為6倍半徑,則信號為0.25而不是0.5,這裏我為了模仿 光照密度模型 將結果進行了平方。

如果Wayne Gretzky在有孩子之前就遭遇了車禍會如何?

[譯者註]:Wayne Gretzky是著名的加拿大冰球運動員

我也給上面提到的訓練算法進行了一點微調。

現在的一個問題是一些表現最好的agent可能會意外死亡,即使它們很厲害,但因為模擬中agent之間太擁擠了,它也會因為純粹運氣不好而死掉。上一代的一個頂尖的躲避墻的agent,起始位置可能是在人群的邊緣,在模擬開始時就會被其它的幾個agent意外的推到木板上面,這就不能把它的好基因傳給下一代了。

我想了一下這個問題,想出了一個主意,在進化算法中加入一個“名人堂”部分,這將會記下那些達到了最佳記錄分數的agent的基因。我也修改了我的 進化庫 來加入這個名人堂特性,以保留歷來的十佳冠軍。對於每一次模擬,名人堂都會加入被加入到當前的這一代。從這層意義上來說,每一代的agent都必須和歷來最好的agent競爭。想象一下能夠在每一個冰球賽季都和Wayne Gretzkey, Doug Gilmour及Tim Horton一起訓練!

這個技術絕對極大提升了進化的結果,因為最好的基因都被強制加入到了種群中。如果這發生在現實生活中會很恐怖的(雖然我們可能很快就將達到這一步了……)。我認為我在進化計算的世界裏發現了一個偉大的新技術,這是一個突破!然而,我發現名人堂技術 已經在圍棋領域中被用於 神經進化了。好吧,這對我不是好消息。

我想看看如果我重新進化一遍,agent是否會表現地完全不同,於是我花了幾天訓練了不同的幾組agent,每一組都有一千代左右。事實證明大部分的agent最終都有相似的權值模式。為了知道每個agent的大腦看起來有何不同,我將表現最好的agent的“基因代碼”畫成了圖,為了圖中的效果我將四個權值作為一組合成了一個顏色(RGBA的四個通道)。

每一行代表進化最成功的神經網絡的權值

可以看出表現最好的agent除了些許差別外似乎都差不多。然而,這可能會導致一個問題,即它們可能都被限制在一個局部優化狀態。我可以想象在某些情境中,agent為了避開木板而趨向於發展出相同的次最優策略,而由於任務的難度的限制就不會有新的進展了。如果使用更高級的方法可以解決這一問題,但是我對現在用簡單的 卷積神經進化 生成的遞歸網絡已經很滿意了。我在demo中使用了最好的23個基因。最終的模擬將會利用從這個訓練完成的組中隨機挑選出的名人堂來進行初始化。

結果分析

在經過約一千代的訓練後,agent已經能不錯地躲避障礙了。請看這個 demo 中的最終結果。Agent還遠不夠完美,但是它們展示出的像昆蟲般的行為讓我覺得很有趣。我很驚訝,即使它們被限制成只能全力左轉或右轉,它們仍然能夠完成躲避木板的任務。在demo中,每個agent有一只手,用於顯示它們轉的方向。沒有手則表示保持靜止。我也很高興的看到當agent想朝一個方向前進時,它能在空白區域搖擺向前,看來它們通過左轉和右轉間的切換發展出了某種模式。

最終模擬——otoro.net/planks

我也註意到它們傾向於和其它agent聚在一起並努力待在中間,我不確定原因。也許是因為在人群的中間,它可以等待其它agent死去從而增加自己存活的幾率。我也考慮過在適應度函數中使用與種群平均值有關的 相對生命長度 ,而不是絕對生命長度。也許在一個更復雜的網絡中,這能夠誘使agent變得邪惡且會計劃殺死其他agent。

繁殖

帶有父母雙方基因的後代

與其每一次都等著所有的agent死亡然後創造下一代,不如讓demo更有趣些,於是我給agent添加了配對和產生後代的能力!在以後這可能會形成一個可供選擇的讓agent進化的代內方法,而不是將每一代的種群數量固定為常數。

它工作的原理是對於每個agent,如果它們能夠生存某一個隨機的時間(一般為30至60秒),它們將具有繁殖的能力。如果這樣的兩個agent相遇了,就會產生兩個後代。後代初始時體積會小一點,在約30-60秒後會長到成年大小。父代agent的“激勵時鐘”重置為零,必須再等30-60秒才能產生下一代……

交叉算法(維基百科)

兩個後代將會繼承父母雙方的基因,這是通過很簡單的一點 交叉方法 。所以第一個孩子將會從第一個父代那裏繼承第一段神經網絡的權值,剩下的來自第二個父代。如上圖中描述的一樣,截斷點是隨機的。我還額外地給每一個孩子增加了隨機變異,所以它們將具有獨特性。這個隨機的變異對於鼓勵創新和給種群的基因庫添加新元素是很重要的。

從原理上說表現越好的agent有越高的生存幾率,因此它們有更高的幾率產生攜帶其基因的後代,反之較弱的個體會在擁有孩子之前死去。雖然有時很好的個體會因為不走運而死的太早,這對於它們確實不太好——這就是生活——生活是不公平的,而且生活很艱難!

與agent互動——扮演上帝

當使用demo時,你可以點擊屏幕的空白部分來創建新的agent加入模擬。一個新的agent的初始基因是從最近的幾個試圖產生後代的agent中隨機選擇出的,如果所有的agent都未繁殖過,那就從名人堂最初的一組中選擇。

如果你點擊到了木板上,將會切換到下一個視覺模式,例如,X射線模式,無邊框模式,沒有手的純粹生物模式等等。我用這些模式來評估不同的設計和總體的美感。我認為X射線模式看起來很酷,而且在較慢的機器上也能運行的更快。

X射線模式

你也可以通過點擊agent來給它們施加一個強大的推力。這模擬了一個暫時的風力效果,將它們從被點擊的地方推開。

你也可以在屏幕上拖動畫線來創建一塊新的木板。依據所畫的方向,木板會沿著其垂直方向向左或向右移動。你可以看到在你釋放了一些木板去摧毀它們的文明時,agent是如何反應的。請善用這個新能力,我註意到在沒有這個特性之前,用戶會給小家夥們加油,但是知道了這個功能後,他們開始準備種族滅絕了!

延伸阅读

评论