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

作者:Adam Geitgey

原文:medium.com/@ageitgey/ma

譯者:巡洋艦科技——趙 95

校對:離線Offline——林沁

轉載請聯繫譯者。

在第一章中我們談到,機器學習是用泛型演算法告訴你一些有關數據的有趣結論,而這個過程中你不需要寫任何與問題有關的特定代碼。(如果你還沒有讀過第一章,現在先去讀吧!)

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

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

和第一章類似,這篇指南是為那些對機器學習感興趣,但又不知從哪裡開始的人而寫的。這意味著文中有大量的概括。但是那又如何呢?只要能讓讀者對機器學習更感興趣,這篇文章的任務也就完成了。

在開始之前,我們先來看看我們用機器學習的方法製作出的關卡吧~

v.youku.com/v_show/id_X

做出更智能更準確的預測

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

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

def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood): price = 0 # 一小撮這個 price += num_of_bedrooms * 0.123# 一大撮這個 price += sqft * 0.41# 也許再來一把這個 price += neighborhood * 0.57return price

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

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

箭頭表示了函數中的權重。

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

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

讓我們試著用四種不同的演算法來解決該問題

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

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

神經網路是什麼?

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

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

當然了,為了保持簡潔性,我跳過了許多內容(例如特徵縮放和激活函數)。但是最重要的是下面的這些內容:

· 我們製造了一個權重×因素的簡單函數,我們把這個函數叫做神經元

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

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

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

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

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

在許多情況下(例如說估計房價),無狀態演算法正是你所需要的演算法。但是隨著時間的增加,這種演算法無法在數據中找出規律。[1]

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

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

我們的模型就像這樣:

讓我們把這個問題變得更難一點。現在我們假設,在整個文章中間的某一點,我們要猜測你即將輸入的下一個字母是什麼。這是一個更有趣的問題。

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

Robert Cohn was once middleweight boxi

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

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

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

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

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

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

猜字母有什麼意義?

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

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

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

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

生成一個故事

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

讓我們用安德烈·卡帕西(Andrej Karpathy)寫的循環神經網路實現來完成我們的目標。安德烈是斯坦福的一位深度學習研究者。有關用 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 [2]

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

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.」[3]

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

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

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?」

有幾個人在裡面酒吧間內,哈維·斯通獨自在外面坐著。他面前放著一大堆小碟子,他需要刮刮臉了。

「坐下吧,」哈維說,「我正在找你。」

「什麼事?」

「沒事兒。只不過找你來著。」

「去看賽馬啦?」

「沒有。星期天以來再沒去過。」

「美國有信來嗎?」

「沒有。毫無音信。」

「怎麼啦?」

即使我們只是尋找每個字元之間的規律,我們的演算法也已經用恰當的格式重新出一篇看起來可信的文章。這非常厲害!

我們也不用完全從頭生成文本。我們可以把前幾個字母放到演算法當中去,讓它找到後面的幾個字母。

讓我們一起來模仿海明威著作的封面,來偽造書名和作者玩玩吧!我們規定最開始的字母分別為「Er」、「He」、「The S」。

真書在左,看起來傻乎乎的假書在右。[4]

看起來不錯呀!

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

不用馬里奧,智造馬里奧

2015年,任天堂在 Wii U 平台上發布了超級馬里奧製造。

每個孩子的夢想!

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

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

首先,我們需要一組數據來訓練我們的模型。我們會使用馬里奧兄弟 1985 年版所有的室外關卡的數據。[5]

這個聖誕節棒極了!謝謝爸爸媽媽!

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

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

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

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

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

--------------------------

--------------------------

--------------------------

#??#----------------------

--------------------------

--------------------------

--------------------------

-##------=--=----------==-

--------==--==--------===-

-------===--===------====-

------====--====----=====-

=========================-

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

· 「-」代表沒有物品

· 「=」代表磚塊

· 「#」代表可以打碎的磚塊

· 「?」代表金幣磚塊

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

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

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

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

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

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

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

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

-----------=

-------#---=

-------#---=

-------?---=

-------#---=

-----------=

-----------=

----------@=

----------@=

-----------=

-----------=

-----------=

---------PP=

---------PP=

----------==

---------===

--------====

-------=====

------======

-----=======

---=========

---=========

訓練我們的模型

和剛剛訓練海明威式文章生成器的過程一樣,隨著訓練次數的增加,模型會漸漸被優化。

經過一點點的訓練,我們的模型生成了一堆垃圾:

--------------------------

LL+<&=------P-------------

--------

---------------------T--#--

-----

-=--=-=------------=-&--T--------------

--------------------

--=------$-=#-=-_

--------------=----=<----

-------b

-

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

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

--

-----------=

----------=

--------PP=

--------PP=

-----------=

-----------=

-----------=

-------?---=

-----------=

-----------=

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

經過大量的訓練之後,模型開始能生成完美的可用數據:

--------PP=

--------PP=

----------=

----------=

----------=

---PPP=---=

---PPP=---=

----------=

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

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

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

· 它把 Lakitu(那個浮在雲上的怪)放在了關卡一開始的空中,就像真實的超級馬里奧關卡一樣。

· 它知道浮在空中的管道是要放在磚塊上面的,它不能單單漂在空中。

· 它把敵人放在了恰當的位置。

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

最終,我們把這一個關放到超級馬里奧製造裡面,來創造出這一關:

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

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

自己玩玩看吧!

如果你有超級馬里奧製造,你可以通過網頁版書籤收藏或者是用關卡代碼 4AC9–0000–0157-F3C3 來找到這一關。

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

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

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

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

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

但如果你沒有海量數據,你仍然沒有辦法創造一個能和谷歌翻譯的匹敵的工具。數據是使谷歌處在行業頂端的源泉。想一想你打開谷歌地圖歷史記錄或者是 Facebook 地點記錄的時候,你會發現它們記錄下來了你去過的每一個地方。

延伸閱讀

在機器學習中,要解決問題決不只有一種方法。你總是有無數種方法預處理數據,你也有無數種機器學習演算法可選。綜合各種方法之後獲得的結果通常會比使用單一方法更好。

以下是一些讀者發給我的鏈接,還有這些有趣的方法可以生成馬里奧兄弟關卡:

· 埃米·K.胡佛(Amy K. Hoover)的團隊把遊戲中的每一種物品(管道、地面、平台等)表示成交響樂中的一種聲音。然後再使用一種名為功能性搭建(functional scaffolding)的方法,讓系統把每一種物品添加到關卡里去。比如說,你可以先自己製作出你想要的關卡基本樣式,然後系統就能通過增加水管和是問號磚塊來完善你的創作。

· 史蒂夫·達爾斯科格(Steve Dahlskog)的團隊,則把每一列關卡數據表示為一串 N 元語法(n-gram)的「單詞」,在此之上建立模型。相比大型的 RNN ,這種生成關卡的演算法更簡單。

1. 譯者註:因為沒有記憶能力。

2. 譯者註:上面這些只是一堆字母而已,拼不成任何單詞。

3. 譯者註:有一半內容還只是無意義的字母組合,另一半內容是有實際含義的單詞,但意思並不通順。

4. 譯者註:右邊的書名意思是——肉用公牛的秘密。

5. 譯者註:就是最經典的那一版本。


推薦閱讀:

2017年數據分析實踐計劃
鏈家網大數據平台建設,平台樞紐——工具鏈
大數據的本質是消除不確定性
線下大數據驅動營銷新趨勢
讓大數據消滅糾紛,別把你消費時受的氣帶回家

TAG:机器学习 | 人工智能 | 大数据 |