在深度学习出现后,人脸识别技术才真正有了可用性。这是由于以前的机器学习技术中,难以从图片中取出合适的特征值。轮廓?颜色?眼睛?如此多的面孔,且随着年纪、光线、拍摄角度、气色、表情、化妆、佩饰挂件等等的不一样,同一我的的面孔照片在照片象素层面上差异很大,凭借专家们的经验与试错难以取出准确率较高的特征值,天然也无法对这些特征值进一步分类。深度学习的最大优点在于由训练算法自行调整参数权重,构造出一个准确率较高的f(x)函数,给定一张照片则能够获取到特征值,进而再归类。本文中笔者试图用通俗的语言探讨人脸识别技术,首先概述人脸识别技术,接着探讨深度学习有效的缘由以及梯度降低为何能够训练出合适的权重参数,最后描述基于CNN卷积神经网络的人脸识别。html
1、人脸识别技术概述python
人脸识别技术大体由人脸检测和人脸识别两个环节组成。git
之因此要有人脸检测,不光是为了检测出照片上是否有人脸,更重要的是把照片中人脸无关的部分删掉,不然整张照片的像素都传给f(x)识别函数确定就不可用了。人脸检测不必定会使用深度学习技术,由于这里的技术要求相对低一些,只须要知道有没有人脸以及人脸在照片中的大体位置便可。通常咱们考虑使用opencv、dlib等开源库的人脸检测功能(基于专家经验的传统特征值方法计算量少从而速度更快),也可使用基于深度学习实现的技术如mtcnn(在神经网络较深较宽时运算量大从而慢一些)。github
在人脸检测环节中,咱们主要关注检测率、漏检率、误检率三个指标,其中:算法
检测率:存在人脸而且被检测出的图像在全部存在人脸图像中的比例;浏览器
漏检率:存在人脸可是没有检测出的图像在全部存在人脸图像中的比例;
网络
误检率:不存在人脸可是检测出存在人脸的图像在全部不存在人脸图像中的比例。架构
固然,检测速度也很重要。本文不对人脸检测作进一步描述。机器学习
在人脸识别环节,其应用场景通常分为1:1和1:N。ide
1:1就是判断两张照片是否为同一我的,一般应用在人证匹配上,例如身份证与实时抓拍照是否为同一我的,常见于各类营业厅以及后面介绍的1:N场景中的注册环节。而1:N应用场景,则是首先执行注册环节,给定N个输入包括人脸照片以及其ID标识,再执行识别环节,给定人脸照片做为输入,输出则是注册环节中的某个ID标识或者不在注册照片中。可见,从几率角度上来看,前者相对简单许多,且因为证件照一般与当下照片年代间隔时间不定,因此一般咱们设定的类似度阈值都是比较低的,以此得到比较好的经过率,容忍稍高的误识别率。
然后者1:N,随着N的变大误识别率会升高,识别时间也会增加,因此类似度阈值一般都设定得较高,经过率会降低。这里简单解释下上面的几个名词:误识别率就是照片实际上是A的却识别为B的比率;经过率就是照片确实是A的,但可能每5张A的照片才能识别出4张是A其经过率就为80%;类似度阈值是由于对特征值进行分类是几率行为,除非输入的两张照片实际上是同一个文件,不然任何两张照片之间都有一个类似度,设定好类似度阈值后惟有两张照片的类似度超过阈值,才认为是同一我的。因此,单纯的评价某我的脸识别算法的准确率没有意义,咱们最须要弄清楚的是误识别率小于某个值时(例如0.1%)的经过率。无论1:1仍是1:N,其底层技术是相同的,只是难度不一样而已。
取出人脸特征值是最难的,那么深度学习是如何取特征值的?
假定咱们给出的人脸照片是100*100像素大小,因为每一个像素有RGB三个通道,每一个像素通道由0-255范围的字节表示,则共有3个100*100的矩阵计3万个字节做为输入数据。深度学习实际上就是生成一个近似函数,把上面的输入值转化为能够用做特征分类的特征值。那么,特征值能够是一个数字吗?固然不行,一个数字(或者叫标量)是没法有效表示出特征的。一般咱们用多个数值组成的向量表示特征值,向量的维度即其中的数值个数。特征向量的维度并不是越大越好,google的facenet项目(参见https://arxiv.org/abs/1503.03832论文)作过的测试结果显示,128个数值组成的特征向量结果最好,以下图所示:
那么,如今问题就转化为怎么把3*100*100的矩阵转化为128维的向量,且这个向量可以准确的区分出不一样的人脸?
假定照片为x,特征值为y,也就是说存在一个函数f(x)=y能够完美的找出照片的人脸特征值。如今咱们有一个f*(x)近似函数,其中它有参数w(或者叫权重w)能够设置,例如写成f*(x;w),如有训练集x及其id标识y,设初始参数p1后,那么每次f*(x;w)获得的y`与实际标识y相比,若正确则经过,若错误则适当调整参数w,若是可以正确的调整好参数w,f*(x;w)就会与理想中的f(x)函数足够接近,咱们就得到了几率上足够高准确率的f*(x;w)函数。这一过程叫作监督学习下的训练。而计算f*(x;w)值的过程由于是正常的函数运算,咱们称为前向运算,而训练过程当中比较y`与实际标识id值y结果后,调整参数p的过程则是反过来的,称为反向传播。
因为咱们传递的x入参毕竟是一张照片,照片既有对焦、光线、角度等致使的不太容易衡量的质量问题,也有自己的像素数多少问题。若是x自己含有的数据太少,即图片很是不清晰,例如28*28像素的照片,那么谁也没法准确的分辨出是哪一个人。能够想见,必然像素数越多识别也越准,但像素数越多致使的计算、传输、存储消耗也越大,咱们须要有根据的找到合适的阈值。下图是facenet论文的结果,虽然只是一家之言,但google的严谨态度使得数据也颇有参考价值。
从图中可见排除照片其余质量外象素数至少也要有100*100(纯人脸部分)才能保证比较高的识别率。
2、深度学习技术的原理
由清晰的人脸照转化出的象素值矩阵,应当设计出什么样的函数f(x)转化为特征值呢?这个问题的答案依赖于分类问题。即,先不谈特征值,首先如何把照片集合按人正确的分类?这里就要先谈谈机器学习。机器学习认为能够从有限的训练集样本中把算法很好的泛化。因此,咱们先找到有限的训练集,设计好初始函数f(x;w),并已经量化好了训练集中x->y。若是数据x是低维的、简单的,例如只有二维,那么分类很简单,以下图所示:
上图中的二维数据x只有方形和圆形两个类别y,很好分,咱们须要学习的分类函数用最简单的f(x,y)=ax+by+c就能表示出分类直线。例如f(x,y)大于0时表示圆形,小于0时表示方形。
给定随机数做为a,c,b的初始值,咱们经过训练数据不断的优化参数a,b,c,把不合适的L一、L3等分类函数逐渐训练成L2,这样的L2去面对泛化的测试数据就可能得到更好的效果。然而若是有多个类别,就须要多条分类直线才能分出,以下图所示:
这其实至关于多条分类函数执行与&&、或||操做后的结果。这个时候还可能用f1>0 && f2<0 && f3>0这样的分类函数,但若是更复杂的话,例如自己的特征不明显也没有汇聚在一块儿,这种找特征的方式就玩不转了,以下图所示,不一样的颜色表示不一样的分类,此时的训练数据彻底是非线性可分的状态:
这个时候,咱们能够经过多层函数嵌套的方法来解决,例如f(x)=f1(f2(x)),这样f2函数能够是数条直线,而f1函数能够经过不一样的权重w以及激励函数完成与&&、或||等等操做。这里只有两层函数,若是函数嵌套层数越多,它越能表达出复杂的分类方法,这对高维数据颇有帮助。例如咱们的照片毫无疑问就是这样的输入。所谓激励函数就是把函数f计算出的很是大的值域转化为[0,1]这样较小的值域,这容许多层函数不断的前向运算、分类。
前向运算只是把输入交给f1(x,w1)函数,计算出的值再交给f2(y1,w2)函数,依次类推,很简单就能够获得最终的分类值。可是,由于初始的w权重其实没有多大意义,它得出的分类值f*(x)确定是错的,在训练集上咱们知道正确的值y,那么事实上咱们实际上是但愿y-f*(x)的值最小,这样分类就越准。这其实变成了求最小值的问题。固然,y-f*(x)只是示意,事实上咱们获得的f*(x)只是落到各个分类上的几率,把这个几率与真实的分类相比较获得最小值的过程,咱们称为损失函数,其值为loss,咱们的目标是把损失函数的值loss最小化。在人脸识别场景中,softmax是一个效果比较好的损失函数,咱们简单看下它是如何使用的。
好比咱们有训练数据集照片对应着cat、dog、ship三个类别,某个输入照片通过函数f(x)=x*W+b,前向运算获得该照片属于这3个分类的得分值。此时,这个函数被称为得分函数,以下图所示,假设左边关于猫的input image是一个4维向量[56,231,24,2],而W权重是一个4*3的矩阵,那么相乘后再加上向量[1.1,3.2,-1.2]可获得在cat、 dog、ship三个类别上的得分:
从上图示例可见,虽然输入照片是猫,但得分上属于狗的得分值437.9最高,但究竟比猫和船高多少呢?很难衡量!若是咱们把得分值转化为0-100的百分比几率,这就方便度量了。这里咱们可使用sigmoid函数,以下图所示:
从上图公式及图形可知,sigmoid能够把任意实数转换为0-1之间的某个数做为几率。但sigmoid几率不具备归一性,也就是说咱们须要保证输入照片在全部类别的几率之和为1,这样咱们还须要对得分值按softmax方式作如下处理:
这样给定x后能够获得x在各个类别下的几率。假定三个类别的得分值分别为三、一、-3,则按照上面的公式运算后可得几率分别为[0.8八、0.十二、0],计算过程以下图所示:
然而实际上x对应的几率实际上是第一类,好比[1,0,0],如今拿到的几率(或者可称为似然)是[0.8八、0.十二、0]。那么它们之间究竟有多大的差距呢?这个差距就是损失值loss。如何获取到损失值呢?在softmax里咱们用互熵损失函数计算量最小(方便求导),以下所示:
其中i就是正确的分类,例如上面的例子中其loss值就是-ln0.88。这样咱们有了损失函数f(x)后,怎么调整x才可以使得函数的loss值最小呢?这涉及到微分导数。
3、梯度降低
梯度降低就是为了快速的调整权重w,使得损失函数f(x;w)的值最小。由于损失函数的值loss最小,就表示上面所说的在训练集上的得分结果与正确的分类值最接近!
导数求的是函数在某一点上的变化率。例如从A点开车到B点,经过距离和时间能够算出平均速度,但在其中C点的瞬时速度是多少呢?若是用x表示时间,f(x)表示车子从A点驶出的距离,那么在x0的瞬时速度能够转化为:从x0时再开一个很小的时间,例如1秒,那么这一秒的平均速度就是这一秒开出的距离除以1秒,即(f(1+x0)-f(x0))/1。若是咱们用的不是1秒而是1微秒,那么这个1微秒内的平均速度必然更接近x0时的瞬时速度。因而,到该时间段t趋向于0时,咱们就获得了x0时的瞬时速度。这个瞬时速度就是函数f在x0上的变化率,全部x上的变化率就构成了函数f(x)的导数,称为f`(x)。即:
从几何意义上看,变化率就变成了斜率,这更容易理解怎样求函数的最小值。例以下图中有函数y=f(x)用粗体黑线表示,其在P0点的变化率就是切线红线的斜率:
能够形象的看出,当斜率的值为正数时,把x向左移动变小一些,f(x)的值就会小一些;当斜率的值为负数时,把x向右移动变大一些,f(x)的值也会小一些,以下图所示:
这样,斜率为0时咱们其实就获得了函数f在该点能够获得最小值。那么,把x向左或者向右移一点,到底移多少呢?若是移多了,可能移过了,若是移得不多,则可能要移好久才能找到最小点。还有一个问题,若是f(x)操做函数有多个局部最小点、全局最小点时,若是x移的很是小,则可能致使经过导数只能找到某个并不足够小的局部最小点。以下图所示:
蓝色的为局部最小点,红色是全局最小点。因此x移动多少是个问题,x每次的移动步长过大或者太小均可能致使找不到全局最小点。这个步长除了跟导数斜率有关外,咱们还须要有一个超参数来控制它的移动速度,这个超参数称为学习率,因为它很难优化,因此通常须要手动设置而不能自动调整。考虑到训练时间也是成本,咱们一般在初始训练阶段把学习率设的大一些,越日后学习率设的越小。
那么每次移动的步长与导数的值有关吗?这是天然的,导数的正负值决定了移动的方向,而导数的绝对值大小则决定了斜率是否陡峭。越陡峭则移动的步长应当越大。因此,步长由学习率和导数共同决定。就像下面这个函数,?λ是学习率,而?F(ωj) /ωj是在ωj点的导数。
ωj=?ωj -?λF(ωj) /ωj
根据导数判断损失函数f在x0点上应当如何移动,才能使得f最快到达最小值的方法,咱们称为梯度降低。梯度也就是导数,沿着负梯度的方向,按照梯度值控制移动步长,就能快速到达最小值。固然,实际上咱们未必能找到最小点,特别是自己存在多个最小点时,但若是这个值自己也足够小,咱们也是能够接受的,以下图所示:
以上咱们是以一维数据来看梯度降低,但咱们的照片是多维数据,此时如何求导数?又如何梯度降低呢?此时咱们须要用到偏导数的概念。其实它与导数很类似,由于x是多维向量,那么咱们假定计算Xi的导数时,x上的其余数值不变,这就是Xi的偏导数。此时应用梯度降低法就以下图所示,θ是二维的,咱们分别求θ0和θ1的导数,就能够同时从θ0和θ1两个方向移动相应的步长,寻找最低点,以下图所示:
前文说过,根据有限的训练集,去适应无限的测试集,固然训练集容量越大效果就越好。可是,训练集若是很大,那么每次都根据所有数据执行梯度降低计算量就太大了。此时,咱们选择每次只取所有训练集中的一小部分(究竟多少,通常根据内存和计算量而定),执行梯度降低,不断的迭代,根据经验同样能够快速的把梯度降下来。这就是随机梯度降低。
上面的梯度降低法只能对f函数的w权重进行调整,而上文中咱们说过实际是多层函数套在一块儿,例如f1(f2(x;w2);w1),那么怎么求对每一层函数输入的导数呢?这也是所谓的反向传播怎样继续反向传递下去呢?这就要提到链式法则。其实质为,原本y对x的求导,能够经过引入中间变量z来实现,以下图所示:
这样,y对x的导数等价于y对z的导数乘以z对x的偏导。当输入为多维时则有下面的公式:
如此,咱们能够获得每一层函数的导数,这样能够获得每层函数的w权重应当调整的步长,优化权重参数。
因为函数的导数不少,例如resnet等网络已经达到100多层函数,因此为区别传统的机器学习,咱们称其为深度学习。
深度学习只是受到神经科学的启发,因此称为神经网络,但实质上就是上面提到的多层函数前向运算获得分类值,训练时根据实际标签分类取损失函数最小化后,根据随机梯度降低法来优化各层函数的权重参数。人脸识别也是这么一个流程。以上咱们初步过完多层函数的参数调整,但函数自己应当如何设计呢?
4、基于CNN卷积神经网络进行人脸识别
咱们先从全链接网络谈起。google的tensorflow游乐场里能够直观的体验全链接神经网络的威力,这是游乐场的网址:http://playground.tensorflow.org/,浏览器里就能够作神经网络训练,且过程与结果可视化。以下图所示:
这个神经网络游乐场共有1000个训练点和1000个测试点,用于对4种不一样图案划分出蓝色点与黄色点。DATA处可选择4种不一样图案。
整个网络的输入层是FEATURES(待解决问题的特征),例如x1和x2表示垂直或者水平切分来划分蓝色与黄色点,这是最容易理解的2种划分点的方法。其他5种其实不太容易想到,这也是传统的专家系统才须要的,实际上,这个游乐场就是为了演示,一、好的神经网络只用最基本的x1,x2这样的输入层FEATURES就能够完美的实现;二、即便有不少种输入特征,咱们其实并不清楚谁的权重最高,但好的神经网络会解决掉这个问题。
隐层HIDDEN LAYERS能够随意设置层数,每一个隐层能够设置神经元数。实际上神经网络并非在计算力足够的状况下,层数越多越好或者每层神经元越多越好。好的神经网络架构模型是很难找到的。本文后面咱们会重点讲几个CNN经典网络模型。然而,在这个例子中,多一些隐层和神经元能够更好的划分。
epoch是训练的轮数。红色框出的loss值是衡量训练结果的最重要指标,若是loss值一直是在降低,好比能够低到0.01这样,就说明这个网络训练的结果好。loss也可能降低一会又忽然上升,这就是很差的网络,你们能够尝试下。learning rate初始都会设得高些,训练到后面都会调低些。Activation是激励函数,目前CNN都在使用Relu函数。
了解了神经网络后,如今咱们回到人脸识别中来。每一层神经元就是一个f函数,上面的四层网络就是f1(f2(f3(f4(x))))。然而,就像上文所说,照片的象素太多了,全链接网络中任意两层之间每俩个神经元都须要有一次计算。特别以前提到的,复杂的分类依赖于许多层函数共同运算才能达到目的。当前的许多网络都是多达100层以上,若是每层都有3*100*100个神经元,可想而知计算量有多大!因而CNN卷积神经网络应运而生,它能够在大幅下降运算量的同时保留全链接网络的威力。
CNN认为能够只对整张图片的一个矩形窗口作全链接运算(可称为卷积核),滑动这个窗口以相同的权重参数w遍历整张图片后,能够获得下一层的输入,以下图所示:
CNN中认为同一层中的权重参数能够共享,由于同一张图片的各个不一样区域具备必定的类似性。这样本来的全链接计算量过大问题就解决了,以下图所示:
结合着以前的函数前向运算与矩阵,咱们以一个动态图片直观的看一下前向运算过程:
这里卷积核大小与移动的步长stride、输出深度决定了下一层网络的大小。同时,核大小与stride步长在致使上一层矩阵不够大时,须要用padding来补0(如上图灰色的0)。以上就叫作卷积运算,这样的一层神经元称为卷积层。上图中W0和W1表示深度为2。
CNN卷积网络一般在每一层卷积层后加一个激励层,激励层就是一个函数,它把卷积层输出的数值以非线性的方式转换为另外一个值,在保持大小关系的同时约束住值范围,使得整个网络可以训练下去。在人脸识别中,一般都使用Relu函数做为激励层,relu函数就是max(0,x),以下所示:
可见 relu的计算量其实很是小!
CNN中还有一个池化层,当某一层输出的数据量过大时,经过池化层能够对数据降维,在保持住特征的状况下减小数据量,例以下面的4*4矩阵经过取最大值降维到2*2矩阵:
上图中经过对每一个颜色块筛选出最大数字进行池化,以减少计算数据量。
一般网络的最后一层为全链接层,这样通常的CNN网络结构以下所示:
CONV就是卷积层,每一个CONV后会携带RELU层。这只是一个示意图,实际的网络要复杂许多。目前开源的google facenet是采用resnet v1网络进行人脸识别的,关于resnet网络请参考论文https://arxiv.org/abs/1602.07261,其完整的网络较为复杂,这里再也不列出,也能够查看基于tensorflow实现的python代码https://github.com/davidsandberg/facenet/blob/master/src/models/inception_resnet_v1.py,雅思官网报名注意slim.conv2d含有relu激励层。
以上只是通用的CNN网络,因为人脸识别应用中不是直接分类,而是有一个注册阶段,须要把照片的特征值取出来。若是直接拿softmax分类前的数据做为特征值效果很很差,例以下图是直接将全链接层的输出转化为二维向量,在二维平面上经过颜色表示分类的可视化表示:
可见效果并很差,中间的样本距离太近了。经过centor loss方法处理后,能够把特征值间的距离扩大,以下图所示:
这样取出的特征值效果就会好不少。
实际训练resnetv1网络时,首先须要关注训练集照片的质量,且要把不一样尺寸的人脸照片resize到resnet1网络首层接收的尺寸大小。另外除了上面提到的学习率和随机梯度降低中每一批batchsize图片的数量外,还须要正确的设置epochsize,由于每一轮epoch应当完整的遍历完训练集,而batchsize受限于硬件条件通常不变,但训练集可能一直在变大,这样应保持epochsize*batchsize接近所有训练集。训练过程当中须要密切关注loss值是否在收敛,可适当调节学习率。
最后说一句,目前人脸识别效果的评价惟一通行的标准是LFW(即Labeled Faces in the Wild,参见http://vis-www.cs.umass.edu/lfw/),它包含大约6000个不一样的人的12000张照片,许多算法都依据它来评价准确率。但它有两个问题,一是数据集不够大,二是数据集场景每每与真实应用场景并不匹配。因此若是某个算法称其在LFW上的准确率达到多么的高,并不能反应其真实可用性。
笔者水平有限,若有错误欢迎你们指出。