机器学习原来这么有趣!【第二章】:用机器学习制作超级马里奥的关卡

在第一章中我们谈到,机器学习是用泛型算法告诉你一些有关数据的有趣结论,而这个过程中你不需要写任何与问题有关的特定代码。(如果你还没有读过第一章,现在先去读吧!机器学习原来这么有趣!【第一章】

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

回到第1部分,我们创建了一个简单的算法,可以根据房屋的属性估算房屋的价值。给定关于如下图所示的房屋数据:

我们最终得到了这个简单的估算函数:

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.57
return price

换句话说,我们通过将房屋的每个属性乘以权重来估算房屋的价值。然后,我们仅将这些数字相加即可得出房屋的价值。

让我们再用简单的图来表示相同的功能,而不是使用代码:

箭头代表我们功能中的权重

但是,该算法仅适用于结果与输入具有线性关系的简单问题。如果房价背后的真相不是那么简单怎么办?例如,对于大房子和小房子来说,邻里关系很重要,而对中型房子根本就不重要。我们如何在模型中捕捉到那种复杂的细节?

为了更聪明的建立模型,我们可以使用不同的权重多次运行此算法,每个权重分别捕获不同的边缘情况:

让我们尝试以四种不同方式解决问题

现在,我们有四个不同的价格估算。让我们将这四个价格估算合并为一个最终估算。我们将通过相同的算法再次运行它们(但使用另一组权重)!

我们的新"超级答案"结合了我们为解决问题而进行的四种不同尝试得出的估计值。因此,与我们在一个简单模型中捕获的案例相比,它可以对更多的案例进行建模。

神经网络是什么?

让我们将我们的四种尝试猜测结合成一个大图:

这是一个神经网络!每个节点都知道如何接收一组输入,对其施加权重并计算输出值。通过将许多这些节点链接在一起,我们可以对复杂的函数进行建模。

为了保持简短,我跳过了很多内容(包括功能缩放和激活功能),但是最重要的部分是这些基本概念:

  • 我们制作了一个简单的估算函数,该函数接受一组输入并将它们乘以权重以得到输出。将此简单函数称为神经元

  • 通过将许多简单的神经元链接在一起,我们可以对过于复杂而无法由一个神经元建模的函数进行建模。

就像乐高!我们不能用一个乐高积木搭建一个大厦,但是如果我们有足够的乐高积木粘合在一起,我们就可以搭建成世界上任何一个东西:

让我们的神经网络拥有记忆的能力

当您输入相同的输入时,我们看到的神经网络总是返回相同的答案。它没有内存。用编程的术语来说,这是一种无状态算法

在许多情况下(例如估算房屋价格),这正是您想要的。但是这种模型不能做的一件事就是随着时间的流逝响应数据模式。

想象一下,我递给您一个键盘,要求您写一个故事。但是在您开始之前,我的工作是猜测您将键入的第一个字母。我应该猜什么字母?

我可以利用我的英语知识来增加猜对正确字母的几率。例如,您可能会在单词开头键入一个常见的字母。如果我查看您过去撰写的故事,则可以根据您故事开始时通常使用的词语来进一步缩小范围。一旦有了所有这些数据,就可以使用它来构建一个神经网络,以模拟您以任何给定字母开头的可能性。

我们的模型可能如下所示:

但是,让问题变得更加棘手。假设我需要猜测故事中任何时候要键入的下一个字母。这是一个更有趣的问题。

让我们以欧内斯特·海明威(Ernest Hemingway)的《太阳升起》为例:

Robert Cohn was once middleweight boxi

猜猜下一个字母?

您可能猜到了'n'这个词可能是"boxing"。我们基于句子中已经看到的字母以及我们对英语常用单词的了解而知道这一点。同样,“middleweight”一词为我们提供了有关boxing的更多线索。

换句话说,如果我们考虑下一个字母的顺序并将其与我们对英语规则的了解相结合,就很容易猜测下一个字母。

为了用神经网络解决这个问题,我们需要将状态添加到模型中。每次我们向神经网络询问答案时,我们还将保存一组中间计算,并在下一次再次使用它们作为输入的一部分。这样,我们的模型将根据最近看到的输入来调整其预测。

通过跟踪模型中的状态,不仅可以预测故事中最可能出现的第一个字母,而且还可以根据给定的所有先前字母来预测最可能出现的一个字母。

这是循环神经网络的基本思想。每次使用网络时,我们都会对其进行更新。这使它可以根据最近看到的内容更新其预测。只要我们有足够的内存,它甚至可以随着时间对模式进行建模。

猜字母有什么意义?

预测故事中的下一个字母可能似乎毫无用处。那它到底有什么用呢?

一种很酷的用途是可以自动预测手机键盘:

下一个最可能的字母是“ t”

但是,如果我们将这个想法发挥到极致呢?如果我们要求模型不断地预测下一个最可能出现的角色,该怎么办?我们会要求它为我们写一个完整的故事!

生成一个故事

我们看到了如何猜测海明威句子中的下一个字母。让我们尝试以海明威风格制作一个完整的故事。

要做到这一点,我们将使用递归神经网络实现的是“Andrej Karpathy”写道。Andrej是斯坦福大学的深度学习研究员,他撰写了一篇出色的介绍,介绍了如何使用RNN生成文本。您可以在github上查看该模型的所有代码(后台回复github获取代码)。

我们将从“太阳照常升起”的完整文本中创建模型-362,239个字符,使用84个唯一字母(包括标点符号,大写/小写字母等)。与典型的实际应用程序相比,该数据集实际上很小。为了生成一个真正好的海明威风格模型,最好具有几倍的示例文本。但这足以作为示例。

当我们刚刚开始训练RNN时,预测字母并不是很好。这是经过100次循环训练后产生的结果:

您可以看到,它已经发现有时候单词之间有空格。

经过大约1000次迭代,优化了很多:

该模型已开始识别基本句子结构中的模式。它在句子甚至引用对话框的末尾添加句点。可以识别一些单词,但是仍然有很多废话。

但是经过数千次训练迭代后,它看起来还不错:

至此,该算法已捕获了海明威简短直接对话的基本模式。几句话甚至说得通。

将其与书中的一些真实文本进行比较:

即使一次只寻找一个字符的图案,我们的算法也以正确的格式重现了看起来似是而非的散文。太神奇了!

我们也不必完全从头开始生成文本。我们可以通过提供前几个字母,然后让它找到下几个字母来播种算法。

为了好玩,让我们通过使用“ Er”,“ He”和“ S”的文本生成一个新的作者姓名和一个新的标题,为虚构的书制作一个假书的封面:

真正的书在左边,而计算机生成的废话在右边。

看起来不错!

但是真正令人兴奋的部分是,该算法可以找出任何数据序列中的模式。它可以轻松生成真实的食谱或虚假的奥巴马演讲。但是,为什么要限制自己的人类语言呢?我们可以将相同的思想应用于具有模式的任何类型的顺序数据。

2015年,任天堂发布了适用于Wii U游戏系统的Super Mario Maker™。

每个孩子的梦想!

该游戏可让您在游戏板上绘制自己的超级马里奥兄弟关卡,然后将其上传到互联网,以便您的朋友可以通过它们玩。您可以在您的关卡中包含所有原始Mario游戏中的经典道具和敌人。这就像是为乐于玩超级马里奥兄弟的人们而设计的虚拟乐高玩具。

我们可以使用生成假海明威文字的模型来生成假超级马里奥兄弟关卡吗?

首先,我们需要一个数据集来训练我们的模型。让我们从1985年发布的原始《超级马里奥兄弟》游戏中获取所有室外水平:

有史以来最好的圣诞节。谢谢爸爸妈妈!

该游戏共有32个等级,其中约70%具有相同的户外风格。所以我们会坚持下去。

为了获得每个关卡的设计,我制作了游戏的原始副本,并编写了一个程序将关卡设计拉出游戏的内存。超级马里奥兄弟(Super Mario Bros.)已有30年的历史了,在线上有很多资源可以帮助您弄清楚关卡是如何存储在游戏内存中的。从旧的视频游戏中提取关卡数据是一项有趣的编程练习,您应该尝试一下。

这是游戏的第一个关卡(如果玩过游戏,您可能还记得):

如果仔细观察,我们可以看到该关卡是由一个简单的对象网格组成的:

我们可以像用一个字符序列(每个对象代表一个字符)一样容易地表示此网格:

--------------------------
--------------------------
--------------------------
#??#----------------------
--------------------------
--------------------------
--------------------------
-##------=--=----------==-
--------==--==--------===-
-------===--===------====-
------====--====----=====-
=========================-
我们用一个字母替换了关卡中的每个对象:

  • “-”是空格

  • '='是一个固体块

  • '#'是易碎的砖块

  • '?' 是一个硬币块

…依此类推,对关卡中每种不同的对象使用不同的字母。

我最终得到的文本文件如下所示:

查看文本文件,可以看到逐行阅读Mario关卡的方式实际上并不多:

逐行阅读,实际上没有可捕获的模式。许多行是完全空白的。

当您将级别视为一系列列时,级别中的模式才真正出现:

逐列查看,这是一个真实的模式。例如,每列以'='结尾。

因此,为了使算法能够在我们的数据中找到模式,我们需要逐列提供数据。弄清楚输入数据的最有效表示形式(称为功能选择)是正确使用机器学习算法的关键之一。

要训练模型,我需要将文本文件旋转90度。这样可以确保将字符按照更容易显示图案的顺序输入到模型中:

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

就像我们在创建海明威散文模型时所看到的那样,模型在训练过程中不断完善。

经过一些训练后,我们的模型产生了垃圾:

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

它有点想法,“-”和“ =”应该出现很多,仅此而已。它尚未弄清楚模式。

经过数千次迭代,它开始看起来像:

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

该模型几乎计算出每行的长度应相同。它甚至已经开始弄清楚Mario的一些逻辑:mario中的管道总是两个块宽,至少两个块高,因此数据中的“ P”应该出现在2x2群集中。太酷了!

经过大量的培训,模型达到了生成完全有效数据的地步:

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

让我们从模型中采样整个级别的数据,然后将其旋转回水平:

这个数据看起来很棒!有几件事要注意:

  • 它在关卡开始时将Lakitu(漂浮在云上的怪物)放在天空中–就像在真正的马里奥关卡中一样。

  • 它知道漂浮在空中的管道应该放在坚固的块体上,而不仅仅是悬挂在空中。

  • 它将敌人放置在合乎逻辑的地方。

  • 它不会产生任何阻碍玩家前进的东西。

  • 感觉就像从超级马里奥兄弟1真实水平,因为它是基于关闭该在那场比赛中存在的原始水平的风格。

最后,让我们采用此级别并在Super Mario Maker中重新创建它:

输入Super Mario Maker后的关卡数据

自己玩!

如果您拥有Super Mario Maker,则可以通过在线对其进行书签或使用级别代码4AC9–0000–0157-F3C3进行查找来播放此级别。

玩具是真实世界的应用?

我们用于训练模型的递归神经网络算法与现实世界中的公司用于解决诸如语音检测和语言翻译之类的难题的算法相同。使我们的模型成为“玩具”而不是尖端技术的原因是,我们的模型是从很少的数据生成的。最初的《超级马里奥兄弟》游戏没有足够的关卡,无法为真正好的模型提供足够的数据。

如果我们可以访问任天堂拥有的成千上万个用户创建的超级马里奥制造商级别,那么我们可以做一个令人惊叹的模型。但是我们不能-因为任天堂不会让我们拥有它们。大公司不会免费提供其数据。

随着机器学习在更多行业中变得越来越重要,好的程序和不好的程序之间的区别将在于,您必须训练模型多少数据。这就是为什么像Google和Facebook这样的公司非常需要您的数据的原因!

例如,谷歌最近开放了TensorFlow的源代码,它的软件工具包用于构建大型机器学习应用程序。Google免费提供了如此重要且功能强大的技术,这是一笔不小的数目。这与为Google翻译提供支持的功能相同。

但是,如果没有Google每种语言的海量数据,您就无法与Google Translate竞争。数据是让Google脱颖而出的原因。下次打开您的Google Maps位置记录或Facebook位置记录时,请考虑一下,请注意,它存储了您去过的每个地方。

在机器学习中,从来没有一种解决问题的方法。在决定如何预处理数据以及使用哪种算法时,您有无限的选择。通常,将多种方法结合起来会比任何一种方法提供更好的结果。

读者给我发送了其他链接来生成超级马里奥关卡的有趣方法:

  • 贾斯汀·米肖(Justin Michaud)扩展了我在这里使用的生成关卡的方法,并弄清楚了如何将其生成的关卡破解回原始NES rom文件(30年前编写的代码)!您甚至可以在线播放他被黑的rom。

  • 艾米·胡佛(Amy K. Hoover)的小组使用了一种方法来表示每种类型的关卡对象(管道,地面,平台等),就好像它是整个交响乐中的单一声音一样。使用称为功能支架的过程,系统可以使用任何给定对象类型的块来增加级别。例如,您可以绘制关卡的基本形状,并可以添加管道和问题块来完成设计。

  • 史蒂夫·达尔斯科格(Steve Dahlskog)的团队表明,将级别数据的每一列建模为一系列n-gram“单词” ,从而可以通过比大型RNN 更简单的算法来生成级别。



1.机器学习原来这么有趣!【第一章】

2.【原创】机器学习从零开始系列连载(1)——基本概念

3.【原创】机器学习从零开始系列连载(2)——线性回归

扫描个人微信号,

拉你进机器学习大牛群。

福利满满,名额已不多…

(0)

相关推荐