怎么把人脸检测的速度做到极致

转载自:

【技术共享】怎么把人脸检测的速度做到极致 

 http://mp.weixin.qq.com/s?__biz=MzA3NDU3MTc1Ng==&mid=2651165778&idx=1&sn=2f2d8f6b7a11d381a4290a20817b46a2&scene=1&srcid=0622IC1saFdptInN9wrp2xDP&from=groupmessage&isappinstalled=0#wechat_redirect


怎么把人脸检测的速度做到极致_第1张图片

首先,我承认这个题目有点标题党。之所以写这篇,因为发现微信微博上有很多公司介绍他们的技术,但都是说如何如何牛,但缺少技术细节,对读者帮助有限。因此写一点相对干货多的东西,希望能帮助大家。如有谬误,也请大家多加指正。

 

下面的内容适合正在用Boosting方法做目标检测的读者,也适合对提升算法速度感兴趣的读者。下面的这些内容,都已经应用到我们的人脸检测算法中,对于提升算法速度发挥了巨大作用。OpenCV中的检测速度是21.2毫秒;同样条件下,我们的算法速度是3.6毫秒,速度接近6倍,且检测准确率高很多。

 

阅读下面的内容之前,首先要区分两个概念“人脸检测/face detection”和“人脸识别/face recognition”。“人脸检测”是从图像中确定人脸的位置和大小,如下图所示;“人脸识别”是识别图像中的人脸是张三还是李四,是身份识别。

怎么把人脸检测的速度做到极致_第2张图片


人脸检测是一个非常经典的问题,很多人认为这是一个“已经解决”了的问题。人脸检测最经典的方法是Haar+AdaBoost。采用开源的Haar+AdaBoost实现(如OpenCV中的训练和检测程序),我们可以很容易的训练一个还算不错的人脸检测器。但是,一旦将人脸检测技术投入实际应用,一系列问题便会冒出来。如(1)误检(把非人脸的物体当作人脸)较多,非人脸图像当作人脸送入后续算法,会引起一系列不良后果。(2)漏检问题,例如戴墨镜、大胡子、逆光条件、黑种人、倾斜姿态较大的脸无法检测到。(3)速度问题,虽很多人脸检测算法的速度已经很快,但在一个人脸分析(如人脸识别)系统中,人脸检测步骤的计算量往往超过50%。大部分检测算法采用窗口扫描的方式,窗口数目巨大,所以计算量居高不下。很多系统运行在低功耗平台,对计算量尤其敏感。假如手机一拍照片就发烫就很不好。

 

下图中人脸因为有墨镜和大胡子遮挡,加上角度倾斜,较难检测。图中红框本不是人脸,如被当作人脸,则是误检测。


下面介绍一下我们设计Boosting人脸检测方法的一些心得体会:

 

一、特征设计

特征设计是重中之重,如果特征从原理上就是计算量大,后面无论如何优化,都很难降计算量。

 

先说Haar特征,毫无疑问Haar特征用在人脸检测里具有里程碑式的意义。但现在看Haar特征,会发现它有一些明显的缺点。Haar特征是一种很弱的特征,这意味着需要很多特征组合在一起才能构成强分类器,对提升速度不利;如果正样本分布比较分散比较难区分时(例如正面侧面人脸全放进去),用这种弱特征分类会比较吃力。此外,在Haar特征的实现中,为了解决亮度归一化问题,需计算像素值的平方和(square sum),平方和需要64位整数来存储;还需要开方(sqrt)运算。64位整数运算和开方运算,对很多嵌入式系统来讲,都是高计算量操作。



HOG特征是一个描述能力特别强的特征,也可以用在人脸检测上。HOG特征需要计算梯度的方向和长度。计算方向需要ctan三角函数(可用查表法加速)以及开方操作。统计直方图时,为了效果好,需要soft voting加权投票。因此HOG是强描述特征,但特征提取的计算量较大。


   (图片来自
http://dlib.net


LBP是一个好特征,描述能力强,特征提取仅需要逻辑运算和加法运算,值得推荐!LBP依然有吐槽点。如果你实现Multi-Block LBP,需要积分图来加速。积分图是很多算法的加速武器,但构建积分图时,很难用SIMD(单指令多数据)指令优化。



前面三种特征的对比分析,是为了说明好的特征要表达能力强且计算简单。很多二值特征(Binary feature)符合这一特点。我也偏好二值特征。二值特征还可以天然地解决图像的亮度变化问题,不需要事先对图像进行亮度均衡化。(例如使用Haar+AdaBoost检测人脸前,先对图像做直方图均衡化再检测,效果会好很多,不信你去试。)

 

二、样本

很多论文中会洋洋洒洒地介绍算法的先进性,但很少有论文分析样本对结果的影响。可能分析样本显得很工程化很low吧。而描述样本在高维特征空间的分布,应该是很多模式识别问题的核心问题。


好,不谈理论谈经验。样本选择是一般人不提的重要事情。如果你用手机自拍照片训练人脸检测器,应用在视频监控中,一般效果不会太好;如果你对所有人脸样本进行人脸对齐,要求双目绝对水平,那么训练出的分类器速度会比较快,但不能处理人脸姿态变化。即人脸样本越单一,训练出的分类器的速度会越快,但正确检测率低;如果样本复杂,速度变慢但检测率升高。如何平衡样本的复杂性和检测速度,需要针对具体应用斟酌。

 

此外负样本也很关键。如果你从几千张风景图里抠图作为负样本进行训练,那么基本上会overfitting,即训练时误检率很低,但实际应用时误检率比较高。要准确刻画非人脸图像,负样本的规模一定要大,负样本的内容一定要多样化!我们平时训练用的负样本图像大约有20GB,包含各种内容的图像。

 

三、分类器训练

这个可说的不多,Boosting方法就那些,可以尝试各种Boosting方法和各种参数,找到合适的。

 

后面会说说代码层面的优化。

 

四、代码优化:消灭重复计算

 

通过分析工具,找出最影响速度的代码段,有针对性地优化。一般来说是判断窗口是否是人脸的代码最耗时,因为调用次数最多。代码里首先要消灭的是重复计算,如代码

int b1 = pixels[y*step + x] - pixels[y*step + x + 1];

int b2 = pixels[y*step + x + 2] - pixels[y*step + x + 3];

可以写为

int offset = y *step + x;

int b1 =pixels[offset] - pixels[offset+1];

int b2 = pixels[offset+2] - pixels[offset+3];

 

五、代码优化:展开循环

如果循环次数是固定的,可以去掉for循环,直接展开。代码行数虽然多了,但是少了for循环的条件判断,可以加速,例如可加速10%-20%。另外可以在设计分类器的时候,就把这些因素考虑进去,由训练程序生成的强分类器包含固定数目的弱分类器,或者某种规律数目的弱分类器,这样有利于检测代码优化。

 

六、代码优化:利用SIMD指令

无论Intel CPU还是ARM CPU,都有SIMD(单指令多数据)指令。利用这些指令,可以一次算多个数据。例如两个BYTE向量相加,支持128位的SIMD指令可以一次算16BYTE的加法,理论上可以加速16倍。我们常用的加速利器积分图,它的构建过程很难用SIMD加速。如果你有更好的策略,可以果断抛弃积分图。

 

七、代码优化:多核并行运算

OpenMP或者Intel TBB可以让我们充分利用CPU的多个内核进行并行运算,提升速度。但用了OpenMPTBB,未必可以加速,或未必可以加速到期望的倍数。多核并行,任务的拆分的粒度应该尽可能粗,不同的任务尽可能不用同一块内存,也就是任务之间的相关度低一些有利于加速。

 

举给例子:如果两个矩阵相加,按像素进行并行操作,加速效果会很糟糕;如果按行并行,效果会好很多,但不要按列并行!

 

八、代码优化:定点化

有些低功耗嵌入式系统不支持硬件浮点运算,特征提取和分类器设计应尽可能避免浮点运算。不可避免的浮点数可以转为定点数,当然这会损失精度。我们曾经将float类型转为8位整数,而准确率无明显影响。

 

九、代码优化:GPU优化

GPUCPU不同,有自己独特的特点。GPU特别适合做无复杂逻辑但计算量大的事情。例如图像resize、图像滤波等。Boosting算法可以运行在GPU上,并获得加速,但GPU加速Boosting优势并没有你想象的明显。Boosting算法中逻辑分支较多,也就是有不定长的for循环,有if-else判断;并行的时候每个运算单元运算量并不相同,有些运行时间长,有些运行时间短。运行时间短的要等运行时间长的。我们做了很多努力,GPU版本(低端GTX750i显卡)速度大约可以做到CPU版本(i7多核并行)的6倍左右。跟OpenCV中用GPU加速Haar+Adaboost的倍数一致,而没有达到期望的几十倍加速。

  

十、吐槽:非连续内存读写

读写非连续内存,速度可能变慢。如下图Haar积分图计算像素和的公式是D-B-C+A,需要读4个元素值,但这4个值在内存里并不连续,特别是AD距离较远,这样降低了CPU缓存的命中率,也就降低了速度。对缓存小的低价位CPU影响尤为明显。虽然公式D-B-C+A的计算量跟E-F-G-H相同,但一般来说后者速度会快。此外,Boosting方法选出的多个弱特征,在图像上往往也不相邻,同样是低效的非连续内存的读写,这是Boosting类方法的一个缺点。

怎么把人脸检测的速度做到极致_第3张图片


十一、未来展望

到目前为止,Boosting方法在人脸检测中依然具有明显的速度优势。但基于深度学习的目标检测方法进展迅速,不容小视。深度学习的方法可以很容易地获得非常高的准确率,如在FDDB人脸检测评库上,传统方法能达到85%准确率就非常高了,但深度学习方法可以轻松超过90%,甚至超过95%。如果想兼顾速度和准确率,传统方法和深度学习的方法结合也许是一个思路,现在已经有一些这样的尝试了。此外,CNN专用硬件应可以弥补深度学习方法的劣势。

 

十二、插播广告

我们的人脸检测库libfacedetection,以二进制的方式免费发布。该库调用非常简单,只有一个函数,纯C语言编译而成,不依赖任何第三方库。通过连续的优化,我们的人脸检测算法可以做到3.6毫秒处理一张VGA图像(最小48x48人脸)。您可将这个库应用到您的系统中,无论是科研目的还是商业目的,均无任何限制。详情请访问https://github.com/ShiqiYu/libfacedetection。下图是我们的算法在FDDB上的评测曲线。

怎么把人脸检测的速度做到极致_第4张图片

************************************************************************************ 

作者简介:

于仕琪 博士、副教授,深圳大学计算机与软件学院计算机视觉研究所,专注于图像中的目标检测。Email[email protected]

************************************************************************************


你可能感兴趣的:(目标检测(Object,Detection))