有趣的机器学习概念纵览:从多元拟合,神经网络到深度学习
笔者自大学以来一直断断续续的学过机器学习啊、自然语言处理啊等等方面的内容,相信基本上每个本科生或者研究生都会接触过这方面,毕竟是一个如此大的Flag。不过同样的,在机器学习,或者更大的一个概念,数据科学这个领域中,同样是学了忘忘了学。不可否认,数学是机器学习的一个基石,但是也是无数人,包括笔者学习机器学习的一个高的门槛,毕竟数学差。而在这篇文章中,原作者并没有讲很多的数学方面的东西,而是以一个有趣实用的方式来介绍机器学习。另一方面,其实很多数学原理也是很有意思的,笔者记得当年看完数学之美有一个不小的感触,就是知道了TF-IDF的计算公式是怎么来的~
What is Machine Learning: Machine Learning的概念与算法介绍
估计你已经厌烦了听身边人高谈阔论什么机器学习、深度学习但是自己摸不着头脑,这篇文章就由浅入深高屋建瓴地给你介绍一下机器学习的方方面面。本文的主旨即是让每个对机器学习的人都有所得,因此你也不能指望在这篇文章中学到太多高深的东西。言归正传,我们先来看看到底什么是机器学习:
Machine learning is the idea that there are generic algorithms that can tell you something interesting about a set of data without you having to write any custom code specific to the problem. Instead of writing code, you feed data to the generic algorithm and it builds its own logic based on the data.
笔者在这里放了原作者的英文描述,以帮助更好地理解。Machine Learning即是指能够帮你从数据中寻找到感兴趣的部分而不需要编写特定的问题解决方案的通用算法的集合。通用的算法可以根据你不同的输入数据来自动地构建面向数据集合最优的处理逻辑。举例而言,算法中一个大的分类即分类算法,它可以将数据分类到不同的组合中。而可以用来识别手写数字的算法自然也能用来识别垃圾邮件,只不过对于数据特征的提取方法不同。相同的算法输入不同的数据就能够用来处理不同的分类逻辑。
Two kinds of Machine Learning Algorithms: 两类机器学习算法
粗浅的划分,可以认为机器学习攘括的算法主要分为有监督学习与无监督学习,概念不难,但是很重要。
Supervised Learning: 有监督学习
假设你是一位成功的房地产中介,你的事业正在蒸蒸日上,现在打算雇佣更多的中介来帮你一起工作。不过问题来了,你可以一眼看出某个房子到底估值集合,而你的实习生们可没你这个本事。为了帮你的实习生尽快适应这份工作,你打算写个小的APP来帮他们根据房子的尺寸、邻居以及之前卖的类似的屋子的价格来评估这个屋子值多少钱。因此你翻阅了之前的资料,总结成了下表:
Unsupervised Learning: 无监督学习
我们再回到最初的那个问题,如果你现在不知道每个房间的售价,而只知道房间大小、尺寸以及临近的地方,那咋办呢?这个时候,就是无监督学习派上用场的时候了。
另外你也可以利用无监督学习发现些特殊的房产,譬如一栋大厦,和其他你售卖的屋子差别很大,销售策略也不同,不过呢却能让你收获更多的佣金。本文下面会更多的关注于有监督学习,不过千万不能觉得无监督学习就无关紧要了。实际上,在大数据时代,无监督学习反而越来越重要,因为它不需要标注很多的测试数据。
House Price Estimation With Supervised Learning: 利用监督学习进行房屋价格估计
作为高等智慧生物,人类可以自动地从环境与经历中进行学习,所谓熟读唐诗三百首,不会做诗也会吟,你房子卖多了那自然而然看到了某个屋子也就能知道价格以及该卖给啥样的人了。这个 Strong_AI 项目也就是希望能够将人类的这种能力复制到计算机上。不过目前的机器学习算法还没这么智能,它们只能面向一些特定的有一定限制的问题。因此, Learning 这个概念,在这里更应该描述为:基于某些测试数据找出解决某个问题的等式,笔者也喜欢描述为对于数据的非线性拟合。希望五十年后看到这篇文章的人,能够推翻这个论述。
Let’s Write the Program
基本的思想很好理解,下面就开始简单的实战咯。这里假设你还没写过任何机器学习的算法,那么直观的来说,我们可以编写一些简单的条件判断语句来进行房屋价格预测,譬如:
这就是典型的简答的基于经验的条件式判断,你也能通过这种方法得出一个较好地模型。不过如果数据多了或者价格发生较大波动的时候,你就有心无力了。而应用机器学习算法则是让计算机去帮你总结出这个规律,大概如下所示:
通俗的理解,价格好比一锅炖汤,而卧室的数量、客厅面积以及邻近的街区就是食材,计算机帮你自动地根据不同的食材炖出不同的汤来。如果你是喜欢数学的,那就好比有三个自变量的方程,代码表述的话大概是下面这个样子:
注意,上面那些譬如.841…这样奇怪的数据,它们就是被称为权重,只要我们能根据数据寻找出最合适的权重,那我们的函数就能较好地预测出房屋的价格。
Weights
首先,我们用一个比较机械式的方法来寻找最佳的权重。
Step 1
首先将所有的权重设置为1:
Step 2
拿已知的数据来跑一波,看看预测出来的值和真实值之间有多少差距,大概效果如下所示:
Step 3
不断测试不同的权重的组合,从而找出其中最靠近零的一组。
Mind Blowage Time
很简单,不是吗?让我们再回顾下你刚才做了啥,拿了一些数据,通过三个泛化的简单的步骤获取一个预测值,不过在进一步优化之前,我们先来讨论一些小小的思考:
- 过去40年来,包括语言学、翻译等等在内的很多领域都证明了通用的学习算法也能表现出色,尽管这些算法本身看上去毫无意义。
- 刚才咱写的那个函数也是所谓的无声的,即函数中,并不知道卧室数目bedrooms、客厅大小square_feet这些变量到底是啥意思,它只知道输入某些数字然后得出一个值。这一点就很明显地和那些面向特定的业务逻辑的处理程序有很大区别。
- 估计你是猜不到哪些权重才是最合适的,或许你连自己为啥要这么写函数都不能理解,虽然你能证明这么写就是有用的。
- 如果我们把参数 sqft 改成了图片中的像素的敏感度,那么原来输出的值是所谓的价格,而现在的值就是所谓的图片的类型,输入的不同,输出值的意义也就可以不一样。
Try every number?
言归正传,我们还是回到寻找最优的权重组合上来。你可以选择去带入所有的可能的权重组合,很明显是无穷大的一个组合,这条路肯定是行不通的。是时候展示一波数学的魅力了,这里我们介绍一个数学中常见的优化求值的方法:
首先,我们将Step 2中提出的代价方程公式化为如下形式:
如果你是打算找个机器学习的工具库来辅助工具,那么到这里你的知识储备已经差不多咯,下面我们再扯扯其他的东西。
Something Skip Over: 刚才没提到的一些东西
上文提到的所谓三步的算法,用专业的名词表述应该是多元线性回归。即通过输入含有多个自变量的训练数据获得一个有效的计算表达式用于预测未来的部分房屋的价格。但是上面所讲的还是一个非常简单的例子,可能并不能在真实的环境中完美地工作,这时候就会需要下文即将介绍的包括神级网络、SVM等等更复杂一点的算法了。另外,我还没提到一个概念:overfitting(过拟合)。在很多情况下,只要有充足的时间我们都能得到一组在训练数据集上工作完美的权重组合,但是一旦它们用于预测,就会跌破眼镜,这就是所谓的过拟合问题。同样的,关于这方面也有很多的方法可以解决,譬如 正则化 或者使用 交叉验证 。
一言以蔽之,尽管基础的概念非常简单,仍然会需要一些技巧或者经验来让整个模型更好地工作,就好像一个才学完Java基础的菜鸟和一个十年的老司机一样。
Further Reading: 深入阅读
可能看完了这些,觉着ML好简单啊,那这么简单的东西又是如何应用到图片识别等等复杂的领域的呢?你可能会觉得可以用机器学习来解决任何问题,只要你有足够多的数据。不过还是要泼点冷水,千万记住,机器学习的算法只在你有足够的解决某个特定的问题的数据的时候才能真正起作用。譬如,如果你想依靠某个屋子内盆栽的数目来预测某个屋子的价格,呵呵。这是因为房屋的价格和里面的盆栽数目没啥必然联系,不管你怎么尝试,输入怎么多的数据,可能都不能如你所愿。
Neural Network: 神级网络
上文中,我们通过一个简单的房价预测的例子了解了机器学习的基本含义,在本节,我们将会继续用一些泛化的算法搭配上一些特定的数据做些有趣的事情。本节的例子大概如下图所示,一个很多人的童年必备的游戏:马里奥,让我们用神级网络帮你设计一些新奇的关卡吧。
上文中我们是使用了多元线性回归来进行房屋价格预测,数据格式大概这个样子:
如果用图来表示的话,大概是这个样子:
What is Neural Network?: 神经网络初识
我们将上文提到的两个步骤合并起来,大概如下图所示:
- 每个能够接收一系列的输入并且能够按权重求和的估值函数被称为Neuron(神经元)
- 多个简单的神经元的连接可以用来构造处理复杂问题的模型
有点像乐高方块,单个的乐高方块非常简单,而大量的乐高方块却可以构建出任何形状的物体:
Giving Our Neural Network a Memory: 给神级网络加点上下文
目前,整个神级网络是无状态的,即对于任何相同的输入都返回相同的输出。这个特性在很多情况下,譬如房屋价格估计中是不错的,不过这种模式并不能处理时间序列的数据。举个栗子,我们常用的输入法中有个智能联想的功能,可以根据用户输入的前几个字符预测下一个可能的输入字符。最简单的,可以根据常见的语法来推测下一个出现的字符,而我们也可以根据用户历史输入的记录来推测下一个出现的字符。基于这些考虑,我们的神经网络模型即如下所示:
Robert Cohn was once middleweight boxi
你可能会猜想是 n ,这样整个词汇就是 boxing ,这是基于你看过了前面的语句以及基本的英文语法得出的推论,另外, middleweight 这个单词也给了我们额外的提示,跟在它后面的是 boxing 。换言之,在文本预测中,如果你能将句子的上下文也考虑进来,再加上基本的语法知识就能较为准确地预测出下一个可能的字符。因此,我们需要给上面描述的神经网络模型添加一些状态信息,也就是所谓的上下文的信息:
Generating a story: 生成一个完整的故事
正如上文所说,文本预测在实际应用中一个典型的例子就是输入法,譬如iPhone里面会根据你之前输入的字符自动帮你补全:
惨不忍睹啊,继续进行训练,大概1000次迭代之后,内容看起来好一点了:
已经能够识别基本的句型结构与语法规则咯,甚至能够较好地为上下文添加标点符号了,不过还是存在着大量的无意义词汇,我们继续增加训练的次数:
现在差不多能看了,有些句式还是很模仿Hemingway’s的风格的,而原作者的内容是:
Super Mario: 利用神级网络进行Mario过关训练
In 2015, Nintendo 宣布了 Super Mario Maker™ 用于Wii U游戏系统上。
其中:
– 代表空白
= 代表坚固的方块
# 代表那些可以被撞破的块
? 代表钱币块
然后就可以使用上面创建好的模型进行训练咯,经过几轮训练之后大概可以得出这个样子:
最初的训练里模型认知到应该大量的出现 – 与 = 字符,不过还是很粗糙,再经过几千次的训练,得出的内容是:
此时模型已经能够认知到需要将每行保证相同的长度,甚至开始寻找出Mario内在的规律:管道呢一般都是两个块这么宽,所以它将所有的 P 都放到了2*2的矩阵中,聪明了一点啊。继续学习:
- Lakitu,就是那个小怪兽被放到了半空中,跟Mario关卡一样一样的。
- 它认知到了应该把管道插入大地
- 并没有让玩家无路可走
- 看起来风格非常像最传统的马里奥的版本
最后生成出来的游戏截图大概是这样的:
Toys VS Real World Applications
这里用于训练模型的循环神经网络算法与真实环境下大公司用于解决语音识别以及文本翻译等常见问题的算法一本同源,而让我们的模型看上去好像个玩具一样的原因在于我们的训练数据。仅仅取自最早期的超级马里奥的一些关卡数据远远不足以让我们的模型出类拔萃。如果我们能够获取由其他玩家创建的成百上千的关卡信息,我们可以让模型变得更加完善。不过可惜的是我们压根获取不到这些数据。
随着机器学习在不同的产业中变得日渐重要,好的程序与坏的程序之间的差异越发体现在输入数据的多少。这也就是为啥像Google或者Facebook这样的大公司千方百计地想获取你的数据。譬如Google最近开源的 TensorFlow ,一个用于大规模可扩展的机器学习的集群搭建应用,它本身就是Google内部集群的重要组成部分。不过没有Google的海量数据作为辅助,你压根创建不了媲美于Google翻译那样的牛逼程序。下次你再打开 Google Maps Location History 或者 Facebook Location History ,想想它们是不是记录下你日常的东西。
Further Reading
条条大道通罗马,在机器学习中解决问题的办法也永远不止一个。你可以有很多的选项来决定如何进行数据预处理以及应该用啥算法。 增强学习 正是可以帮你将多个单一的方法组合起来的好途径。如果你想更深入的了解,你可以参考下面几篇较为专业的论文:
- Amy K. Hoover ’s team used an approach that represents each type of level object (pipes, ground, platforms, etc) as if it were single voice in an overall symphony . Using a process called functional scaffolding, the system can augment levels with blocks of any given object type. For example, you could sketch out the basic shape of a level and it could add in pipes and question blocks to complete your design.
- Steve Dahlskog ’s team showed that modeling each column of level data as a series of n-gram “words” makes it possible to generate levels with a much simpler algorithm than a large RNN.
Object Recognition In Images With Deep Learning: 利用深度学习对于图片中对象进行识别
近年来关于深度学习的讨论非常火爆,特别是之前阿尔法狗大战李世乭之后,更是引发了人们广泛地兴趣。南大的周志华教授在《机器学习》这本书的引言里,提到了他对于深度学习的看法:深度学习掀起的热潮也许大过它本身真正的贡献,在理论和技术上并没有太大的创新,只不过是由于硬件技术的革命,从而得到比过去更精细的结果。相信读者看完了第三部分也会有所感。
仁者见仁智者见智,这一章节就让我们一起揭开深度学习的神秘面纱。在本章中,我们还是基于一个实际的例子来介绍下深度学习的大概原理,这里我们会使用简单的卷积神级网络来进行图片中的对象识别。换言之,就类似于Google Photos的以图搜图的简单实现,大概最终的产品功能是这个样子的:
Recognizing Objects: 对象识别
先来看一个有趣的漫画:
Starting Simple: 先来点简单的
在尝试怎么识别照片中的鸟儿之前,我们先从一些简单的识别开始:怎么识别手写的数字8。在上一章节,我们了解了神级网络是如何通过链式连接组合大量的简单的neurons(神经元)来解决一些复杂的问题。我们创建了一个简单的神级网络来基于床铺数目、房间大小以及邻居的类型来预测某个屋子的可能的价格。
大量的数据是机器学习不可代替的前提条件与基石,首先我们需要去寻找很多的训练数据。索性对于这个问题的研究已持续了很久,也有很多的开源数据集合,譬如MNIST关于手写数字的数据集 。MNIST提供了60000张不同的关于手写数字的图片,每个都是18*18的大小,其中部分关于8的大概是这个样子:
Tunnel Vision
虽然我们上面一直说这个任务不难,不过也没那么简单。首先,我们的识别器能够对于标准的图片,就是那些数字端端正正坐在中间,不歪不扭的图片,可以非常高效准确地识别,譬如:
1. Searching with a Sliding Window: 基于滑动窗口的搜索
虽然道路很曲折,但是问题还是要解决的,我们先来试试暴力搜索法。我们已经创建了一个可以识别端端正正的8的识别器,我们的第一个思路就是把图片分为一块块地小区域,然后对每个区域进行识别,判断是否属于8,大概思路如下所示:
1. More data and a Deep Neural Net
刚才那个识别器训练的时候,我们只是把部分规规矩矩的图片作为输入的训练数据。不过如果我们选择更多的训练数据时,自然也包含那些七歪八斜的8的图片,会不会起到什么神奇的效果呢?我们甚至不需要去搜集更多的测试数据,只要写个脚本然后把8放到图片不同的位置上即可:
The Solution is Convolution:卷积神经网络
人们在看图片的时候一般都会自带层次分割的眼光,譬如下面这张图:
- 地上覆盖着草皮与水泥
- 有个宝宝
- 宝宝坐在个木马上
- 木马在草地上
更重要的是,不管宝宝坐在啥上面,我们都能一眼看到那嘎达有个宝宝。即使宝宝坐在汽车、飞机上,我们不经过重新的学习也可以一眼分辨出来。可惜现在我们的神经网络还做不到这一点,它会把不同图片里面的8当成不同的东西对待,并不能理解如果在图片中移动8,对于8而言是没有任何改变的。也就意味着对于不同位置的图片仍然需要进行重新学习。我们需要赋予我们的神经网络能够理解平移不变性:不管8出现在图片的哪个地方,它还是那个8。我们打算用所谓的卷积的方法来进行处理,这个概念部分来自于计算机科学,部分来自生物学,譬如神经学家教会猫如何去辨别图片。
How Convolution Works
上面我们提到一个暴力破解的办法是将图片分割到一个又一个的小网格中,我们需要稍微改进下这个办法。
1. 将图片分割为重叠的砖块
譬如上面提到的滑动窗口搜索,我们将原图片分割为独立的小块,大概如下图所示:
2. 将每个图片瓷砖输入到小的神经网络中
之前我们就训练一个小的神经网络可以来判断单个图片是否属于8,不过在这里我们的输出并不是直接判断是不是8,而是处理输出一个特征数组:
3. 将每个小块的处理结果存入一个新的数组
对于每个小块输出的数组,我们希望依然保持图片块之间的相对位置关联,因此我们将每个输出的数组仍然按照之前的图片块的次序排布:
4. 缩减像素采样
上一步的结果是输出一个数组,会映射出原始图片中的哪些部分是我们感兴趣的。不过整个数组还是太大了:
5. 进行预测
截至目前,一个大图片已经转化为了一个相对较小地数组。该数组中只是一系列的数字,因此我们可以将该小数组作为输入传入另一个神经网络,该神经网络会判断该图片是否符合我们的预期判断。为了区别于上面的卷积步骤,我们将此称为 fully connected 网络,整个步骤呢,如下所示:
上面的图片处理过程可以总结为以下步骤:
- Convolution: 卷积
- Max-pooling: 特征各维最大汇总
- Full-connected: 全连接网络
在真实的应用中,这几个步骤可以组合排列使用多次,你可以选择使用两个、三个甚至十个卷积层,也可以在任何时候使用Max-pooling来减少数据的大小。基本的思想就是将一个大图片不断地浓缩直到输出一个单一值。使用更多地卷积步骤,你的网络就可以处理学习更多地特征。举例而言,第一个卷积层可以用于识别锐边,第二个卷积层能够识别尖锐物体中的鸟嘴,而第三个卷积层可以基于其对于鸟嘴的知识识别整个鸟。下图就展示一个更现实点地深度卷积网络:
Building our Bird Classifier: 构建一个真实的鸟儿分类器
概念了解了,下面我们就动手写一个真正的鸟类分类器。同样地,我们需要先收集一些数据。免费的 CIFAR10 data set 包含了关于鸟儿的6000多张图片以及52000张不是鸟类的图片。如果不够, Caltech-UCSD Birds-200–2011 data set 中还有12000张鸟类的图片。其中关于鸟类的图片大概如下所示:
如果你有足够的RAM,譬如Nvidia GeForce GTX 980 Ti或者更好地硬件设备,大概能在1小时内训练结束,如果是普通的电脑,时间要耗费地更久一点。随着一轮一轮地训练,准确度也在不断提高,第一轮中准确率只有75.4%,十轮之后准确率到91.7%,在50轮之后,可以达到95.5%的准确率。
Testing out Network
我们可以使用如下脚本进行图片的分类预测:
How accurate is 95% accurate?: 怎么理解这95%的准确率
刚才有提到,我们的程序有95%的准确度,不过这并不意味着你拿张图片来,就肯定有95%的概率进行准确分类。举个栗子,如果我们的训练数据中有5%的图片是鸟类而其他95%的都不是鸟类,那么就意味着每次预测其实不是鸟类的准确度达到95%。因此,我们不仅要关注整体的分类的准确度,还需要关注分类正确的数目,以及哪些图片分类失败,为啥失败的。这里我们假设预测结果并不是简单的正确或者错误,而是分到不同的类别中:
首先,我们将正确被标识为鸟类的鸟类图片称为:True Positives
via:segmentfault
End.