编者按:在科技圈,如果你不懂“机器学习”,那你就 out 了。当别人在谈论机器学习娓娓道来时,你却一头雾水,怎么办?在跟同事的聊天中,你只能频频点头却插不上话,怎么办?让我们来做些改变!Adam Geitgey 撰写了一份简单易懂的《机器学习,乐趣无限》的资料,共分为5个部分,主要针对所有对“机器学习”感兴趣,却苦于不知从何下手的朋友,希望能借此让更多人认识了解“机器学习”,激发其对“机器学习”的兴趣。本文为第四篇。
不知道你有没有留意,Facebook现在有了一个令人非常不可思议的功能——它能在你的图库中识别出你的朋友!
过去,Facebook会让你自己在照片中标记出你的朋友,你需要点击你朋友的脸,并输入他们的名字。现在,每当你上传一张照片,Facebook就会发挥它的“魔力”,自动帮你标记出照片中的所有人。
(Facebook能在照片上传后,自动标记出照片中你之前设置过标记的人。不可思议!我也不能确定这到底算是个平常的实用功能,还是个神奇得令人毛骨悚然的功能。)
这就是“人脸识别技术”。照片中你朋友的脸只需要被标记过几次以后,Facebook的算法就能够在下次照片上传后,迅速识别出你朋友的脸。这是个令人相当不可思议的技术!Facebook能够进行人脸识别,并且准确率达到了98%,与人类自己的识别准确率相当。
那么接下来,我们就试着研究一下这个现代“人脸识别技术”是怎么工作的吧!但仅仅识别你的朋友太简单了,我们可以把这项技术推到极致,让它去解决一个更加具有挑战性的问题——把Will Ferrell(著名演员)与Chad Smith(著名的摇滚音乐家)区分开来!
(这两人其中一位是Will Ferrell,另一位是Chad Smith。我发誓,这绝对是两个不同的人。)
如何在一个非常复杂的问题中使用“机器学习”?
目前为止,在这部教程的前三个部分中,我们已经试着用机器学习去解决了只包含一个步骤的、独立的问题,比如说预估房子的价格;根据已有的数据创造出更多新的数据;以及判断出一张图片中是否包含一个特定的对象。这些问题都能通过选择一个机器学习算法,输入数据后得到结果的步骤来解决。
但是,“人脸识别”涉及的是一系列相互关联的问题:
1.首先,我们要找出一张照片上面所有的脸
2.第二,关注到每一张脸,无论这些脸的角度多么奇怪,或者光线多暗,都要能够判断出这些脸始终是同一个人。
3.第三,要能够抓住一张脸的独特的特征,这样才能将它与其他人脸区别,比如眼睛有多大,脸有多长,等等。
4.最后,把这些脸部特征与你已经知晓的人连比较,判断出人的名字。
作为一个人,你的大脑能够立刻连续地、自动地完成以上所有的步骤。事实上,人类是非常擅长识别人脸,所以我们总能在日常生活的物体中发现人脸的。
计算机还没有,至少现在还没有,这种高水平的概括泛化能力,所以我们需要单独教它们在这个过程中完成每一个步骤。
我们需要建立一个“流水线”来单独完成人脸识别的每一个步骤,并且把上一个步骤的结果传送至下一步。换句话来说,我们将要把几个机器学习算法链接在一起:
(这就是一个基础的人脸识别“流水线”的工作过程)
人脸识别——步步进击
接下来,我们试着一步一步地解决这个问题。针对每一步,我们都将学习一个不同的机器学习算法。为了避免这个教程变成一本死板的教科书,我不会对每个算法进行逐一、详细地解释,但是你能够了解每个算法的主要内容,并且掌握使用OpenFace和dlib在Python中建立你自己的人脸识别系统的方法。
步骤一:找出所有的“脸”
我们这个“流水线”的第一步就是“人脸检测”。在我们区分每个人脸之前,当然,我们必须首先确定照片中的所有人脸。在过去的十年内,如果你用过任何一款相机,那么你可能就已经见识了“人脸检测”:
“人脸检测”是相机的最重要的功能和特征。
一个相机如果能够自动检测出人脸,那么它就会在拍照前将镜头内所有的人脸聚焦。但是我们这一步将会把这个脸部检测技术用在别处——选出我们将传送至“流水线”下一个步骤中使用的图像区域。
实际上,“人脸检测”早在20世纪初就已经成为了主流,那时Paul Viola和Michael Jones发现了一种人脸检测的方法,这一方法能够以较快的速度在相对廉价的相机上使用。但是相比之前,我们现在有了更多更可靠的解决方法。在这些方法中,我们将使用一种发明于2005年的,叫做“方向梯度直方图(HOG)”的方法。
为了找到图片中的人脸,我们将把图片设置为黑白,因为我们在人脸检测的时候是不需要考虑图片颜色的:
接下来,我们将依次观察这张图片中的每一个像素。对于每一个像素,我们需要观察紧挨着这一单个像素的周围像素——直接周边像素:
我们的目标就是看看当前像素与其直接周边像素相比下的暗度,之后我们会画出一个箭头用于指示像素变暗的方向:
(先只观察这一个像素和紧挨着它的其他像素,我们发现越往右上方,这张图片的颜色就越暗。)
如果你对照片中的每一个像素都重复这一流程,那么最后你将会得到每一个像素都被一个箭头所替代的图像。这些箭头显示了整张图片从亮到暗的梯度变化,被称为“梯度渐变”。
这种方法可能看上去像是胡乱而为的,但是实际上使用“梯度渐变”的箭头代替图片中的像素有着非常重要的意义。如果我们直接分析像素,会出现这种情况:同一个人的两张照片,非常暗和非常亮的照片会显示出完全不同的像素值,但是这两张照片中都是同一个人。然而,如果仅考虑图片亮度的变化方向,那么非常暗和非常亮的两张照片最终都会得到一个相同的表示。考虑到这两个方面,那么我们的问题就更容易解决了。
但是,把每一个像素点的梯度渐变都保存下来太过冗杂了,我们最后会“只见树木不见森林”,错失整体。更好的做法是,我们从一个高的角度只看图像亮度或者暗度的基本变化方向,这样我们就能看到一张图像亮度变化的基本模式了。
为了做到这点,我们将把这张图片分成每个为16*16像素的小正方形。在每一个小正方形图片了,我们将数出每个主要方向的渐变箭头的数量(比如正上方方向的渐变箭头的数量;右上方方向的渐变箭头数量;右方方向......)。接着,我们将用一个个大的方向箭头代替图片中的小正方形。
最后的结果是,我们把原始的图片转换成了一个非常简单的表示,这个表示通过一种简单的方法抓住了一张脸的基本构造:
(这张原始图片被转换成了一个HOG图示,这个HOG图示在不考虑图片亮度的情况下抓住了图片的主要特征)
HOG人脸模式是从一堆人脸训练数据中提取出来的,为了在这个HOG图像里成功找到人脸,我们需要做的是找到我们这张图片中与已知HOG人脸模式相似度最高的那一部分:
运用这种技术,我们现在就能轻易地在任何一张图片中识别出人脸了:
如果你想使用Python和dlib自己尝试这个步骤,以上就是告诉你如何生成和查看图片的HOG图示的秘方。
步骤二:摆放和突出人脸
我们之前是单独观察图片中的人脸,但是现在我们需要解决这样的问题:同一个人的人脸转到不同的方向,在计算机看来就是完全不同的两张脸:
(人当然可以轻易地判断出两张图片中的都是Will Ferrell,但是计算机做不到,它会把这些照片中的人看作是完全不同的两个人。)
为了更好地解释这一点,我们将尝试把每一张图片变形,让眼睛和嘴巴始终处在图像中的示例位置,这种处理会令下一步中的脸部比较更容易进行。这时,我们需要用到一种叫做“人脸关键点检测”的算法。在众多方法中,我们选择使用一个由Vahid Kazemi和Josephine Sullivan在2014年发明的方法。
这个方法的基本内容就是:我们将在每张人脸中选出68个特定的点(称作“关键点”),比如说下巴的顶部;每只眼睛的外缘;每条眉毛的内缘,等等。之后,我们就会训练一个机器学习算法,让它能在任何脸上都能找到这68个特定的点:
(这就是我们将会定位的68个面部标志点。这张图片是由工作于 OpenFace的卡耐基梅隆大学学生Brandon Amos创建的。)
以下是在我们的测试图片中定位的68个人脸关键点的结果:
(小贴士:你也可以使用这一技术设计一款属于你自己的Snapchat实时3D人脸滤镜。)
既然现在已经知道了眼睛和嘴巴的位置,那么接下来我们将对这张图片稍微进行旋转,缩放和裁剪,让眼睛和嘴巴尽可能地处在图像的中心。我们不会做任何过多的3D变形,因为那样会造成图像的扭曲,所以我们只需要使用一些基础的图像转换方式,比如旋转和能够保持平行线的裁剪(被称为“仿射转换”):
现在,不论这张脸的方向怎么变化,我们都能让眼睛和嘴巴大致处于图像的中心位置,这一操作会使我们的下一个步骤更加精确。
如果你想使用Python和dlib自己尝试这个步骤,以上就是让你找到人脸关键点,以及使用这些标志点进行图像转化的秘诀。
步骤三:对人脸进行编码
接下来我们就要进入问题的关键步骤了——把不同的人脸区分开来。这也是最有趣的部分!
最简单的人脸识别方法就是将我们在步骤二中找到的未知人脸与图片中所有已经被标签了的人脸直接进行比较。当我们发现一个之前已经被标记了的人脸与我们的未知人脸非常相像时,那他们就一定就是最匹配的了。听起来是个相当不错的方法,对吗?
但是事实上,这种方法存在着很大的问题。一个有着数百万用户和数亿照片的网站,例如Facebook,是不可能将已标签的照片依次与每一张新上传的照片进行比较的,这样的工作量会非常大。毕竟他们需要在毫秒内迅速识别出人脸,而不是数个小时内。
所以,我们需要一种能够帮助我们从每一张脸中提取出一些基本的度量指标的方法,然后我们可以通过相同的方式来对我们照片中的未知脸进行量度,并且依据最接近的度量指标找出我们之前已标签的人脸。举个例子来说,我们可以度量每只耳朵的大小、两只眼睛的间距、鼻子的长度等等。如果你有看过类似CSI(《犯罪现场调查》)的犯罪节目,那你就能理解我所说的了:
(就像电视剧里一样!看起来特别的真实!#科学)
量度一张脸的最靠谱方法
那么,我们到底要收集一张脸的哪些部分作为度量点,从而建立起我们的“已标签脸”的数据库呢?耳朵大小?鼻子长度?眼睛颜色?还是其他的呢?
结果是,有些度量的点对于我们人类来说是看起来很明显、突出的,比如眼睛的颜色;但是对那些查看图片的单个像素的计算机来说却不是这么回事。研究人员发现,最好的方法是让计算机自己找出判别性高的脸部特征并收集它们 。在这个方面,深度学习可比人类在行多了。
我们需要训练一个“深度卷积神经网络”(我们在此教程的第三部分中曾经介绍过的)。但是我们不会像上次训练一个网络去识别图片中的对象;而是让它针对每张脸,分别生成128个特征。
在这个训练过程中,我们会一次查看三张人脸图片:
1.输入一张已标签人物的图片作为训练图片(一号图片);
2.输入另外一张同一个已标签人物的图片(二号图片);
3.输入一张其他人的图片(三号图片)。
接着,算法就开始生成每张图片的度量指标,它会不断调整神经网络的参数,以确保一号图片和二号图片的度量指标是相对接近的,同时也确保二号图片和三号图片的度量指标是相对疏离的 。
在数千个不同人物的数百万张照片中不停地重复这个步骤后,逐渐地,神经网络就能对每个人物生成128个相对有判别性的特征了。同一个人的任意十张不同照片是有大致相同的特征的。
机器学习研究者把每张脸的这128个特征称作“嵌入(embedding)”,在机器学习里(尤其是在语言翻译方面),我们经常希望缩减复杂的原始数据(比如一张图片转换为一串电脑生成的数字)。我们所使用的方法是由谷歌的研究人员在2015年发明的,但类似的方法其实还有很多。
对人脸图像进行编码
训练一个卷积神经网络,让它输出人脸的特征——“嵌入(embedding)”,这一过程需要大量的数据和计算机力量。就算是一个昂贵的英伟达Telsa显卡,它也需要大概24个小时的不间断训练,以达到更高的精确度。
但是这个网络一旦完成了所有的训练,它就能对任意的人脸(就算是之前从未见过的人脸)生成有用的特征。因此,这一步只需要完成一次。幸运的是,OpenFace的研究者已经替我们完成了这一步,他们还发布了一些训练完毕的网络直接供我们使用。感谢Brandon Amos和他的团队!
所以我们自己需要做的就是把我们的人脸图片输入他们的预训练好的网络,然后得到每张人脸的128个特征。以下是我们测试图片得到的衡量指标:
所以这128个数字测量的到底是人脸的哪些部分呢?事实上我们也不清楚,而且与我们来说这些都是无关紧要的。我们真正关心的是,这个网络对一个人的两张不同照片,生成的是几乎完全相同的指数。
如果你想要自己尝试这一步骤,OpenFace会提供一个能够对文件夹里的所有图片生成嵌入,并且将其编写入csv文件中的lua脚本。你可以参照上面的操作运行这个脚本。
步骤四:从编码中找到人物的名字
最后一步其实是整个流程中最简单的一步,我们需要做的就是找到我们数据库中已标签人物中与我们测试图片中的人物的度量指标最接近的人。你可以使用任何一个基础的机器学习分类算法来完成这一操作,不需要复杂的深度学习技巧。有非常多的分类算法能够完成这一操作,我们选择的是一个简单的线性SVM分类器。
我们需要训练这个分类器,让它能收入新测试图片的度量指标,并且找出最接近、最匹配的已标签人物。运行这个分类器只需要数毫秒,其最终输出结果就是我们图像中的人物的名字!
那么我们就来试验一下我们的系统。首先,我用Will Ferrell、Chad Smith和Jimmy Falon三个人的,每人大约20张图片作为训练数据,用上面的神经网络提取它们的嵌入,训练了一个分类器:
(超萌的训练数据!)
然后,我把这个分类器运行于Will Ferrell和Chad Smith的视频的每一帧,在这“Jimmy Show”视频里,他们互相假扮对方。
成功了!看,对处于不同位置的人脸,就算是侧脸,它也同样能够运行得非常好!
自己动手,丰衣足食
让我们来回顾一下上面步骤:
1.使用HOG算法创建一个图片的简化版,然后对一张图片进行编码。用这个简化版图像,找到图像中与通用的HOG人脸编码最接近的部分。
2.通过定位人脸的主要关键点,得出人脸的位置。找到了那些关键点以后,对图像做些变形,让眼睛和嘴巴处于图片中间。
3.把这个人脸为中心的图片输入至一个能够检测脸部特征的神经网络,保存输出的128个特征。
4.观察我们之前检测过的所有人脸,找到那个与我们的人脸度量指标最接近的人,他就是我们要找的最佳匹配人选啦!
现在,相信你应该已经大致了解了人脸识别技术的全部工作流程了,以上就是你在计算机上使用OpenFace运行这整个人脸识别工作流水线时需要注意的内容。
转自:http://36kr.com/p/5063265.html