查看原文
其他

用机器学习制作超级马里奥的关卡

2016-12-23 九五要当学霸 混沌巡洋舰

概述:用泛型算法之一来做一件很酷炫的事情。创造一个看起来像是人类设计的电子游戏关卡!我们会构造一个神经网络,并提供给它已存在的超级马里奥的关卡设计,然后就可以等它自己创造出新的关卡了!

图:使用这种泛型算法可以创造出来关卡之一


这份指南是针对所有对机器学习感兴趣但不知从哪里学起的读者的。本文目标在于平易近人,这意味着文中有大量的概括。但是谁在乎这些呢?只要能让读者对于机器学习更感兴趣,我的任务也就完成了。


做出更智能更准确的预测

如何向你奶奶解释机器学习是什么,我们根据房屋各种特征属性创造了一个来估计房屋价格的简单算法。我们给出了一所房子的如下数据:

我们得到了这个简单的预估函数:

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来进行创作”的指南。

我们会用这本“太阳照常升起”,来创造我们的模型。这本书里包括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)放在了关卡的一开始的天上,就像真实的超级马里奥关卡一样。

  • 他知道管道是压在砖块上面的,而不是仅仅漂浮在天上。

  • 他把敌人放在了恰当的位置

  • 它看上去就超级马里奥的一关一样,因为它是在游戏里存在的原版关卡的基础上创造出来的。


最终,我们把这一个关放到超级马里奥编辑器里面,来创造出这一关。

我们的把关卡数据输入到编辑器以后得到的关卡


如果你有超级马里奥编辑器,你可以在线试玩或者是通过关卡代码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” ),相比于循环神经网络算法,这种方法这使得他们能够以一种更简单的方法来生成关卡。


更多阅读

数据分析实践项目101

朴素贝叶斯之实践篇

SVM初识之如何解决分类问题


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存