[CNN] Face Detection
即将进入涉及大量数学知识的阶段,先读下“别人家”的博文放松一下。
读罢该文,基本能了解面部识别领域的整体状况。
后生可畏。
结尾的Google Facenet中的2亿数据集,仿佛隐约听到:“你们都玩儿蛋去吧”。
看到不少人在读,遂整理一下,2020.5 re-edit.
资源
史前方案
一、Face detection 的开始和基本流程
具体来说,人脸检测的任务就是判断给定的图像上是否存在人脸,如果人脸存在,就给出全部人脸所处的位置及其大小。
-
历史进程
由于人脸检测在实际应用中的重要意义,早在上世纪70年代就已经有人开始研究,然而受当时落后的技术条件和有限的需求所影响,直到上世纪90年代,人脸检测技术才开始加快向前发展的脚步,在新世纪到来前的最后十年间,涌现出了大量关于人脸检测的研究工作,这时期设计的很多人脸检测器已经有了现代人脸检测技术的影子,例如可变形模板的设计(将人脸按照五官和轮廓划分成多个相互连接的局部块)、神经网络的引入(作为判断输入是否为人脸的分类模型)等。这些早期的工作主要关注于检测正面的人脸,基于简单的底层特征如物体边缘、图像灰度值等来对图像进行分析,结合关于人脸的先验知识来设计模型和算法(如五官、肤色),并开始引入一些当时已有的的模式识别方法。虽然早期关于人脸检测的研究工作离实际应用的要求还有很远,但其中进行检测的流程已经和现代的人脸检测方法没有本质区别。
-
传统流程
给定一张输入图像,要完成人脸检测这个任务,我们通常分成三步来进行:
检测人脸的过程就是不断地执行上面三步,直到遍历所有需要观察的窗口。
-
-
不是 :如果所有的窗口都被判断为不包含人脸,那么就认为所给的图像上不存在人脸,
-
是 :否则就根据判断为包含人脸的窗口来给出人脸所在的位置及其大小。
-
二、流程重难点
- 那么,如何来选择我们要观察的窗口呢?
所谓眼见为实,要判断图像上的某个位置是不是一张人脸,必须要观察了这个位置之后才知道,因此,选择的窗口应该覆盖图像上的所有位置。显然,最直接的方式就是让观察的窗口在图像上从左至右、从上往下一步一步地滑动,从图像的左上角滑动到右下角——这就是所谓的滑动窗口范式,你可以将它想象成是福尔摩斯(检测器)在拿着放大镜(观察窗口)仔细观察案发现场(输入图像)每一个角落(滑动)的过程。
别看这种用窗口在图像上进行扫描的方式非常简单粗暴,它的确是一种有效而可靠的窗口选择方法,以至于直到今天,滑动窗口范式仍然被很多人脸检测方法所采用,而非滑动窗口式的检测方法本质上仍然没有摆脱对图像进行密集扫描的过程。
- 对于观察窗口,还有一个重要的问题就是:窗口应该多大?
我们认为一个窗口是一个人脸窗口当且仅当其恰好框住了一张人脸,即窗口的大小和人脸的大小是一致的,窗口基本贴合人脸的外轮廓。
那么问题来了,即使是同一张图像上,人脸的大小不仅不固定,而且可以是任意的,这样怎么才能让观察窗口适应不同大小的人脸呢?
一种做法当然是采用多种不同大小的窗口,分别去扫描图像,但是这种做法并不高效。换一个角度来看,其实也可以将图像缩放到不同的大小,然后用相同大小的窗口去扫描。这就是所谓的构造图像金字塔的方式。图像金字塔这一名字非常生动形象,将缩放成不同大小的图像按照从大到小的顺序依次往上堆叠,正好就组成了一个金字塔的形状。
通过构建图像金字塔,同时允许窗口和人脸的贴合程度在小范围内变动,我们就能够检测到不同位置、不同大小的人脸了。另外需要一提的是,对于人脸而言,我们通常只用正方形的观察窗口,因此就不需要考虑窗口的长宽比问题了。
-
收集证据,提取特征
选好了窗口,我们开始对窗口中的图像区域进行观察。在处理图像的过程中,这个收集证据的环节我们称之为特征提取,特征就是我们对图像内容的描述。由于机器看到的只是一堆数值,能够处理的也只有数值,因此对于图像所提取的特征具体表示出来就是一个向量,称之为特征向量,其每一维是一个数值,这个数值是根据输入(图像区域)经由某些计算(观察)得到的,例如进行求和、相减、比较大小等。总而言之,特征提取过程就是从原始的输入数据(图像区域颜色值排列组成的矩阵)变换到对应的特征向量的过程,特征向量就是我们后续用来分析和寻找真相的证据。
特征是人脸么 之 人脸分类器
特征提取之后,就到了决断的时刻:判别当前的窗口是否恰好包含一张人脸。我们将所有的窗口划分为两类:
-
-
- 一类是恰好包含人脸的窗口,称之为人脸窗口,
- 剩下的都归为第二类,称之为非人脸窗口,
-
而最终判别的过程就是一个对当前观察窗口进行分类的过程。
因为我们的证据是由数值组成的特征向量,所以我们是通过可计算的数学模型来寻找真相的。
用来处理分类问题的数学模型我们通常称之为分类器,分类器以特征向量作为输入,通过一系列数学计算,以类别作为输出。
每个类别会对应到一个数值编码,称之为这个类别对应的标签,如将人脸窗口这一类编码为1,而非人脸窗口这一类编码为-1;
分类器就是一个将特征向量变换到类别标签的函数。
但,分类器的阈值往往是很难确定的
尽管我们对目标非常明确,我们也仍然没法给出一个最优的参数取值,因为我们并不使用机器所采用的二进制语言系统,我们并不懂什么才是对机器最好的。
于是我们只有一种选择:
-
把我们的目标告诉机器,举一些例子向其进行解释,
-
然后让机器自己去学习这个参数,
-
最后我们给机器设计一场考试,测试其是否满足了我们的要求。
-
我们从一些图像上选出一部分人脸和非人脸窗口的样例,用对应的类别标签对其进行标注,然后将这些样例划分成两个集合,一个集合作为分类器学习所使用的训练集,另一个集合作为最终考查分类器能力的测试集,同时我们设定一个目标:希望分类的准确率能够在80%以上。(典型的机器学习方法)
由于采用滑动窗口的方式需要在不同大小的图像上的每一个位置进行人脸和非人脸窗口的判别,而对于一张大小仅为480*320的输入图像,窗口总数就已经高达数十万,面对如此庞大的输入规模,如果对单个窗口进行特征提取和分类的速度不够快,就很容易使得整个检测过程产生巨大的时间开销,也确实就因为如此,早期所设计的人脸检测器处理速度都非常慢,一张图像甚至需要耗费数秒才能处理完成——视频的播放速度通常为每秒25帧图像,这给人脸检测投入现实应用带来了严重的障碍。
技术突破
一、VJ人脸检测器及其发展
VJ人脸检测之所以器能够获得成功,极大地提高人脸检测速度,其中有三个关键要素:
-
-
特征的快速计算方法——积分图,
-
有效的分类器学习方法——AdaBoost,
-
高效的分类策略——级联结构的设计。
-
VJ人脸检测器采用Haar特征来描述每个窗口。
- 所谓Haar特征,其实就是在窗口的某个位置取一个矩形的小块,
- 然后将这个矩形小块划分为黑色和白色两部分,并分别对两部分所覆盖的像素点(图像上的每个点称为一个像素)的灰度值求和,
- 最后用白色部分像素点灰度值的和减去黑色部分像素点灰度值的和,得到一个Haar特征的值。
二、Haar特征 (Haar-like特征)
反映了局部区域之间的相对明暗关系,能够为人脸和非人脸的区分提供有效的信息,例如眼睛区域比周围的皮肤区域要暗,通过Haar特征就可以将这一特点表示出来。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
http://www.cnblogs.com/ello/archive/2012/04/28/2475419.html 人脸检测方法主要有两大类:基于知识和基于统计。 基于知识的方法主要利用先验知识将人脸看作器官特征的组合,根据眼睛、眉毛、嘴巴、鼻子等器官的特征以及相互之间的几何位置关系来检测人脸。 基于统计的方法则将人脸看作一个整体的模式——二维像素矩阵,从统计的观点通过大量人脸图像样本构造人脸模式空间,根据相似度量来判断人脸是否存在。 在这两种框架之下,发展了许多方法。目前随着各种方法的不断提出和应用条件的变化,将知识模型与统计模型相结合的综合系统将成为未来的研究趋势。”(来自论文《基于Adaboost的人脸检测方法及眼睛定位算法研究》) 基于知识的人脸检测方法 Ø 模板匹配 Ø 人脸特征 Ø 形状与边缘 Ø 纹理特性 Ø 颜色特征 基于统计的人脸检测方法 Ø 主成分分析与特征脸 Ø 神经网络方法 Ø 支持向量机 Ø 隐马尔可夫模型 Ø Adaboost算法 虽说haar分类器采用了Boosting的算法,但在OpenCV中,Haar分类器与Boosting没有采用同一套底层数据结构。 《Learning OpenCV》中有这样的解释:“Haar分类器,它建立了boost筛选式级联分类器。它与ML库中其他部分相比,有不同的格局,因为它是在早期开发的,并完全可用于人脸检测。” 在2001年,Viola和Jones两位大牛发表了经典的《Rapid Object Detection using a Boosted Cascade of Simple Features》【1】和《Robust Real-Time Face Detection》【2】,在AdaBoost算法的基础上,使用Haar-like小波特征和积分图方法进行人脸检测,他俩不是最早使用提出小波特征的,但是他们设计了针对人脸检测更有效的特征,并对AdaBoost训练出的强分类器进行级联。 这可以说是人脸检测史上里程碑式的一笔了,也因此当时提出的这个算法被称为Viola-Jones检测器。 又过了一段时间,Rainer Lienhart和Jochen Maydt两位大牛将这个检测器进行了扩展【3】,最终形成了OpenCV现在的Haar分类器。 AdaBoost是Freund 和Schapire在1995年提出的算法,是对传统Boosting算法的一大提升。Boosting算法的核心思想,是将弱学习方法提升成强学习算法,也就是“三个臭皮匠顶一个诸葛亮”,它的理论基础来自于Kearns 和Valiant牛的相关证明【4】 在此不深究了。反正我是能多简略就多简略的把Haar分类器的前世今生说完鸟,得出的结论是,大牛们都是成对儿的。。。(啊哈哈哈哈哈。。。)额,回到正题,Haar分类器 = Haar-like特征 + 积分图方法 + AdaBoost + 级联; 阿 Haar分类器算法的要点如下: ① 使用Haar-like特征做检测。 ② 使用积分图(Integral Image)对Haar-like特征求值进行加速。 ③ 使用AdaBoost算法训练区分人脸和非人脸的强分类器。 ④ 使用筛选式级联把强分类器级联到一起,提高准确率。 论文列表: 【1】《Rapid Object Detection using a Boosted Cascade of Simple Features》 【2】《Robust Real-Time Face Detection》 【3】《An Extended Set of Haar-like Features for Rapid Object Detection》 【4】《Crytographic Limitations on Learning Boolean Formulae and Finite Automata》 【5】《A Theory of the Learnable》 【6】《The Computational Complexity of Machine Learning》 【7】《The Strength of Weak Learnability》 【8】《Boosting a weak learning algorithm》 【9】《A Decision-Theoretic Generalization of On-Line Learning and an Application to Boosting》
- Viola牛们提出的Haar-like特征。
- Lienhart等牛们提出的Haar-like特征。
- 其他Haar-like特征。
将上面的任意一个矩形放到人脸区域上,
然后,(白色区域的像素和 - 黑色区域的像素和)的值 = 暂且称之为人脸特征值。
如果你把这个矩形放到一个非人脸区域,那么计算出的特征值应该和人脸特征值是不一样的,而且越不一样越好,所以这些方块的目的就是把人脸特征量化,以区分人脸和非人脸。
Haar特征本质上是局部区域像素值的一种线性组合,其相对应的更一般的形式则是不指定线性组合的系数,允许系数为任意实数,这被称之为线性特征。
三、其他特征点方案
-
LBP特征 - 二值编码特征
其直接基于像素灰度值进行计算,特点是在编码时考虑的是两个值的相对大小,并且按照一定的空间结构来进行编码,局部组合二值特征就是在LBP特征的启发下设计的;
从计算上来看,提取LBP特征比提取Haar特征要快,但是Haar特征对于人脸和非人脸窗口的区分能力更胜一筹。
-
SURF特征
简化的SURF特征是一种和Haar特征相类似的特征,但是其计算的是局部区域中像素点的梯度和,并在求和的过程中考虑了梯度方向;
所谓梯度,最简单的一种情形就是指同一行上两个不同位置像素值的差比上它们水平坐标的差;
SURF特征比Haar特征更为复杂,因此计算代价更高,但是由于其表达能力更强,因此能够以更少数目的特征来达到相同的区分度,在一定程度上弥补了其在速度上的不足。
-
HOG特征
HOG特征也是一种基于梯度的特征,其对一个局部区域内不同方向的梯度进行统计,计算梯度直方图来表示这个区域。
-
积分通道特征
积分通道特征和多通道的Haar特征有些类似,但是其使用的通道更加多样化,将通道的概念推广为由原图像变换而来并且空间结构和原图像对应的任何图像。
-
聚合通道特征
聚合通道特征则在积分通道特征的基础上进一步加入了对每个通道进行下采样的操作,实现局部区域信息的聚合。
四、总结
在过去十几年的探索过程中,涌现出的特征不胜枚举,这里只选取了部分比较有代表性和反映了人们探索思路的特征进行举例。
这里所有列举的特征都有一个共同的特点:都由科研工作者根据自己的经验手工设计,这些特征的设计反映了人们对问题的理解和思考。
虽然随着不断的改进,设计出的特征已经日臻完善,但直到现在,人们在特征上的探索还远没有结束。
关键要素
—— 特征的快速计算方法:积分图;
—— 有效的分类器学习方法:AdaBoost;
—— 高效的分类策略:级联结构的设计。
一、AdaBoost算法
为了增加区分度,可以对多个矩形特征计算得到一个区分度更大的特征值。
"那么什么样的矩形特征怎么样的组合到一块可以更好的区分出人脸和非人脸呢?" -- 这就是AdaBoost算法要做的事了。
这里我们先放下积分图这个概念不管,为了让我们的思路连贯,我直接开始介绍AdaBoost算法。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
我比较喜欢查算法的户口,所以新写了一章查了下去。 AdaBoost的老祖宗可以说是机器学习的一个模型,它的名字叫PAC(Probably Approximately Correct)。 PAC模型是计算学习理论中常用的模型,是Valiant牛在我还没出生的1984年提出来的【5】,他认为“学习"是模式明显清晰或模式不存在时仍能获取知识的一种“过程”,并给出了一个【从计算角度】来获得这种“过程"的方法,这种方法包括: (1) 适当信息收集机制的选择; (2) 学习的协定; (3) 对能在合理步骤内完成学习的概念的分类。 PAC学习的实质就是在样本训练的基础上,使算法的输出以概率接近未知的目标概念。 PAC学习模型是考虑: 1) 样本复杂度(指学习器收敛到成功假设时至少所需的训练样本数) 2) 计算复杂度(指学习器收敛到成功假设时所需的计算量) 的一个基本框架。 成功的学习被定义为形式化的概率理论。(来自论文《基于Adaboost的人脸检测方法及眼睛定位算法研究》)简单说来,PAC学习模型不要求你每次都正确,只要能在多项式个样本和多项式时间内得到满足需求的正确率,就算是一个成功的学习。 基于PAC学习模型的理论分析,Valiant牛提出了Boosting算法【5】,Boosting算法涉及到两个重要的概念就是弱学习和强学习, 所谓弱学习,就是指一个学习算法对一组概念的识别率只比随机识别好一点, 所谓强学习,就是指一个学习算法对一组概率的识别率很高。 现在我们知道所谓的弱分类器和强分类器就是弱学习算法和强学习算法。 弱学习算法是比较容易获得的,获得过程需要数量巨大的假设集合,这个假设集合是基于某些简单规则的组合和对样本集的性能评估而生成的, 强学习算法是不容易获得的, 然而,Kearns 和Valiant 两头牛提出了弱学习和强学习等价的问题 【6】 并证明了只要有足够的数据,弱学习算法就能通过集成的方式生成任意高精度的强学习方法。这一证明使得Boosting有了可靠的理论基础,Boosting算法成为了一个提升分类器精确性的一般性方法。【4】 1990年,Schapire牛提出了第一个多项式时间的算法【7】, 1年后,Freund牛又提出了一个效率更高的Boosting算法【8】。 然而,Boosting算法还是存在着几个主要的问题, 其一、Boosting算法需要预先知道弱学习算法学习正确率的下限即弱分类器的误差, 其二、Boosting算法可能导致后来的训练过分集中于少数特别难区分的样本,导致不稳定。 针对Boosting的若干缺陷,Freund和Schapire牛于1996年前后提出了一个实际可用的自适应Boosting算法AdaBoost【9】,AdaBoost目前已发展出了大概四种形式的算法: 1) Discrete AdaBoost(AdaBoost.M1)、 2) Real AdaBoost、 3) LogitBoost、 4) Gentle AdaBoost, 至此,AdaBoost的身世之谜就这样揭开了。
"弱弱变强,强强联手“ -- 级联分类器
原因一:
造成人脸检测速度慢的根本原因还在于输入规模过大,动辄需要处理几十上百万的窗口,如果这样的输入规模是不可避免的,那么有没有可能在处理的过程中尽快降低输入规模呢?
如果能够通过粗略地观察快速排除掉大部分窗口,只剩下少部分窗口需要进行仔细的判别,则总体的时间开销也会极大地降低。
从这样的想法出发,VJ人脸检测器采用了一种级联结构来达到逐步降低输入规模的目的。
原因二:
通过AdaBoost算法辛苦的训练出了强分类器,然而在现实的人脸检测中,只靠一个强分类器还是难以保证检测的正确率,这个时候,需要一个豪华的阵容,训练出多个强分类器将它们强强联手,最终形成正确率很高的级联分类器这就是我们最终的目标Haar分类器。
那么训练级联分类器的目的就是为了检测的时候,更加准确,这涉及到Haar分类器的另一个体系,检测体系 -- 以现实中的一幅大图片作为输入,然后对图片中进行多区域,多尺度的检测。
-
- 所谓多区域,是要对图片划分多块,对每个块进行检测.
- 由于训练的时候用的照片一般都是20*20左右的小图片,所以对于大的人脸,还需要进行多尺度的检测。
多尺度检测机制一般有两种策略:
-
- 一种是不改变搜索窗口的大小,而不断缩放图片,这种方法显然需要对每个缩放后的图片进行区域特征值的运算,效率不高,
- 另一种方法,是不断初始化搜索窗口size为训练时的图片大小,不断扩大搜索窗口,进行搜索,解决了第一种方法的弱势。
在区域放大的过程中会出现同一个人脸被多次检测,这需要进行区域的合并,这里不作探讨。
无论哪一种搜索方法,都会为输入图片输出大量的子窗口图像,这些子窗口图像经过筛选式级联分类器会不断地被每一个节点筛选,抛弃或通过。
级联强分类器的策略是,将若干个强分类器由简单到复杂排列,希望经过训练使每个强分类器都有较高检测率,而误识率可以放低。
比如几乎99%的人脸可以通过,但50%的非人脸也可以通过,这样如果有20个强分类器级联,那么:
他们的总识别率为0.99^20 98%,错误接受率也仅为0.5^20
0.0001%。
这样的效果就可以满足现实的需要了,但是如何使每个强分类器都具有较高检测率呢,为什么单个的强分类器不可以同时具有较高检测率和较高误识率呢?
下面我们讲讲级联分类器的训练。( 主要参考了论文《基于Adaboost的人脸检测方法及眼睛定位算法研究》)
设:
K 是一个级联检测器的层数,
D 是该级联分类器的检测率,
F 是该级联分类器的误识率,
di 是第i层强分类器的检测率,
fi 是第i层强分类器的误识率。
如果要训练一个级联分类器达到给定的F值和D值,只需要训练出每层的d值和f值,这样:
d^K = D
f^K = F
级联分类器的要点就是:如何训练每层强分类器的 d值 和 f值 达到指定要求。
AdaBoost训练出来的强分类器一般具有较小的误识率,但检测率并不很高,
一般情况下,高检测率会导致高误识率,这是强分类阈值的划分导致的:
-
- 要提高强分类器的检测率既要降低阈值,
- 要降低强分类器的误识率就要提高阈值,
这是个矛盾的事情。
据参考论文的实验结果,增加分类器个数可以在提高强分类器检测率的同时降低误识率,所以级联分类器在训练时要考虑如下平衡:
-
- 一是弱分类器的个数和计算时间的平衡,
- 二是强分类器检测率和误识率之间的平衡。
具体说来,VJ人脸检测器将多个分类器级联在一起,从前往后,分类器的复杂程度和计算代价逐渐增大。
对于给定的一个窗口,先由排在最前面也最简单的分类器对其进行分类,如果这个窗口被分为非人脸窗口,那么就不再送到后面的分类器进行分类,直接排除,
否则就送到下一级分类器继续进行判别,直到其被排除,或者被所有的分类器都分为人脸窗口。
这样设计的好处是显而易见的,每经过一级分类器,下一级分类器所需要判别的窗口就会减少,使得只需要付出非常少的计算代价就能够排除大部分非人脸窗口。
从另一个角度来看,这实际上也是根据一个窗口分类的难度动态地调整了分类器的复杂程度,这显然比所有的窗口都用一样的分类器要更加高效。
二、积分图 —— 加速器
它是Haar分类器能够实时检测人脸的保证。
以Viola牛提出的最基本四个特征为例,在一个24×24size的窗口中任意排列至少可以产生数以10万计的特征 (超过160,000个),对这些特征求值的计算量是非常大的。
而积分图就是只遍历一次图像就可以求出图像中所有区域像素和的快速算法,大大的提高了图像特征值计算的效率。
积分图是一种能够描述全局信息的矩阵表示方法。积分图的构造方式是位置(i,j)处的值ii(i,j)是原图像(i,j)左上角方向所有像素的和:
积分图构建算法:
1)用s(i,j)表示行方向的累加和,初始化s(i,-1)=0;
2)用ii(i,j)表示一个积分图像,初始化ii(-1,i)=0;
3)逐行扫描图像,递归计算每个像素(i,j)行方向的累加和s(i,j)和积分图像ii(i,j)的值
s(i,j) = s(i,j-1) + f(i,j)
ii(i,j) = ii(i-1,j) + s(i,j)
4)扫描图像一遍,当到达图像右下角像素时,积分图像ii就构造好了。
积分图构造好之后,图像中任何矩阵区域的像素累加和都可以通过简单运算得到如图所示。
设D的四个顶点分别为α、β、γ、δ,则D的像素和可以表示为
Dsum = ii(α) + ii(β) - ( ii(γ) + ii(δ) );
而Haar-like特征值无非就是两个矩阵像素和的差,同样可以在常数时间内完成。
积分图示范:
三、Haar分类器
Haar分类器的检测效率
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
简略的探讨下Haar分类器的检测效率。
尝试过的几种方法:
1)尝试检测算法与跟踪算法相结合,原本以为Camshift是个轻量级的算法,但是正如我后来看到的,建立反向投影图的效率实在不高,在PC上效果不错,但是在ios上速度很慢,这个我后来发现可能是因为ios浮点运算效率不高的原因。但是即便速度能上去,靠Camshift跟踪算法太依赖肤色了,导致脖子,或是手什么的干扰很严重,这个调起来很费神,也不一定能调好。
2)修改OpenCV中Haar检测函数的参数,效果非常明显,得出的结论是,搜索窗口的搜索区域是提高效率的关键。
3)根据2)的启发,我打算利用YCbCr颜色空间,粗估肤色区域,以减少人脸的搜索面积,但是后来苦于没能高效率的区分出肤色区域,放弃了该方法。
4)换了策略,考虑到视频中人脸检测的特殊性,上一帧人脸的位置信息对下一帧的检测有很高的指导价值,所以采有帧间约束的方法,减少了人脸搜索的区域,并且动态调整Haar检测函数的参数,得到了较高的效率。
5)其他关于算法之外的优化需要根据不同的处理器做具体的优化。
分类器及其学习方法的进化
分类器能力的强弱直接决定了分类准确度的高低,而分类的计算代价是影响检测速度的一个关键因素,因此,人们探索的另一个方向就是对分类器及其学习方法的改进。
采用AdaBoost方法由弱分类器构建强分类器,这是一个顺序执行的过程,换言之,一旦一个弱分类器被选中,其就必定会成为强分类器的组成部分,不允许反悔,这其实是假设增加弱分类器一定会使得强分类器的分类准确度更高,但是,这个假设并不总是成立。事实上,每次对弱分类器的选择只是依照当时的情况决定,而随着新的弱分类器被增加进来,从整体上来看,之前的选择未必最优。基于这样的想法,出现了允许回溯的FloatBoost方法。
FloatBoost 方法
FloatBoost方法在选择新的弱分类器的同时,也会重新考查原有的弱分类器,如果去掉某个弱分类器之后强分类器的分类准确度得到了提升,那说明这个弱分类器带来了负面影响,应该被剔除。(去掉负面作用分类器)
VJ人脸检测器中,相级联的多个分类器在学习的过程中并不会产生直接的联系,
其关联仅体现在训练样例上:"后一级分类器的训练样例一定要先通过前一级分类器。"
不同分类器在学习时的独立性会带来两方面的坏处:
- 一是在每个分类器都是从头开始学习,不能借鉴之前已经学习好的分类器的经验;
- 二是每个分类器在分类时都只能依靠自己,不能利用其它分类器已经获得的信息。
链式 Boosting 方法 & 嵌套式 Boosting 方法
为此,出现了两种改进的方案:链式Boosting方法和嵌套式Boosting方法。(在学习中也要体现)
共同:
两种方案都在学习新一级的分类器时,都考虑之前已经学好的分类器,
区别:
在于链式Boosting方法直接将前面各级分类器的输出进行累加,作为基础得分,新分类器的输出则作为附加得分,换言之,前面各级分类器实际上是新分类器的一个“前缀”,所有的分类器通过这种方式链在了一起;
嵌套式Boosting方法则直接将前一级分类器的输出作为新分类器第一个弱分类器的特征,形成一种嵌套的关系,其特点是只有相邻的分类器才会互相影响。
特征继承
还有一种和嵌套式Boosting方法相类似的方案:特征继承,即从特征而不是分类器的角度来关联不同的分类器,
具体而言,新的分类器在学习时会先继承前一级分类器的所有特征,基于这些特征学习弱分类器,再此基础上再考虑增加新的弱分类器,
这一方案的特点在于其只引入了分类器学习时的相互影响,而在分类时分类器之间仍然是相互独立的。
特征点定位
相关的任务之间往往会相互产生促进作用,相辅相成,而和人脸检测密切相关的一个任务就是特征点定位:预测脸部关键点的位置,这些关键点可以是双眼中心、鼻尖、嘴角等。
基于这样一种想法,在2014年出现了Joint Cascade,即把检测人脸所需要的分类器和预测特征点位置的回归器交替级联,同时进行人脸检测和特征点定位两个任务。
用特征点定位辅助人脸检测的关键在于形状索引特征的引入,即特征不再是在整个窗口中提取,而是在以各个特征点为中心的局部区域进行提取。
这样的好处就在于提高了特征的语义一致性。
避免了:“不同的人脸其对应的特征点位置是不同的,反过来看,也就是说相同的位置实际上对应于脸部的不同区域,那么在相同区域提取的特征实际上表示的是不同的语义,简单地说,就是在拿鼻子去和嘴巴匹配。”
采用形状索引特征可以很好地避免这个问题,从而增大人脸和非人脸窗口之间的区分性。
对于一个给定的窗口,我们并不知道特征点的位置,因此采用一个“平均位置”作为初始位置,
即基于标注有特征点坐标的人脸样例集,计算出的每个点坐标的平均值;
在平均位置的基础上,我们提取特征预测各个特征点真实的位置,
不过一次预测往往是不准确的,就好像跑步的时候我们没法直接从起点跳到终点一样,所以需要不断基于当前确定的特征点位置来预测新的位置,逐步向其真实的位置靠近。
这个过程很自然地形成了一种级联结构,从而能够和人脸检测器耦合在一起,形成一种不同模型交替级联的形式。
针对分类器学习过程中的每一个环节,人们都进行了细致而充分的探索,除了上面提到的几个方向,在分类器分类阈值的学习、提升分类器学习的速度等问题上,也出现了很多出色的研究工作。大部分在分类器及其学习方法上进行改进的工作关注的还是Boosting方法(AdaBoost方法是Boosting方法的一个杰出代表)和相对简单的分类器形式,如果能够引入具有更强分类能力的分类器,相信能给检测器带来进一步的性能提升,这一点在后文会有所涉及。
四、级联结构的演化
分类器的组织结构也是人们关心的一个重要问题,尤其是在面临多姿态人脸检测任务的时候。
人脸的姿态是指人脸在三维空间中绕三个坐标轴旋转的角度,而多姿态人脸检测就是要将带旋转的人脸给检测出来,不管是斜着的(绕x轴旋转)、仰着的(绕y轴旋转)还是侧着的(绕z轴旋转)。
不同姿态的人脸在表观特征上存在很大的差异,这给检测器带来了非常大的挑战,为了解决这一问题,通常采用分治的策略,
-
- 分别针对不同姿态的人脸单独训练分类器,
- 然后组合起来构建成多姿态人脸检测器。
最简单的多姿态人脸检测器就是将针对不同姿态人脸的分类器采用并列式的结构进行组织,其中并列的每一个分类器仍然采用原来的级联结构(我们称这种分类器为级联分类器);
在检测人脸的过程中,一个窗口如果被其中一个级联分类器分为人脸窗口,则认为其确实是一个人脸窗口,而只有当每一个级联分类器都将其判别为非人脸窗口时,才将其排除掉。
这种并列式的组织架构存在两方面的缺陷:
- 一是造成了检测时间的成倍增长,因为绝大部分窗口是非人脸窗口,这些窗口需要经过每一个级联分类器的排除;
- 二是容易造成整体分类准确度的降低,因为整个检测器分错的窗口包含的是所有级联分类器分错的窗口。
有人设计了一种金字塔式的级联结构,金字塔的每一层对应于对人脸姿态(旋转角度)的一个划分,从顶层到底层划分越来越细,级联的每个分类器只负责区分非人脸和某个角度范围内的人脸。
对于一个待分类的窗口:
从最顶层的分类器开始对其进行分类,
如果其被分为人脸窗口 --> 则送入到下一层的第一个分类器继续进行分类,
如果其被分为非人脸窗口 --> 则送入到同一层的下一个分类器继续进行分类,
当在某一层上所有的分类器都将其分为非人脸窗口时,就确认其为非人脸窗口,将其排除。
图示:
金字塔式的级联结构也可以看成是一种特殊的并列式结构,只不过每个级联分类器相互之间有共享的部分,这样最直接的好处就在于:
-
- 减少了计算量,共享的部分只需要计算一次,
- 同时在底层又保留了分治策略所带来的好处 —— 子问题比原问题更加容易,因此更容易学习到分类准确度更高的分类器。
还有一种比较典型的结构是树形的级联结构,从形状上来看其和金字塔式的级联结构是一样的,也是从上往下分类器的数目逐层增多,区别就在于:
-
- 树形的级联结构中没有同一层分类器之间的横向连接,
- 只有相邻层分类器之间的纵向连接,即一个窗口在同一层上不会由多个分类器进行分类,而会直接被送往下一层或者被排除。
树形级联结构通过引入分支跳转机制,进一步减少了对一个窗口进行分类所需要的计算量,不过同时也带来了新的问题:
分支跳转通常根据姿态估计(估计旋转角度的范围)的结果来进行,而如果姿态估计出现错误,就会出现某个姿态的人脸窗口被送给另一个姿态人脸对应的分类器进行分类的情况,容易导致错误的分类。
为了缓解这一问题,出现了允许多个分支同时跳转的设计,从而降低了由于跳转错误而引起分类错误的风险。
分治策略是处理多姿态人脸检测任务最基本的策略,但要同时兼顾速度和分类准确度并不是一件容易的事情,分类能力的增强不可避免地会带来计算代价的增大,如何用更小的计算代价来换取更高的分类准确度,这仍然是一个需要去思考和探索的问题。
人脸检测器的比拼
在不断对人脸检测器进行改进的过程中,有一个问题是不容忽视的:如何科学地比较两个人脸检测器的优劣?
简单地说,出一套考题让所有的检测器进行一场考试,谁得分高谁就更好。
对于人脸检测器而言,
所谓考题(测试集)就是一个图像集合,通常其中每张图像上都包含至少一张人脸,并且这些人脸的位置和大小都已经标注好。
关于得分,需要考虑检测器两方面的表现,
- 一是检测率,也即对人脸的召回率,检测出来的人脸占总人脸的比例——测试集中一共标注了100张人脸,检测器检测出其中70张人脸,则检测率为70%;
- 二是误检(也称为虚警)数目,即检测器检测出来的人脸中出现错误(实际上不是人脸)的数目 —— 检测器一共检测出80张人脸,然而其中有10个错误,只有70个是真正的人脸,那么误检数目就是10。
在这两个指标上,我们所希望的总是检测率尽可能高,而误检数目尽可能少,但这两个目标之间一般是存在冲突的;
在极端的情况下,如果一张脸也没有检测出来,那么误检数目为0,但是检测率也为0,而如果把所有的窗口都判别为人脸窗口,那么检测率为100%,而误检数目也达到了最大。
在比较两个检测器的时候,我们通常固定一个指标,然后对比另一个指标,要么看相同误检数目时谁的检测率高,要么看相同检测率时谁的误检少。
对于每一个检测出的人脸,检测器都会给出这个检测结果的得分(或者说信度),那么如果人为地引入一个阈值来对检测结果进行筛选(只保留得分大于阈值得检测结果),那么随着这个阈值的变化,最终得检测结果也会不同,因而其对应得检测率和误检数目通常也会不同。
通过变换阈值,我们就能够得到多组检测率和误检数目的值,由此我们可以在平面直角坐标系中画出一条曲线来:
以x坐标表示误检数目,以y坐标表示检测率,这样画出来的曲线称之为ROC曲线(不同地方中文译法不一,如接收机曲线、接收者操作特征曲线等,这里直接采用英文简写)。ROC曲线提供了一种非常直观的比较不同人脸检测器的方式,得到了广泛的使用。
评测人脸检测器时还有一个重要的问题:怎么根据对人脸的标注和检测结果来判断某张人脸是否被检测到了?
一般来说,检测器给出的检测框(即人脸窗口)不会和标注的人脸边框完全一致,而且对人脸的标注也不一定是矩形,例如还可能是椭圆形;因此当给定了一个检测框和一个标注框时,我们还需要一个指标来界定检测框是否和标注框相匹配,这个指标就是交并比:两者交集(重叠部分)所覆盖的面积占两者并集所覆盖面积的比例,一般情况下,当检测框和标注框的交并比大于0.5时,我们认为这个检测框是一个正确检测的人脸。
MIT - FDDB 人脸检测数据集
在早期的人脸检测工作中,一般采用MIT-CMU人脸检测数据集作为人脸检测器的测试集,来比较不同的检测器。这个测试集只包含几百张带有人脸的图像,并且人脸主要是清晰且不带遮挡的正面人脸,因而是一个相对简单的测试集,现在几乎已经不再使用。
在2010年,美国麻省大学的一个实验室推出了一个新的人脸检测评测数据集:FDDB,这个集合共包含2845张带有人脸的互联网新闻图像,一共标注了5171张人脸,其中的人脸在姿态、表情、光照、清晰度、分辨率、遮挡程度等各个方面都存在非常大的多样性,贴近真实的应用场景,因而是一个非常具有挑战性的测试集。FDDB的推出激发人们在人脸检测任务上的研究热情,极大地促进了人脸检测技术的发展,在此后的几年间,新的人脸检测方法不断涌现,检测器在FDDB上的表现稳步提高。从100个误检时的检测率来看,从最初VJ人脸检测器的30%,发展到现在已经超过了90% —— 这意味着检测器每检测出50张人脸才会产生一个误检,这其中的进步是非常惊人的,而检测器之间的比拼还在继续。
深度学习
一、给目标检测带来的变革
从2006年开始逐步蔓延开的深度学习大爆发给目标检测的研究带来了强劲的助推力,使得通用的目标检测以及各种特定类型目标的检测任务得到了跨越式地发展。
从神经网络到深度学习
从“深度学习”这一字面上可以看到,神经网络改头换面重出江湖,关键在一个“深”字上。
神经网络有一个非常大的特点,就是非线性激活函数的引入和层层嵌套,这使得其能够表示高度非线性(相对于输入而言)的函数,因而对于复杂的数据变化模式具有更强的建模能力。
早期的神经网络一般层数比较少(如3层的浅层网络),因为多层的深度网络学习起来非常困难,在各种任务上难以取得令人满意的表现,这一状况直到 2006 年才被打破。
在2006年,机器学习领域的泰斗 Geoffrey E.Hinton 教授在《科学》杂志上发表了题为《Reducing the Dimensionality of Data with Neural Networks》的论文,这一工作为深度网络的学习提供了一种有效的解决方案:
采用无监督的方式对网络进行逐层预训练,从而打开了学习深度网络的大门。
在接下来的几年中,人们对深度网络的热情已经高涨到了无以复加的地步,有关设计和学习深度网络的各种问题也逐一被解决,从初始化方式到优化方法,从激活函数到网络结构,科研工作者们对此产生了全方位的研究,使得深度网络的训练能够做得又快又好。由于对神经网络本身的探讨并不在本文所涉及的范畴之内,因此这里不再展开讨论,读者只需要将神经网络看成是一种具有更强非线性建模能力的模型即可。
神经网络分为很多种,上面提到的只是其中最简单一种:前馈神经网络 —— 也经常被简称为神经网络,因此神经网络这个名字很多时候指的仅仅是前馈网络这一种。
在计算机视觉领域,应用最成功的一种神经网络是卷积神经网络(CNN),其最大的特点就是引入了卷积操作,将前馈网络中的全连接替换为局部连接,在不同的连接之间进行权值共享:
将一个卷积核作用于一张图像时,卷积核就像检测时的观察窗口,
其从图像的左上角逐步滑动到右下角,
其滑动的每个位置对应于一个输出节点,
这个节点只和窗口内的输入节点(图像上每一个点都对应于一个输入节点)相连接,
而不同输出节点和对应输入节点连接的权值是相同的。
卷积神经网络在处理图像问题上具有得天独厚的优势,因为卷积操作可以自然地保留图像的空间信息,其只作用域局部,因而输出节点的空间结构和输入节点的空间结构是对应的,
而前馈神经网络则做不到这一点:输入节点的排列顺序甚至可以是任意的,只要相应地调换连接的权值,就能保证输出不变。CNN早在上世纪末就由著名的机器学习研究者Yann LeCun设计出来,并应用于手写数字的识别问题,不过其在计算机视觉领域大规模得到应用则源于2012年CNN在一般的图像分类任务上的巨大成功。
二、R-CNN 系列
在2013年底,深度学习给目标检测任务点起了一把火,这个火种就是R-CNN。
R对应于“Region(区域)”,意指CNN以图像区域作为输入,这个工作最终发展成了一个系列,也启发和衍生出了大量的后续工作,这一场大火简直烧红了计算机视觉领域的半边天。
(1). 候选窗口
R-CNN的提出变革了目标检测方法中很多旧有的做法,同时在标准的目标检测评测数据集上使检测精度得到了前所未有的提升。
在检测方法上的变革,首当其冲的是抛弃了滑动窗口范式,取而代之的是一个新的生成候选窗口的环节。
对于给定的图像,不再用一个滑动窗口去对图像进行扫描,枚举所有可能的情况, // F**k off, 难道前面的白看了?!
而是采用某种方式“提名”出一些候选窗口,在获得对待检测目标可接受的召回率的前提下,候选窗口的数量可以控制在几千个或者几百个。
从某种意义上讲,VJ 人脸检测器中多个分类器相级联,每一级分类器都在为接下来的一级分类器提名候选窗口,但是这和 R-CNN 所采用的生成候选窗口的方式有一个重要的区别:
实际上所有的窗口仍然都被检查了一遍,只是不断在排除,这是一种减法式的方案。
相比之下,R-CNN 采用的候选窗口生成方式,是根据图像的某些特征来猜测可能有哪些地方存在待检测的目标,以及这些目标有多大,这是一种从无到有的加法式的方案。
Selective Search是一种典型的候选窗口生成方法,其采用了图像分割的思路,简单地说:
先基于各种颜色特征将图像划分为多个小块,
然后自底向上地对不同的块进行合并,
在这个过程中,合并前后的每一个块都对应于一个候选窗口,
最后挑出最有可能包含待检测目标的窗口作为候选窗口。
(2). CNN来自动学习特征
第二点非常大的改变在特征提取上:不再采用人工设计的特征,而是用 CNN来自动学习特征。
特征提取过程就是从原始的输入图像(像素颜色值构成的矩阵)变换到特征向量的过程,
之前的如 Haar 特征等是科研工作者根据自己的经验和对研究对象的认识设计出来的,换言之人工定义了一个变换,而新的做法是只限定这个变换能够用CNN来表示
事实上 CNN 已经可以表示足够多足够复杂的变换,而不具体设计特征提取的细节,用训练数据来取代人的角色。这种自动学习特征的做法是深度学习一个非常鲜明的特色。
好处:
不仅避免了人工干预,解放了人力,而且有利于学习到更契合实际数据和目标的特征来,特征提取和分类两个环节可以相互促进,相辅相成;
坏处:
自动学习出的特征往往可解释性比较差,不能让人直观地去理解为什么这样提取出特征会更好,另外就是对训练集会产生一定程度的依赖。
(3). 边框回归
R-CNN在检测过程中引入了一个新的环节:边框回归(友情提醒:“框”念第四声,不是多音字!),检测不再仅仅是一个分类问题,它还是一个回归问题:
"回归和分类的区别就在于回归模型输出的不是离散的类别标签,而是连续的实数值。"
边框回归指的是在给定窗口的基础上去预测真实检测框的位置和大小,也就是说:
有了候选窗口之后,如果其被判别成了一个人脸窗口,那就会进一步被调整以得到更加精确的位置和大小——和待检测目标贴合得更好。
- 边框回归一方面提供了一个新的角度来定义检测任务,
- 另一方面对于提高检测结果的精确度有比较显著的作用。
Therefore, 用R-CNN进行目标检测的流程是:
1. 先采用如 Selective Search等方法生成候选窗口,
2. 然后用学习好的CNN提取候选窗口对应的特征,
3. 接着训练分类器基于提取的特征对候选窗口进行分类,
4. 最后对判别为人脸的窗口采用边框回归进行修正。
虽然R-CNN带来了目标检测精度的一次巨大提升,然而由于所采用的候选窗口生成方法和深度网络都具有比较高的计算复杂度,因而检测速度非常慢。
为了解决R-CNN的速度问题,紧接着出现了Fast R-CNN 和 Faster R-CNN,从名字上可以看到,它们的速度一个比一个快。
三、Fast R-CNN 和 Faster R-CNN
第一步加速是采用了类似于 VJ 人脸检测器中积分图的策略。
积分图是对应整张输入图像计算的,它就像一张表,在提取单个窗口的特征时,直接通过查表来获取所需要的数据,然后进行简单的计算即可。
-
- 在R-CNN中每个候选窗口都需要单独通过CNN来提取特征,当两个窗口之间有重叠部分时,重叠部分实际上被重复计算了两次,
- 在 Fast R-CNN 中,(这一策略的使用可以提供几十甚至上百倍的加速)
直接以整张图像作为输入,先得到整张图对应的卷积特征图,
然后对于每一个候选窗口,在提取特征时直接去整张图对应的卷积特征图上取出窗口对应的区域,从而避免重复计算,
之后只需要通过所谓的RoIPooling层来将所有的区域放缩到相同大小即可。
第二步加速,Fast R-CNN利用了一种名为 SVD 的矩阵分解技术,其作用是将一个大的矩阵(近似)拆解为三个小的矩阵的乘积,使得拆解之后三个矩阵的元素数目远小于原来大矩阵的元素数目,从而达到在计算矩阵乘法时降低计算量的目的,通过将 SVD应用于全连接层的权值矩阵,处理一张图片所需要的时间能够降低30%。
第三步加速,Faster R-CNN开始着眼于生成候选窗口的环节,其采用 CNN 来生成候选窗口,同时让其和分类、边框回归所使用的 CNN 共享卷积层,
这样使得两个步骤中可以使用同样的卷积特征图,从而极大地减少计算量。
除了采用各种策略进行加速,从R-CNN到Faster R-CNN,检测的框架和网络结构也在不断发生改变。R-CNN从整体框架上来说,和传统的检测方法没有本质区别,不同的环节由单独的模块来完成:
一个模块生成候选窗口(Selective Search),
一个模块进行特征提取(CNN),
一个模块对窗口进行分类(SVM),
一个模块做边框回归。
到Fast R-CNN的时候,后面三个模块合并成了一个模块,全部都用CNN来完成。因此整个系统实际上只剩下两个模块:
一个模块生成候选窗口,
另一个模块直接对窗口进行分类和修正。
再到Faster R-CNN,所有的模块都整合到了一个CNN中来完成,形成了一种端到端的框架:
直接从输入图像通过一个模型得到最终的检测结果,
"这种多任务在同一个模型中共同学习的做法,能够有效利用任务之间的相关性,达到相辅相成、相得益彰的效果。"
从 R-CNN 到 Faster R-CNN,这是一个化零为整的过程,其之所以能够成功,
- 一方面得益于CNN强大的非线性建模能力,能够学习出契合各种不同子任务的特征,
- 另一方面也是因为人们认识和思考检测问题的角度在不断发生改变,打破旧有滑动窗口的框架,将检测看成一个回归问题,不同任务之间的耦合。
尽管目前 Faster R-CNN在速度上仍然无法和采用非深度学习方法的检测器相比,但是随着硬件计算能力的不断提升和新的CNN加速策略的接连出现,速度问题在不久的将来一定能够得到解决。
四、全卷积网络 FCN
卷积层是CNN区别于其它类型神经网络的本质特点,不过CNN通常也不仅仅只包含卷积层,其也会包含全连接层,
全连接层的坏处就在于其会破坏图像的空间结构,因此人们便开始用卷积层来“替代”全连接层,通常采用1 × 1的卷积核,这种不包含全连接层的CNN称为全卷积网络(FCN)。
FCN最初是用于图像分割任务,之后开始在计算机视觉领域的各种问题上得到应用,事实上,Faster R-CNN中用来生成候选窗口的CNN就是一个FCN。
FCN 的特点就在于
-
- 输入和输出都是二维的图像,
- 输出和输入具有相对应的空间结构,
在这种情况下,我们可以将 FCN 的输出看成是一张热度图,用热度来指示待检测目标的位置和覆盖的区域:
-
- 在目标所处的区域内显示较高的热度,
- 在背景区域显示较低的热度,
五、目标检测器 DenseBox
这也可以看成是对图像上的每一个像素点都进行了分类:这个点是否位于待检测的目标上。
DenseBox是一个典型的基于全卷积网络的目标检测器,其
- 通过 FCN得到待检测目标的热度图,
- 然后根据热度图来获得目标的位置和大小,
这给目标检测又提供了一种新的问题解决思路。(下面这张图其实来源于另一篇论文,放在这里仅用来帮助读者了解人脸热度图长什么样子。)
在DenseBox中,还有一点值得一提,其在分类的同时还会预测特征点的位置——就像 JointCascade一样,DenseBox将检测和特征点定位两个任务集成在同一个网络中,并且也用热图的方式来确定每个点的位置。
基于CNN的人脸检测器
一、FacenessNet 人脸检测器
上面提到的都是通用的目标检测器,这些检测器可以直接通过人脸图像来学习从而得到人脸检测器,虽然它们没有考虑人脸本身的特殊性,但是也能够获得非常好的精度,这反映出不同类型目标的检测其实是相通的,存在一套通用的机制来处理目标检测问题。也有一部分工作是专门针对人脸检测任务的,有的考虑了人脸自身的特点,有的其实也是比较通用的目标检测方法,可以自然地迁移到各种类型目标的检测任务中去。
FacenessNet 是专门针对人脸设计的一个检测器,其考虑了头发、眼睛、鼻子、嘴巴和胡子这五个脸部特征,
简单地说,对于一个候选窗口,FacenessNet 先分析这五个部分是否存在,然后再进一步判断是不是一张人脸。
Figure, Faceness-Net: Face Detection through Deep Facial Part Responses
这种方法:
-
- 一方面同时利用了整体和局部的信息,能够从不同的角度对图像内容进行刻画,使得人脸和非人脸能够更好地被区分;
- 另一方面增强了对遮挡的鲁棒性,人脸的局部遮挡会影响整体表现出的特征,但是并不会对所有的局部区域造成影响,因而增强了检测器对遮挡的容忍度。
二、检测精度的大跃进
随着越来越多的检测器开始采用深度网络,人脸检测的精度也开始大幅地提升。
在2014年,学术界在FDDB上取得的最好检测精度是在100个误检时达到84%的检测率,达到这一精度的是JointCascade 人脸检测器。
到2015年,这一纪录被FacenessNet 打破,在100个误检时,检测率接近88%,提升了几乎4个百分点。
不仅如此,工业界的最好记录已经达到了100个误检时92.5%的检测率 (估计是通过额外的人脸数据库),检测率达到 90%以上的公司还不止一家,并且这些结果都是通过基于深度网络的人脸检测器所获得的。
在大幅提升人脸检测精度的同时,深度学习实际上还降低了包括人脸检测技术在内的各种目标检测技术的门槛,几乎到了只要采用深度网络就能获得不错的检测精度的地步;
在精度方面,相比于基于非深度学习方法的检测器,基于深度学习方法的检测器在起点上就要高出一截。
不过在检测速度方面,基于深度学习方法的检测器还难以达到实际应用的需求,即使是在GPU上,也还不能以实时的速度(25fps)运行;
而反过来看,一旦速度问题能够得到解决,那么深度学习也一定会在目标检测任务上有更广泛和更大规模的应用。
三、传统人脸检测技术和 CNN 的结合
VJ人脸检测器自提出以来,启发和影响了后续的大量工作,所引入的积分图、AdaBoost方法、级联结构等至今仍在各种各样的检测器中以不同的形式被使用。
传统的人脸检测技术优势在于速度,而在精度上则相比基于深度网络的方法要略输一筹,
在这种情况下,一个自然的想法就是:“ 能否将传统的人脸检测技术和深度网络(如CNN)相结合,在保证检测速度的情况下进一步提升精度? ”
Cascade CNN可以认为是传统技术和深度网络相结合的一个代表,
和VJ人脸检测器一样,其包含了多个分类器,这些分类器采用级联结构进行组织,然而不同的地方在于,Cascade CNN采用CNN作为每一级的分类器,而不是用AdaBoost方法通过多个弱分类器组合成的强分类器,并且也不再有单独的特征提取过程,特征提取和分类都由CNN来统一完成。
1. 在检测过程中,Cascade CNN采用的还是传统的滑动窗口范式,为了避免过高的计算开销,第一级的CNN仅包含一个卷积层和一个全连接层,并且输入图像的尺寸控制在12*12,同时滑动窗口的步长设置为4个像素,在这种情况下,
一方面每张图像上候选窗口的数量变少了,窗口数量随着滑动步长的增大是按照平方规律下降的,
另一方面每个窗口提取特征和分类的计算开销也受到了严格控制。
2. 经过第一级CNN之后,由于通过的窗口中人脸和非人脸窗口之间更加难以区分,因此第二级CNN将输入图像的尺寸增大到了24*24,以利用更多的信息,并且提高了网络复杂度——虽然仍然只包含一个卷积层和一个全连接层,但是卷积层有更多的卷积核,全连接层有更多的节点。
3. 第三级CNN也采用了类似的思路,增大输入图像大小的同时提高网络的复杂度 —— 采用了两个卷积层和一个全连接层。通过引入CNN,传统的级联结构也焕发出了新的光彩,在FDDB上,Cascade CNN在产生100个误检的时候达到了85%的检测率,而在速度上,对于大小为640*480的图像,在限定可检测的最小人脸大小为80*80的条件下,Cascade CNN在CPU上能够保持接近10fps的处理速度。Cascade CNN中还采用了一些其它的技术来保证检测的精度和速度,如多尺度融合、边框校准、非极大值抑制等,限于篇幅,这里不再继续展开。
吸取传统人脸检测技术中的精华,借鉴深度学习研究的最新成果,在对问题的深刻思考和理解上,探寻旧瓶装新酒的最佳模式,这是一条值得去继续探索的道路。
四、对现状和未来的简单思考
经过几十年的研究和发展,人脸检测方法正日趋成熟,在现实场景中也已经得到了比较广泛的应用,但是人脸检测问题还并没有被完全解决,
复杂多样的姿态变化,
千奇百怪的遮挡情况,
捉摸不定的光照条件,
不同的分辨率,
迥异的清晰度,
微妙的肤色差,
各种内外因素的共同作用让人脸的变化模式变得极其丰富,而目前还没有检测器可以同时对所有的变化模式都足够鲁棒。
五、数据集
FDDB
Ref: FDDB: Face Detection Data Set and Benchmark
目前的人脸检测器在FDDB上已经能够取得不错的性能,不少检测器在100个误检时的检测率达到了80%以上,这意味着它们检测出40个以上的人脸才会出现一个误检。
到目前为止,本文所提到的误检和召回率都对应于FDDB上的离散型得分ROC曲线,所谓“离散型”是指每个人脸是否被检测到是分别用1和0来表示的;相对应地也有连续型得分ROC曲线,而“连续型”指的是人脸被检测到与否是通过检测框和标注框之间的交并比来表示的,从某种意义上来说,连续型得分试图评判的是检测框的准确程度,即检测框的位置和大小与实际人脸的位置和大小的接近程度。对于两个不同的检测器而言,两类曲线的相对关系并非是完全一致的:离散型得分ROC曲线接近的两个检测器,其对应的连续型得分ROC曲线可能存在明显的差异。最直接地,这说明有的检测器虽然检测出了人脸,但是检测框的准确度比较低,但其实造成这种不一致性的另一个重要原因还在于检测框与标注框之间的差异性。
在FDDB中人脸是通过椭圆来进行标注的,大多数情况下,几乎会包含整个头部,相比之下,检测器给出的检测结果是矩形的人脸框,并且通常只包含脸部区域——尤其是对于采用滑动窗口范式的检测器,这就很容易导致检测框和标注椭圆之间的交并比过小,甚至可能小于0.5。对不同的检测器来说,其能够最好地区分人脸和非人脸窗口的情况所对应的框的大小会有所不同,从而不同检测器给出的检测框也会存在差别,部分方法会采用扩大检测框或者回归椭圆的方式,以尽量减小由标注框和检测框的不一致性所造成的影响,保证评测的公平性。
除了标注框的问题之外,要更为客观地看待FDDB上的评测结果,我们还需要考虑另外一点:FDDB测试图像上的人脸和实际应用场景的差异性,换言之,我们需要思考这样一个问题:人脸检测器在FDDB上所达到的精度能否真实反映其在实际应用场景中的表现?FDDB中测试图像上的人脸包含了从表情到姿态、从光照到遮挡等各个方面的变化,因而是一个相对通用的数据集,但是在实际应用中,不同场景下人脸往往呈现出比较鲜明的特点,例如在视频监控场景下,由于摄像头架设位置较高和分辨率有限,同时在存储和传输过程中会引入噪声,因此图像上的人脸往往具有较大的俯仰角,且清晰度较低,在这种情况下,原来在FDDB上表现出色的检测器就未必能够达到令人满意的精度。在FDDB中,有大约10%的人脸其大小在40*40以下,而对于人脸识别等一些任务来说,太小的人脸并不适合,因此如果一个检测器因为在小脸上表现不好而导致其在FDDB上表现平平,而在较大的人脸上和表现更好的一些检测器没有太大差别,那么将其应用在人脸识别任务中是完全没有问题的,甚至还可能因为模型简单带来速度上的优势。
总而言之,当面对具体的应用场景时,
-
- 一方面,我们还需要具体问题具体分析,不能盲目地根据检测器在FDDB或者其它人脸检测数据集上精度来下结论;
- 另一方面,我们需要基于当前的人脸检测器去适配实际所需要处理的数据,以使检测器能够在特定的场景下达到更好的精度。
AFW
Ref: WIDER FACE: A Face Detection Benchmark
除了FDDB之外,比较常用的人脸检测评测集还有AFW,以及最近几年公开的MALF、IJB-A和Wider Face。
AFW 包含的图像数比较少,总共只有205张测试图像,标注了468张人脸,不过由于其覆盖了众多的人脸变化模式,具有一定的挑战性,因此也比较常用。
另外三个评测集在图像规模上都相对较大,其中MALF和Wider Face没有发布人脸标注和评测程序,需要提交检测结果给发布方进行评测,这在一定程度上防止了由于评测方式不一致而导致比较不公平和对测试集进行过拟合的情况;这两个数据集还按照不同的属性(如分辨率、姿态、难易程度等)将测试集分成了多个子集,评测时会同时在全集和子集上进行测试,这能够更加全面地反映检测器在不同场景下的能力。
IJB-A中不仅包含静态人脸图像,还有一部分是从视频中提取的视频帧。
在上面提到的所有评测集中,只有Wider Face提供了专门的训练集和验证集,其它评测集合都只包含测试集,
这其实也给不同方法的比较带来了一个问题:
-
- 我们难以判断导致检测器在精度上存在差异的原因到底是训练数据还是算法和模型本身,
- 也不知道这两方面的因素谁起的作用更大。
Wider Face应该是难度最大的一个评测集,所标注的人脸在姿态、遮挡情况等方面的跨度非常大,并且分辨率在50*50以下的人脸占到了50%(训练集和校验集中达到了80%以上),不过在部分应用场景下(如人脸识别),过于关注小尺寸的人脸并没有必要。
虽然基于深度网络的检测器目前能够达到很高的检测精度,并且其通用性非常强,但其所付出的计算代价也非常高,因此这类检测器突破的关键在于深度网络的简化和加速。
除此之外,如果单单考虑人脸检测,这个分类问题相对来说要简单一些,也存在一种可能性:直接学习一个小型的网络就能足够好地完成这个任务。
对于采用非深度学习方法的检测器,其基础的检测精度相比会低不少,但是速度上会有明显的优势,因此其关键在于针对特定应用场景下的问题进行合理的改进和适配,以获得更好的检测精度。
为了提供更加便利的人机交互接口,创造有效的视觉理解手段,让机器变得有温度,会观察,能感受,广大的科研工作者们在人脸检测和通用目标检测任务上还在继续探索。终有一天,当我们和机器四目相对时,彼此能够会心一笑:科学让生活更美好!
消化了整整一白天,你以为就此结束了么?
No... 后续的并行算法、GPU优化等还在向你招手 -_-b
路漫漫其修远兮...
《人脸识别简史与近期进展》
---- 读完上文再读此文,理解加深。
一、远古历史
自动人脸识别的经典流程:
人脸检测 --> 面部特征点定位(又称Face Alignment人脸对齐) --> 特征提取 --> 分类器设计。
在深度学习出现以前,
人脸识别方法一般分为高维人工特征提取(例如:LBP, Gabor等)和降维(PCA, LDA等子空间学习方法和LPP等流行学习方法)两个步骤。
2013年之前,主要技术路线为人造或基于学习的局部描述子+测度学习。
在深度学习方法流行之后,
代表性方法为从原始的图像空间直接学习判别性的人脸表示。
一般而言,人脸识别的研究历史可以分为三个阶段。
在第一阶段(1950s-1980s),人脸识别被当作一个一般性的模式识别问题,主流技术基于人脸的几何结构特征。
在第二阶段(1990s)人脸识别迅速发展,出现了很多经典的方法,例如Eigen Face, Fisher Face和弹性图匹配,此时主流的技术路线为人脸表观建模。
在第三阶段(1990s末期到现在),人脸识别的研究不断深入,研究者开始关注面向真实条件的人脸识别问题,主要包括以下四个方面的研究:
1)提出不同的人脸空间模型,包括以线性判别分析为代表的线性建模方法,以Kernel方法为代表的非线性建模方法和基于3D信息的3D人脸识别方法。
2)深入分析和研究影响人脸识别的因素,包括光照不变人脸识别、姿态不变人脸识别和表情不变人脸识别等。
3)利用新的特征表示,包括局部描述子(Gabor Face, LBP Face等)和深度学习方法。
4)利用新的数据源,例如基于视频的人脸识别和基于素描、近红外图像的人脸识别。
在前DL时代,以VIPL实验室三代半SDK为例,关键技术点包括
1)分块人脸特征融合:Gabor特征+LPQ特征。
2)子空间学习进行特征降(PCA+LDA)。
3)融合多尺度的人脸归一化模板。
SDK3.5的相关技术在FRGC实验4上取得了0.1%错误接受率条件下96%的确认率,至今依然是FRGC数据集上最好结果。
在前DL时代,利用浅层模型从图像中直接学习表示和基于人造描述子学习语义表示(例如学习中层属性表示的Attributes and Simile Classifier和学习高层语义表示的Tom-vs-Pete)的工作都见于相关文献。
二、近代发展
2014年以来,深度学习+大数据(海量的有标注人脸数据)成为人脸识别领域的主流技术路线,其中两个重要的趋势为:
1)网络变大变深(VGGFace 16层,FaceNet 22层)。
2)数据量不断增大(DeepFace 400万,FaceNet 2亿),大数据成为提升人脸识别性能的关键。
2014年,Facebook发表于CVPR14的工作DeepFace将大数据(400万人脸数据)与深度卷积网络相结合,在LFW数据集上逼近了人类的识别精度。
其中DeepFace还引入了一个Local Connected卷积结构,在每个空间位置学习单独的卷积核,缺点是会导致参数膨胀,这个结构后来并没有流行起来。
DeepID家族可以看作是DL时代人脸识别领域的一组代表性工作。
最早的DeepID网络包括四个卷积层,采用softmax损失函数。
DeepID2在DeepID网络的基础上,同时考虑了分类损失(identity loss) 和确认损失(verification loss), 这两种损失在Caffe深度学习框架中分别可以采用softmaxwithloss层和contrastive loss层来实现。
DeepID2+网络则是在DeepID2的基础上,增加了每一层的辅助损失函数(类似Deep Supervised Network)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
2014年的三个逆天结果,deepface的97.25%、face++的97.27%、gaussianface的98.52%,前两者都用了deep learning。第一个训练数据400万。第二个算法细节不明,但deeplearning向来吃样本,想来训练库也是百万量级。唯有gaussianface的训练库仅2万余。
From
GaussianFace(下面用GF表示)的核心在于高斯过程(Gaussian Processes,GPs)[10]的应用,包括Gaussian Processes for classification 和 Gaussian Process Latent Variable Model (高斯过程隐变量模型,GPLVM),其优点如下:
高斯过程是一种基于核函数的方法,是一种非参数概率模型,具有完全的贝叶斯公式化表示;根据训练样本,可以从先验分布转换到后验分布,不仅能对未知输入做输出预测,同时也能给出该预测的精度参数。(原文描述为:Moreover, the GaussianFace model is a reformulation based on the Gaussian Processes (GPs), which is a non-parametric Bayesian kernel method)
GPLVM的特性在于,当观测数据的样本个数比较少时,仍然可以用来寻找观测数据的低维流形,也就是说GPLVM非常适合处理小样本的高维数据。这就是GF只需要少量样本(约40000),便在LFW上取得 了良好的结果;
相比于SVM的参数需要通过交叉验证方法或者经验法得到,高斯过程隐变量模型中需要确定的模型参数包括核函数中的超参数((hyper parameter)和隐变量Z,采用的方法是共扼梯度优化法( Conjugate Gradient);至于神经网络或深度学习,那更是门调参数的艺术;
Google发表于CVPR2015的工作FaceNet采用了22层的深层卷积网络和海量的人脸数据(800万人的2亿张图像)以及常用于图像检索任务的Triplet Loss损失函数。
值得一提的是,由于人脸类别数达到800万类,如果使用softmax loss,输出层节点将达到800万个,需要至少32GB显存(假设上一个隐层节点1024个,采用单精度浮点数),而Triplet Loss则不需要额外占用显存。
FaceNet 在LFW数据集上十折平均精度达到99.63%,这也是迄今为止正式发表的论文中的最好结果,几乎宣告了LFW上从2008年到2015年长达8年之久的性能竞赛的结束。
End.