机器学习原来如此有趣:用深度学习识别人脸

本系列文章目前已经更新两期,分别是:  机器学习原来如此有趣!全世界最简单的机器学习入门指南、  机器学习原来如此有趣:如何故意欺骗神经网络

 

你是否有注意到Facebook最近开发了一个非同寻常的功能:将你照片中的好友识别出来。过去,Facebook 让你手动点击照片上的好友,输入他们的名字,而后加上标签。如今只要你上传一张照片,Facebook就会像变魔术同样为你自动标记出全部人:html

 

这项技术就叫作人脸识别。在你的朋友的脸被标记了几回以后,Facebook的算法就能够识别他了。这是一个让人惊艳的技术--Facebook识别人脸的正确率高达98%!这与人类的表现差很少了。python

 

下面就让咱们来学习一下人脸识别技术是如何实现的!可是只是识别你的朋友的脸就太简单了。 咱们能够最大化扩展这项技术,来解决一个更具挑战性的问题——区分威尔·法瑞尔(Will Ferrell,著名演员)和查德·史密斯(Chad Smith,著名摇滚音乐家)!git

 

 

如何使用机器学习来解决复杂的问题

 

人脸识别由一个系列的相关问题组成:github

 

1.首先:查看一张照片并找出上面全部的脸算法

2.将注意力放在每一张脸上面,即便这张脸被转到奇怪的方向或者是光线很差的状况下也依旧是同一我的。docker

3. 从这张脸上挑出一些特征用于和其余人区分来,好比像眼睛有多大,脸有多长等。数据库

4.最后,将这张脸的特征和其余其余脸做比较,以最后肯定这我的的名字。bash

 

做为一我的类,你的大脑会自动作这些事情。实际上,人类太擅长于识别人脸了,以致于他们在平常物品上面也会试图去寻找脸(好像是这样哦,人们老是喜欢去物品上找出练得形状,而且以为这样很萌)。网络

 

计算机目前并不具有这种高水平的能力。。。因此咱们须要一步步的教他们。app

 

咱们须要构建一个流水线(pipeline):咱们将分别解决人脸识别的每一步,并将当前步骤的结果传入下一个步骤。换句话说,咱们须要将几个机器学习算法链(chain)起来。

 

人脸识别-一步一步来

 

咱们一步一步地解决这个问题。在每个步骤中,咱们都将学习到不一样的机器学习算法。我不会对算法的每一步都进行解释,可是你能够学习到每个算法的主体思想,以及如何在 Python 中使用 OpenFace 和 dlib 来构建一个你本身的面部识别系统。

 

第一步:寻找全部的脸

 

在咱们的流水线中的第一步是人脸检测。很明显在咱们区分人脸以前须要在图片中将脸标记出来。

 

若是你有在最近十年里面用过相机的话,你可能已经见过正在运行中的人脸检测了:

 

面部识别是相机的一个伟大的功能。当相机能够自动挑出面部的时候,这将确保在拍照片的瞬间全部的脸都对准焦点了。不过咱们使用它是为了别的目的--寻找咱们想在下一步要传递的照片区域。

 

2000年年初的时候,当Paul Viola和Michael Jones发明了一种能够在廉价相机上面快速运行的面部检测技术后,人脸检测成为了主流。然而如今更可靠的解决方案出现了。咱们如今用的是2005年发明的一个叫作方向梯度直方图,简称为HOG

 

为了识别出图片中的脸,首先咱们须要将图片转换为黑白色,由于在识别面部的时候咱们不须要颜色数据。

 

而后咱们须要依次遍历图片中的每一个像素。对于单个像素,咱们也须要看直接包围它的其余元素:

 

 

咱们的目标是比较这个像素与周围像素的深度。而后咱们要画一个箭头来表明图像变暗的方向:

 

 

若是你对这个图像中的每一个像素都重复这个过程,最后每一个像素,最终每一个像素会被一个箭头取代。这些箭头被称为梯度(gradients),它们能显示出图像上从明亮到黑暗的流动过程:

 

 

这看起来没有明确的目的,但其实这颇有必要。若是咱们直接分析像素,同一我的明暗不一样的两张照片将具备彻底不一样的像素值。可是若是只考虑亮度变化方向(direction)的话,明暗图像将会有一样的结果。这使得问题变得更容易解决!

 

可是保存每一个像素的梯度太过细节化了,咱们最终颇有可能捡了芝麻丢了西瓜。若是能从更高的角度上观察基本的明暗流动,咱们就能够看出图像的基本规律,这会比以前更好。

 

为了作到这一点,咱们将图像分割成一些 16×16 像素的小方块。在每一个小方块中,咱们将计算出每一个主方向上有多少个梯度(有多少指向上,指向右上,指向右等)。而后咱们将用指向性最强那个方向的箭头来代替原来的那个小方块。

 

最终的结果是,咱们把原始图像转换成了一个很是简单的表达形式,这种表达形式能够用一种简单的方式来捕获面部的基本结构:

 

原始图像被表示成了 HOG 形式,以捕获图像的主要特征,不管图像明暗度如何。

 

为了在这个 HOG 图像中找到脸部,咱们要所须要作的,就是找到咱们的图像中,与已知的一些 HOG 图案中,看起来最类似的部分。这些 HOG 图案都是从其余面部训练数据中提取出来的:

 

使用这种技术,咱们如今能够轻松地在任何图片中找到脸部:

 

 

 

若是你想用 Python 和 dlib 亲手试试看,这些代码显示了如何生成和查看 HOG 图像。

 

第二步:脸部的不一样姿式和方位

 

当当当,咱们把图片中的脸部分离出来了。 但如今,咱们要处理的问题就是,对于电脑来讲,面朝不一样方向的同一张脸是两我的:

人类能够很轻松地识别出到两个图片都是同一我的,但电脑会认为这两张图片是两个彻底不一样的人。

 

为了解决这一点,咱们将试图扭曲每一个图片,使得眼睛和嘴唇老是在图像中的样本位置(sample place)。 这将使咱们在接下来的步骤中,更容易比较脸部之间的不一样。

 

为此,咱们将使用一种称为面部特征点估计(face landmark estimation)的算法。 不少方法均可以作到这一点,但此次咱们会使用由 瓦希德·卡奇米(Vahid Kazemi)和约瑟菲娜·沙利文(Josephine Sullivan)在 2014 年发明的方法

 

基本思路是找到 68 我的脸上广泛存在的特征点( landmarks)——包括下巴的顶部、每只眼睛的外部轮廓、每条眉毛的内部轮廓等。接下来咱们训练一个机器学习算法,让它可以在任何脸部找到这 68 个特定的点:

 

 

咱们将在每一张脸上定位的 68 个特征点。这张图片的做者是在OpenFace工做的卡内基梅隆大学 Ph.D. 布兰东·阿莫斯(Brandon Amos)。

 

这是在测试图片上定位 68 个特征点的结果:

 

你也可使用这一技术来实现本身的 Snapchat 实时 3D 脸部过滤器!

 

如今,咱们知道了眼睛和嘴巴在哪儿,咱们将图像进行旋转、缩放和错切,使得眼睛和嘴巴尽量靠近中心。咱们不会作任何花哨的三维扭曲,由于这会让图像失真。咱们只会使用那些可以保持图片相对平行的基本图像变换,例如旋转和缩放(称为仿射变换):

 

如今不管人脸朝向哪边,咱们都能将眼睛和嘴巴向中间挪动到大体相同的位置。这将使咱们的下一步更加准确。

 

若是你想用 Python 和 dlib 亲手试试看这一步的话,这里有一些代码帮你寻找脸部特征点并用这些特征点完成图像变形

 

第三步:给脸部编码

 

如今咱们要面临最核心的问题了——准确识别不一样的人脸。这才是这件事的有趣之处!

 

最简单的人脸识别方法,是把咱们在第二步中发现的未知人脸,与咱们已经标注了的人脸图片做比较。当咱们发现未知的面孔与一个之前标注过的面孔看起来及其类似的时候,它确定是同一我的。这个想看起来很完美,对吧?

 

实际上这种方法有一个巨大的问题。像 Facebook 这种拥有数十亿用户和数万亿张照片的网站,是不可能去循环比较每张先前标记的脸的,这太浪费时间了。他们须要在毫秒内识别人脸,而不是几个小时。

 

咱们须要的方法是从每张人脸上提取一些基本的测量数值。而后,咱们能够用一样的方式测量未知的面孔,并找到最接近测量数值的那张已知的脸。例如,咱们能够测量每一个耳朵的大小、眼距、鼻子的长度等。若是你曾经看过像《犯罪现场调查》这样的电视剧,你就知道我在说什么了。

 

 

测量面部的最可靠方法

 

好的,因此为了创建咱们的已知脸部数据库呢,咱们应该测量面部的哪些数值?耳朵的大小?鼻子的长度?眼睛的颜色?还有什么?

 

事实证实,对于咱们人类来讲一些显而易见的测量值(好比眼睛颜色),对计算机来讲没什么意义。研究人员发现,最准确的方法是让计算机本身找出它要收集的测量值。深度学习在寻找哪些部分的测量值比较重要方面表现的比人类更好。

 

因此,解决方案是训练一个深度卷积神经网络。可是,并非让它去识别图片中的物体,这一次咱们的训练是要让它为脸部生成 128 个测量值。

 

每次训练要观察三个不一样的脸部图像:

 

1. 加载一张已知的人的面部训练图像

 

2. 加载同一我的的另外一张照片

 

3. 加载另一我的的照片

 

而后,算法查看它本身为这三个图片生成的测量值。再而后,稍微调整神经网络,以确保第一张和第二张生成的测量值接近,而第二张和第三张生成的测量值略有不一样。

 

 

在为几千我的的数百万图像重复该步骤几百万次以后,神经网络学习了如何可靠地为每一个人生成 128 个测量值。对于同一我的的任何十张不一样的照片,它都应该给出大体相同的测量值。

 

机器学习专业人士把每张脸的 128 个测量值称为一个嵌入(embedding)。将复杂的原始数据(如图片)缩减为可由计算机生成的一个数列的方法,在机器学习(特别是语言翻译)中出现了不少次。咱们正在使用的这种脸部提取方法是由 Google 的研究人员在 2015 年发明的,但也有许多相似方法存在。

 

给咱们的脸部图像编码

 

这个经过训练卷积神经网络来输出脸部嵌入的过程,须要大量的数据和强大的计算能力。即便使用昂贵的 Nvidia Telsa 显卡,你也须要大约 24 小时的连续训练,才能得到良好的准确性。

 

但一旦网络训练完成,它就能够为每一张脸生成测量值,即便以前它从未见过这张脸!因此这种训练只需一次便可。幸运的是,OpenFace 上面的大牛已经作完了这些,而且他们发布了几个训练过能够直接使用的网络。谢谢Brandon Amos他的团队!

 

因此咱们须要作的,就是经过他们预训练的网络来处理咱们的脸部图像,以得到 128 个测量值。这是咱们测试图像的一些测量值:

 

 

那么,这 128 个数字到底测量了脸部的哪些部分?咱们固然不知道,可是这对咱们并不重要。咱们关心的是,当看到同一我的两张不一样的图片时,咱们的网络能获得几乎相同的数值。

 

若是你想本身尝试这个步骤,OpenFace 提供了一个 lua 脚本,它能够生成一个文件夹中全部图像的嵌入,并将它们写入 csv 文件。点此查看如何运行

 

第四步:从编码中找出人的名字

 

最后这一步其实是整个过程当中最简单的一步。咱们要作的就是找到数据库中,与咱们的测试图像的测量值最接近的那我的。

 

你能够经过任何基本的机器学习分类算法来达成这一目标。咱们并不须要太花哨的深度学习技巧。咱们将使用一个简单的线性 SVM 分类器,但实际上还有不少其余的分类算法可使用。

 

咱们须要作的是训练一个分类器,它能够从一个新的测试图像中获取测量结果,并找出最匹配的那我的。分类器运行一次只须要几毫秒,分类器的结果就是人的名字!

 

因此让咱们试一下咱们的系统。首先,我使用Will Ferrell, Chad Smith and Jimmy Falon三人每人 20 张照片的嵌入来训练分类器:

 

嗯……就是这些训练数据!

 

接下来,我在这个分类器上运行了威尔·法瑞尔和查德·史密斯在吉米·法伦的节目上互相模仿的那个视频的每一帧:

 

https://cdn-images-1.medium.com/max/800/1*_GNyjR3JlPoS9grtIVmKFQ.gif

 

结果成功了!不一样角度的脸部,甚至是侧脸,它都能捕捉到!

 

本身动手作一遍

 

让咱们回顾一下咱们的步骤:

 

1. 使用 HOG 算法给图片编码,以建立图片的简化版本。使用这个简化的图像,找到其中看起来最像通用 HOG 面部编码的部分。

 

2. 经过找到脸上的主要特征点,找出脸部的姿式。一旦咱们找到这些特征点,就利用它们把图像扭曲,使眼睛和嘴巴居中。

 

3. 把上一步获得的面部图像放入神经网络中,神经网络知道如何找到 128 个特征测量值。保存这 128 个测量值。

 

4. 看看咱们过去已经测量过的全部脸部,找出哪一个人的测量值和咱们要测量的面部最接近。这就是你要找的人!

 

如今你知道这一切都是如何运行的了,这里是如何使用 OpenFace 在你本身的电脑上运行整我的脸识别系统的说明:

 

开始以前

 

确保你已经安装了 python、OpenFace 和 dlib。你也能够在这里手动安装,或者使用一个已经设定好的 docker image:

 

docker pull
bamos/openface
docker run -p 9000:9000
-p 8000:8000 -t -i bamos/openface /bin/bash
cd /root/openface

 

友情提示:若是你正在 OSX 上使用 Docker,你能够这样使你的 OSX /Users/

文件夹在 docker image 中可见:

 

docker run -v /Users:/host/Users -p 9000:9000 -p
8000:8000 -t -i bamos/openface /bin/bash
cd /root/openface

 

而后你就能访问你在 docker image 中 /host/Users/...的 OSX 文件

 

ls /host/Users/

 

第一步

在 openface 文件中创建一个名为 ./training-images/ 的文件夹。

 

mkdir training-images

 

第二步

为你想识别的每一个人创建一个子文件夹。例如:

 

mkdir ./training-images/will-ferrell/
mkdir ./training-images/chad-smith/
mkdir ./training-images/jimmy-fallon/

 

第三步

将每一个人的全部图像复制进对应的子文件夹。确保每张图像上只出现一张脸。不须要裁剪脸部周围的区域。OpenFace 会本身裁剪。

第四步

从 openface 的根目录中运行这个openface 脚本。

首先,进行姿式检测和校准:


./util/align-dlib.py
./training-images/ align outerEyesAndNose ./aligned-images/ --size 96

 

这将建立一个名为./aligned-images/的子文件夹,里面是每个测试图像裁剪过、而且对齐的版本。

其次,从对齐的图像中生成特征文件:


./batch-represent/main.lua
-outDir ./generated-embeddings/ -data ./aligned-images/

运行完后,这个./generated-embeddings/子文件夹会包含一个带有每张图像嵌入的 csv 文件。

第三,训练你的面部检测模型:

./demos/classifier.py
train ./generated-embeddings/

 

这将生成一个名为 ./generated-embeddings/classifier.pkl的新文件,其中包含了你用来识别新面孔的 SVM 模型。

到这一步为止,你应该有了一个可用的人脸识别器!

 

第五步:识别面孔!

 

获取一个未知脸孔的新照片,而后像这样把它传递入分类器脚本中:

 

./demos/classifier.py
infer ./generated-embeddings/classifier.pkl your_test_image.jpg

你应该会获得像这样的一个预测:

 

===/test-images/will-ferrel-1.jpg ===
Predict will-ferrell with 0.73 confidence.

 

至此,你已经完成了一个预测了。你也能够修改./demos/classifier.py 这个 python 脚本,来让它匹配其余人的脸。

重要提示:

 

  • 若是你获得的结果不够理想,试着在第三步为每一个人添加更多照片(特别是不一样姿式的照片)。
  • 即便彻底不知道这个面孔是谁,如今这个脚本仍然会给出预测。在真实应用中,低可信度(low confidence)的预测可能会被直接舍弃,由于颇有可能它们就是错的。
 
via medium.com
相关文章
相关标签/搜索