有趣的機器學習第二章:用機器學習製作超級馬里奧的關卡

有趣的機器學習第二章:用機器學習製作超級馬里奧的關卡

來自專欄 混沌巡洋艦

有趣的機器學習第二章:用機器學習製作超級馬里奧的關卡

作者:九五要當學霸

鏈接:知乎專欄

來源:知乎

著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

在開始之前,先來看看機器學習製作的關卡成果吧~

有趣的機器學習 第二章:用機器學習製作超級馬里奧的關卡—在線播放—優酷網,視頻高清在線觀看http://v.youku.com/v_show/id_XMTg2NTg1MTk5Ng==.html?spm=a2hzp.8253869.0.0&from=y1.7-2

在第一章中我們談到了,即使不用編寫具體的程序,我們也能用機器學習的泛型演算法告訴你一些有趣的結論。點此閱讀第一章

這一次,我們要來用泛型演算法之一來做一件很酷炫的事情。創造一個看起來像是人類設計的電子遊戲關卡!我們會構造一個神經網路,並提供給它已存在的超級馬里奧的關卡設計,然後就可以等它自己創造出新的關卡了!

使用這種泛型演算法可以創造出來關卡之一

和第一章類似的是,這份指南是針對所有對機器學習感興趣但不知從哪裡學起的讀者的。本文目標在於平易近人,這意味著文中有大量的概括。但是誰在乎這些呢?只要能讓讀者對於機器學習更感興趣,我的任務也就完成了。

做出更智能更準確的預測

回到第一章,我們根據房屋各種特徵屬性創造了一個來估計房屋價格的簡單演算法。我們給出了一所房子的如下數據:

我們得到了這個簡單的預估函數:

def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): price = 0# a little pinch of this price += num_of_bedrooms * 0.123# and a big pinch of that price += sqft * 0.41# maybe a handful of this price += neighborhood * 0.57return price

換一個角度來說,我們把決定房屋價格的因素乘以它的權重,再把這些乘積求和,就可以得到房子的預估價格了。

或者不使用代碼,我們直接用一個圖片來概括這個函數:

箭頭表示了函數中的權重

然而,這個演算法僅僅能用於處理一些簡單的問題,就是那些輸入和輸出有著線性關係(Linear Relationship)的問題。但如果真實價格和決定因素的關係並不是如此簡單,那我們該怎麼辦? 比如說,地段對於大戶型和小戶型的房屋有很大影響,然而對中等戶型的房屋並沒有太大影響。那我們該怎麼在我們的模型中收集這種複雜的信息呢?

所以為了更加的智能化,我們可以利用不同的權重來多次運行這個演算法,收集各種不同情況下的價格估計。

我們來嘗試用4中不同的演算法來解決該問題

現在,我們有了4種不同的價格估計。我們將這4種價格估計匯總到一個最終估計當中。我們再把們放到同樣的演算法當中再算一遍(當然這次我們使用的權重不同)。

我們現在就結合了解決同一問題的方法4種不同方法,得到的一個「超級答案」。正是由於此,我們才能夠用它來模擬更多不同的情況。

神經網路是什麼?

我們來把4種不同的預測方法概括到一個圖當中:

這就是一張神經網路!每一個節點都知道如何收集一組收據,找到他們的權重,做出對應的輸出值(價格預測)。把這些節點連接到一起,我們就可以模擬更複雜的函數了!

當然了,為了保持簡潔性,我跳過了許多內容(例如數據規範化Feature Scaling和激活函數Activation Function)。但是最重要的是下面的這些內容:

  • 我們製造了一個 權重*因素簡單演算法,我們把這個演算法叫做神經元。

  • 通關連接神經元,我們能模擬那些不能被一個簡單神經元所模擬的函數。

這就好像樂高積木一樣! 我們不能用一個樂高積木搭成摩天大樓,但是如果有足夠多的樂高積木的話,我們能夠搭建成任何東西。

也許未來的動物都是由積木搭成的? 那隻能去未來一探究竟了…

讓我們的神經網路擁有記憶的能力

如果輸入相同的數據,我們剛剛看到的那個神經網路總是有著一樣的輸出。這是因為他沒有記憶能力。用編程的語言來說,他是一個無狀態演算法(Stateless Algorithms)。

在許多情況下(例如說預估房子價格),這正是你所需要的演算法。但是隨著時間的增加,這種演算法無法在數據中找出規律。(譯者註:因為沒有記憶能力)。

假設我現在讓你在電腦上寫一個故事。在你開始之前,我需要猜測你最先敲擊鍵盤上的哪個字母。我應該猜哪個呢?

我可以使用我的語言(英語)知識來增加我猜對的概率。比如說,你可能會先打單詞常見的第一個字母。如果我查看一下你過去寫過的故事,我能夠根據你過去的用詞選擇來縮小我猜測的範圍。一旦我擁有這些數據,我能夠用他們來構建一個神經網路,並能計算出你用任意一個字母來開頭的概率。

我們的模型就像這樣:

讓我們把這個問題變得更難。現在我們假設在整個故事當中的任何一個點,我們要猜測你要敲擊的第下一個字母是什麼。這是一個更有趣的問題。

讓我們把海明威的著作「太陽照常升起」的前幾個單詞當成一個例子:

  • 「Robert Cohn was once middleweight boxi」

所以,下一個字母是什麼?

你可能會猜是「n」,這個詞有可能是「boxing」。我們是通過觀察還有語言常識來猜測這個詞的。同時,「middleweight」這個詞也給了我們猜測的額外線索。

換一個角度來說,如果我們知道了在這之前出現的字母並和我們的語言常識相結合,我們對下一個字母的猜測就會變得更加簡單。

為了用神經網路的方法來解決這個問題,我們需要把狀態(state)加入到我們的模型當中。每次通過神經網路來解決問題的時候,我們將中間的計算結果也保存下來,並作為下次的輸入的一部分再次使用。這樣一來,我們的模型就能根據以往的輸入數據來調整他的猜測。

跟蹤模型中的每一個狀態(state),不僅能夠讓我們更好預測第一個字母,更能讓我們更好的預測到任意位置的下一個字母。

這就是一個關於「循環神經網路」(Recurrent Neural Network,簡稱RNN)的基本概念。我們每次使用神經網路的時候都會對他進行升級。這使得讓它能跟根據最近瀏覽的信息更新它的預測。如果數據記憶足夠大的話,他甚至能夠模擬出長期的規律。

猜字母有什麼意義?

猜下一個字母看上去並沒有什麼卵用。這麼做的意義是什麼呢?

根據你的輸入,自動預測你想輸入的單詞,就是一個比較酷炫的應用。

下一個最有可能的字母是「t」

但是如果我們最大程度的拓展我們的概念會怎樣?如果我們讓我們的模型一直去預測下一個字母,永遠不停止,那會怎樣? 會不會機器自己寫出一個完整的故事?

生成一個故事

剛剛我們看到了如何猜測海明威的「太陽照常升起」中的下一個字母的。現在讓我們來試一試寫一個海明威式(寫作風格)的故事吧!

我們會通過「Andrej Karpathy」寫到的「循環神經網路實現」(Recurrent Neural Network implementation)來達成我們的目標。Adrej是斯坦福的一位深度學習研究者。他寫過一篇非常棒的關於 「通過RNNs來進行創作」的指南。你可以在GitHub上來查看這個指南。

我們會用這本「太陽照常升起」,來創造我們的模型。這本書里包括362,239個字,一共是84個不同的字母(包括標點符號和大小寫字母等)。相對於真實世界的問題來說,這組數據其實已經非常小了。為了儘可能好的創作出類似於海明威的風格,我們可能會需要比這本小說內容多出數倍的樣例文本。但是這本「太陽照常升起」已經足夠展示製作我們模型的過程了。

當我們剛開始訓練RNN的時候,他猜測的並不準確。這是它經過100個循環訓練之後的結果:

hjCTCnhoofeoxelif edElobe negnk e iohehasenoldndAmdaI ayio pe e h』e btentmuhgehi bcgdltt. gey heho grpiahe.

Ddelnss.eelaishaner」 cot AAfhB ht ltny

ehbih a」on bhnte ectrsnae abeahngy

amo k ns aeo?cdse nh a taei.rairrhelardr er deffijha

(譯者註:上面這些只是一堆字母而已 並拼不成任何單詞)

你可以看到的是機器已經知道單詞之間應該有空格,這正是我們想要的。

1000個循環之後:

hing soor ither. And the caraos, and the crowebel for figttier and ale the room of me? Streat was not to him Bill-stook of the momansbed mig out ust on the bull, out here. I been soms

inick stalling that aid.

「Hon』t me and acrained on .Hw』s don』t you for the roed,」 In』s pair.」

「Alough marith him.」

(譯者註:一半兒還只是字母,另一半被拼成了有實際含義的單詞,但意思並不通順)

我們的模型已經開始識別出句子的基本構成模式了。他已經學會給句子加上句號,甚至學會了用引號。還成功的拼出了一些單詞,但依然大部分都在胡扯。

經過幾千次交互訓練之後,他看起來很棒:

He went over to the gate of the café. It was like a country bed.

「Do you know it』s been me.」

「Damned us,」 Bill said.

「I was dangerous,」 I said. 「You were she did it and think I would a fine cape you,」 I said.

「I can』t look strange in the cab.」

「You know I was this is though,」 Brett said.

「It』s a fights no matter?」

「It makes to do it.」

「You make it?」

「Sit down,」 I said. 「I wish I wasn』t do a little with the man.」

「You found it.」

「I don』t know.」

「You see, I』m sorry of chatches,」 Bill said. 「You think it』s a friend off back and make you really drunk.」

(譯者註:翻譯一下上面的這段話雖然詞語都正確了但是句子根本不通順:

他跑到了咖啡廳的門口。它像是一個鄉下的床一樣。

「你知道那是我。」

「詛咒我們」比爾說。

「我曾經很危險,」我說「你是她做了它並且認為我會一個好的海角你」

我說。

「我不能在計程車里看起來奇怪」

「你知道我是這個雖然」,布拉特說。

「他是一個打架不重要?」

「它讓去做它」

「你做的?」

「坐下,」我說。「我希望我沒有和那個男人做一點。」

「你找到了它。」

「我不知道。」

「你看,我對chatches(英文中沒有chatches這個詞)感到抱歉」比爾說道「你認為它是一個朋友後面並且它真的讓你醉」)

到此時,演算法已經收集到了海明威寫作的基本風格——簡短而直接的對話形式。甚至有一些話語開始被人類理解。

和原文中的句子作比較:

There were a few people inside at the bar, and outside, alone, sat Harvey Stone. He had a pile of saucers in front of him, and he needed a shave.

「Sit down,」 said Harvey, 「I』ve been looking for you.」

「What』s the matter?」

「Nothing. Just looking for you.」

「Been out to the races?」

「No. Not since Sunday.」

「What do you hear from the States?」

「Nothing. Absolutely nothing.」

「What』s the matter?」

即使我們每一個單詞都做比較,我們的演算法也已經用恰當的格式重新出一篇看起來可信的文章。這非常厲害!

當然,我們再也不用寫文章之前打草稿了。我們可以把前幾個字母放到演算法當中去,讓演算法找到後面的幾個字母。

為了好玩,我們一起來模仿海明威著作的封面,並通過我們的演算法,生成一個假書名和假作者吧!

真書在左,看起來傻乎乎的假書在右(譯者註:右邊的書名意思是:肉用公牛的秘密)

看起來不錯呀!

但是真正讓人腦洞大開的部分是這個演算法能夠找出任何數據序列中的規律。他可以輕鬆創作出食譜或者是假的奧巴馬的演講。為什麼一定要限定是人類的語言呢?我們也可以用這個想法來處理任何有規律可循的數據。

不用馬里奧,智造馬里奧

2015年,任天堂在Wii平台上發布了「超級馬里奧編輯器」。

每個孩子的夢想。

你能夠用這個編輯器創造出你自己的超級馬里奧關卡並把它們上傳到互聯網上,和朋友們一起玩。你可以使用遊戲中所有經典的道具和敵人來創造你自己的關卡。這就像是一個為成年人設計的樂高積木玩具一樣。

所以問題來了,我們能夠使用創作海明威的模型來製作馬里奧么?

首先,我們需要一組數據來訓練我們的模型。我們會使用馬里奧兄弟1985年版所有的室外關卡的數據(譯者註:就是最經典的那一版本)。

這個聖誕節棒極了!謝謝粑粑麻麻!

這個遊戲共包含32關而其中70%是都有類似的戶外場景。所以我們將會使用這些數據。

我設計了一個小程序,把原版遊戲中所有的關卡設計都提取了出來。超級馬里奧兄弟是一個有著30年歷史的遊戲,網上有著豐富的資源來幫助你找出關卡設計在遊戲代碼中的存儲位置。從一個老遊戲中提取關卡數據,是一個很有趣的編程練習,你有空可以試一下!

這個就是遊戲的第一關(如果你玩過超級馬里奧,你應該會記得)

超級馬里奧關卡1-1

如果我們仔細觀察,我們會發現這一關是由一個個簡單的小網格類型的物品構成的。

我們可以簡單的把這些網格表示成一序列字元,每一個字元都代表著一個物品:

------------------------------------------------------------------------------#??#-----------------------------------------------------------------------------------------------------##------=--=----------==---------==--==--------===--------===--===------====-------====--====----=====-=========================-

我們把物品換成了下列字母:

  • 「_」代表沒有物品

  • 「=」代表磚塊
  • 「#」代表可以打碎的磚塊
  • 「?」代表金幣磚塊

…就類似於這樣,用不同的字字元代表關卡里的不同的物品。

最後就得到了如下的文本文檔:

仔細觀察這個文本文檔,你會發現如果以「行」的順序觀察,並沒有什麼規律可循:

一行一行尋找,並找不到什麼規律。你會發現很多行就是空白的。

當你把關卡理解為連續的「列(Column)」的時候,規律就浮現出來了:

一列一列尋找,規律就顯現出來了。比如說每一列都以「=」結尾。

為了讓演算法能找出我們數據中的規律,我們需要把數據以列的形式輸入。找出你數據的最有效的表達方法(這個方法也叫作特徵選擇Feature Selection),是使用機器學習演算法的重要技巧之一。

為了訓練模型,我需要把這個文本文檔旋轉90度。這樣一來就保證了這些字元被輸入進模型之後,模型能夠更容易找到其中的規律。

-----------=-------#---=-------#---=-------?---=-------#---=-----------=-----------=----------@=----------@=-----------=-----------=-----------=---------PP=---------PP=----------==---------===--------====-------=====------======-----=======---=========---=========

訓練我們的模型

就好像我們剛剛看到的創作海明威風格的那個模型一樣,經過訓練之後,一個模型會得到提升。

經過一點點的訓練,我們的模型生成了並沒有什麼卵用的東西:

--------------------------LL+<&=------P------------------------------------------T--#--------=--=-=------------=-&--T------------------------------------=------$-=#-=-_--------------=----=<-----------b-

它好像理解了應該有很多的「_」和「=」的思路,這已經很好了。但是還沒有找到規律。

經過幾千個循環之後,它開始變得有模有樣了:

-------------=----------=--------PP=--------PP=-----------=-----------=-----------=-------?---=-----------=-----------=

模型幾乎已經知道每一行應該有相同的長度。它甚至開始找出馬里奧的一些邏輯:管道(綠色的管子)經常是兩個磚塊那麼寬,並且至少有兩個磚塊那麼高,所以數據裡面的「P」應該以一種2×2的方格形式出現。這非常酷炫!

經過大量的訓練之後,模型開始達到一種創造出完美的可用的數據的階段:

--------PP=--------PP=----------=----------=----------=---PPP=---=---PPP=---=----------=

讓我們用我們的模型來創造一整個關卡,並把它們橫過來:

用我們的模型創造的一整關

數據看起來棒棒噠!並且有以下幾個優點值得關註:

  • 他把那個蟲子(譯者註:那個蟲子叫做Lakitu)放在了關卡的一開始的天上,就像真實的超級馬里奧關卡一樣。

  • 他知道管道是壓在磚塊上面的,而不是僅僅漂浮在天上。

  • 他把敵人放在了恰當的位置

  • 它看上去就超級馬里奧的一關一樣,因為它是在遊戲里存在的原版關卡的基礎上創造出來的。

最終,我們把這一個關放到超級馬里奧編輯器裡面,來創造出這一關。

我們的把關卡數據輸入到編輯器以後得到的關卡

(Youtube視頻)

自己玩吧!

如果你有超級馬里奧編輯器,你可以在線試玩或者是通過關卡代碼4AC9–0000–0157-F3C3來找到這一關。

玩具或是真實世界的應用?

我們所使用的用來訓練我們模型的循環神經網路演算法,就是一些真實的公司用來解決難題的演算法。這些難題包括語音識別和文字翻譯。解決難題和創造一個遊戲關卡的區別,就在於數據量,我們的模型是由極少量的數據生成的。對於創造一個非常好的模型來說,原版超級馬里奧兄弟裡面的關卡數量還不夠多。

如果我們像任天堂一樣擁有成千上萬玩家自己創作的馬里奧關卡的數據,我們可以製作出一個令人震驚的模型。但是我們不能,因為任天堂並不讓我們擁有他們。天下沒有免費的午餐,大公司的數據不免費給你。

隨著機器學習在許多領域越來越重要,好程序與壞程序的區別就在於你需要多少的數據來訓練你的模型。這就是為什麼像谷歌和Facebook這樣的公司如此需要你的數據。

打個比方,谷歌最近對TensorFlow進行了開源,公布了它用來建立大規模機器學習的Toolkit。谷歌把如此重要,如此實用的科技免費公布出來,這還是一個很重量級的決定。你要知道,這可是和谷歌翻譯使用的原理是相同的。

但是離開了谷歌在各種語言裡面收集到的信息,你沒有辦法創辦一個谷歌翻譯的競爭對手。數據是使谷歌處在行業頂端的源泉。想一想你打開谷歌地圖歷史記錄或者是Facebook地點記錄的時候,你會發現它們記錄下來了你去過的每一個地方。

延伸閱讀

在機器學習中,絕不會有單一的解決問題方法。對於如何預處理數據和演算法的使用,你總是有無限種選擇。綜合各種方法經常會比使用單一方法能得到更好的結果。

讀者們發給了我許多其他的生成馬里奧兄弟關卡的有趣的方法:

  • Amy K. Hoover』s 的團隊把遊戲中的每一種物品表示成交響樂中的一種聲音。然後再使用一種叫做「功能性架構(Functional Scaffolding)」的方法,系統能夠把每一種物品添加到關卡里去。比如說,你可以自己製作出你想要的關卡基本樣式,然後再去添加水管或者是問號磚塊,來完成你的創作。

  • Steve Dahlskog的團隊展示了一種模型。這種模型能夠把每一列遊戲關卡數據表示成一序列的有n個元的「單詞」(modeling each column of level data as a series of n-gram 「words」 ),相比於循環神經網路演算法,這種方法這使得他們能夠以一種更簡單的方法來生成關卡。

推薦閱讀:

在哪一瞬間你認識到人類的科技沒有想像中的發達?
黑科技隨機報:怕不是在暗示太空開發要來了
電腦端有哪些特別好用的小工具?
Cluster(集群)[翻譯]
今日頭條的普通自媒體人該何去何從?

TAG:科技 | 機器學習 | 深度學習DeepLearning |