什么是最好的面部检测器? | Dlib、OpenCV DNN、Yunet、Pytorch-MTCNN和RetinaFace

点击下方卡片,关注“小白玩转Python”公众号

我正在处理的面部识别问题,需要选择一个面部检测模型。面部检测是面部识别流水线的第一步,准确识别图像中的面部至关重要。Garbage in, garbage out。

然而,众多的选项让我感到不知所措,而且关于这一主题的零散写作还不够详细,无法帮助我决定选择哪种模型。比较各种模型花费了我很多精力,因此我认为传达我的研究可能会帮助处于类似情况的人们。

面部检测器的选择要点是什么? 

选择面部检测模型时的主要权衡是准确性和性能之间的平衡。但还有其他因素需要考虑。关于面部检测模型的大多数文章要么是模型创建者写的,通常发表在期刊上,要么是那些在代码中实现模型的人写的。在这两种情况下,作者自然会对他们所写的模型持有偏见。在一些极端情况下,这些文章实际上是该模型的宣传广告。

很少有文章比较不同模型的性能表现。进一步增加混乱的是,每当有人写关于像RetinaFace这样的模型时,他们讨论的是该模型的特定实现。模型本身实际上是神经网络架构,不同的实现可能会导致不同的结果。更复杂的是,这些模型的性能还取决于后处理参数,如置信度阈值、非极大值抑制等。

每个作者都将自己的模型描述为“最好”,但我很快意识到“最好”取决于上下文。没有客观上最好的模型。决定哪个面部检测模型最合适的两个主要标准是准确性和速度。

没有一个模型能同时具备高准确性和高速度,这是一个权衡。我们还必须查看原始准确性之外的指标,大多数基准测试基于原始准确性(正确猜测/总样本量),但原始准确性不是唯一需要关注的指标。假阳性与真阳性的比率以及假阴性与真阴性的比率也是重要的考虑因素。用技术术语来说,这种权衡是精度(最小化假阳性)和召回率(最小化假阴性)之间的权衡。这篇文章深入讨论了这个问题。

测试模型 

有一些现有的用于基准测试的面部检测数据集,如WIDER FACE,但我总是喜欢看看这些模型在我的数据上表现如何。所以我随机选取了1064帧电视节目样本来测试这些模型(±3%的误差范围)。在手动标注每张图像时,我尽量选择尽可能多的面部,包括部分或几乎完全遮挡的面部,以给模型带来真正的挑战。因为我最终要对检测到的面部进行面部识别,所以我想测试每个模型的极限。

数据和标注可以从下面链接进行下载:

  • https://drive.google.com/uc?export=download&id=1OPAT47OXjgmjKlAY2irQLf4GNoHyMlhX(数据)

  • https://drive.google.com/uc?export=download&id=1UbrndfOvvzFIdU-w3Kw8qrFM6D_ZljJZ(标注)

将各种模型分为两类是有帮助的;那些运行在GPU上的模型和那些运行在CPU上的模型。一般来说,如果你有兼容CUDA的GPU,应该使用基于GPU的模型。我有一个NVIDIA 1080 TI显卡,具有11GB内存,这使我能够使用一些大规模的模型。然而,我的项目规模巨大(我指的是成千上万的视频文件),所以对速度极快的基于CPU的模型很感兴趣。基于CPU的面部检测模型不多,所以我决定只测试最受欢迎的一个:YuNet。由于其速度,YuNet构成了我的基线比较。一个GPU模型必须比其CPU对应的模型准确得多,以证明其较慢的处理速度是合理的。

CPU模型 

YuNet 

YuNet是为性能而开发的,其模型大小仅为较大模型的一小部分。例如,YuNet只有75,856个参数,而RetinaFace则有27,293,600个参数,这使得YuNet可以在“边缘”计算设备上运行,而这些设备不足以运行较大的模型。

a186945884c5c889d684ddf708cb859a.png

  • 论文地址:https://doi.org/10.1007/s11633-023-1423-y

  • 代码地址:https://github.com/ShiqiYu/libfacedetection

  • 预训练模型:https://github.com/opencv/opencv_zoo

作为一个CPU模型,YuNet的表现比我预期的要好得多。它能够毫无问题地检测到大面部,但在检测较小面部时有些困难。

e85e4a82b52c3a8392058ebd7747a546.jpeg

能够检测到即使在斜角度的大面部。边界框有些偏差,可能是因为图像需要调整为300x300才能输入到模型中。

a2d0b651feabf89e6acdbf489bc2f3be.jpeg

YuNet几乎找到了所有面部,但也包括了一些假阳性。

f6e1ff6d7fddb8d71f126ab649b3a956.png

当限制为图像中的最大面部时,准确性大大提高。

b6ccfda3746938e44d2c916aa922f161.png

如果性能是主要考虑因素,YuNet是一个很好的选择。它甚至足够快,可以用于实时应用,而GPU选项则不能(至少在没有一些严重硬件的情况下)。

709c9115559cb0b2b7bc6c95941a1fe3.png

YuNet使用固定的300x300输入尺寸,因此时间差异是由于将图像调整为这些尺寸导致的。GPU模型 

Dlib 

Dlib是一个C++实现,带有Python包装器,保持了准确性、性能和便利性之间的平衡。Dlib可以直接通过Python安装,也可以通过Face Recognition Python库访问。然而,Dlib的准确性和性能在upsampling参数上有很强的权衡。当上采样次数设置为0时,模型速度更快但准确性较低。

无上采样

e70c9f3d5003604c5dc9a7ee50e98ea0.png

9fc8493ca7b5178607cd0b32ab202af7.png

30cc8360357503f2158cebd486b2beb2.png

上采样=1

9a448740ad23ff8ef9e434cb1a87c890.png

9c61b195e9de4f8a2413d6e9014ce40b.png

67531ddfa9e533689b5ddd2daa307296.png

Dlib模型的准确性随着进一步的上采样而增加,但任何高于上采样=1的值都会导致我的脚本崩溃,因为它超出了我的GPU内存(顺便说一下,我的内存是11GB)。

Dlib的准确性相对于其(缺乏)速度来说有些令人失望。然而,它在最小化假阳性方面表现非常好,这是我的优先事项。面部检测是我面部识别流水线的第一部分,因此最小化假阳性数量将有助于减少下游的错误。为了进一步减少假阳性数量,我们可以使用Dlib的置信度输出来过滤低置信度的样本。

39a40c14878388678657b6f43506e8b7.png

假阳性和真阳性之间的置信度差异很大,我们可以利用这一点来过滤前者。我们可以查看置信度分布来选择一个更精确的阈值,而不是选择一个任意的阈值。

8d5a52bc749a645d3ccf6bf6c3788e35.png

95%的置信度值在0.78以上,因此排除低于该值的所有内容可以将假阳性数量减少一半。

7dd4f49cc761b9d8a8442402c551e39e.png

虽然通过置信度过滤减少了假阳性数量,但并没有提高整体准确性。我会考虑在最小化假阳性数量是主要关注点时使用Dlib。但除此之外,Dlib在准确性上并没有比YuNet大幅增加,无法证明其更高的处理时间是合理的;至少对我的用途来说是这样。

OpenCV DNN 

OpenCV面部检测模型的主要吸引力在于其速度。然而,其准确性令人失望。虽然与其他GPU模型相比,它速度非常快,但即使是Top 1准确性也仅略好于YuNet的整体准确性。我不清楚在什么情况下我会选择OpenCV模型进行面部检测,尤其是因为它很难正常工作。

8e5f6cbe387459cce80b658fac66e0dc.png

c0ea310088cbf91ce206947393817242.png

0b1e09338b5d10a19370d18b23933711.png

Pytorch-MCNN 

MTCNN模型的表现也很差。尽管它的准确性略高于OpenCV模型,但速度要慢得多。由于其准确性低于YuNet,没有 compelling reason to select MTCNN。

38b4058f0fd3c713149d4f9b3ddbd4fe.png

48875fe117f65df68fc92994e33a0781.png

ddc1015bf6e57093b7828368e2c60e3f.png

RetinaFace 

RetinaFace以其作为开源面部检测模型中最准确的声誉而闻名。测试结果支持了这一声誉。

a9aae7ef26d3ba9587cd08d9d308d37d.png

7baafecbf8d4b61f8459fbeae4d6d5ec.png

它不仅是最准确的模型,而且许多“错误”实际上并不是实际错误。RetinaFace真的测试了“假阳性”这个类别,因为它检测到了一些我没有看到的面部,没有标注的因为我认为它们太难了,或者没有考虑是“面部”。

它在这张《Seinfeld》片段中的镜子中检测到了部分面部。

c73f82b25dc68e9284089a2db148a984.png

它在《Modern Family》的背景图像中找到了面部。

620de8cd350f824feb751f035530a7fc.png

它在识别人脸方面如此出色,以至于找到了非人脸。

2db82fdb497f24f61f71743aa6ca4566.png

学习到RetinaFace并不算太慢是一个惊喜。虽然它不如YuNet或OpenCV快,但与MTCNN相当。虽然它在低分辨率下比MTCNN慢,但它扩展得相对较好,可以同样快速地处理更高分辨率。RetinaFace击败了Dlib(至少在需要上采样时)。它比YuNet慢得多,但准确性显著提高。

0a477908d4c83d310871e888c00e891d.png

通过过滤掉较小的面部,可以排除RetinaFace识别的许多“假阳性”。如果我们删除最低四分位的面部,假阳性率会大幅下降。

b1bc62d5816849e93191cf57fea2151d.png

最低四分位的边界是0.0035

d435134beab08e6ef5fab387f1fc5796.png

虽然RetinaFace非常准确,但其错误确实有特定的偏差。虽然RetinaFace容易识别小面部,但它在检测较大、部分遮挡的面部时存在困难,这在查看面部尺寸相对于准确性时尤为明显。

b49c373ae02c99d009590e04db347ebe.png

这对我的用途来说可能是个问题,因为图像中面部的大小与其重要性密切相关。因此,RetinaFace可能会错过最重要的情况,例如以下示例。

df94c5cad753073d09b82a714e875901.png

RetinaFace未能检测到这张图像中的面部,但YuNet做到了。

结论 

根据我的测试(我想强调这些测试并不是世界上最严格的测试;所以要保留一点怀疑态度),我只会考虑使用YuNet或RetinaFace,具体取决于我的主要关注点是速度还是准确性。可能在我绝对想要最小化假阳性数量时会考虑使用Dlib,但对于我的项目来说,只能选择YuNet或RetinaFace。

完整的项目代码在这里:https://github.com/astaileyyoung/CineFace


·  END  ·

🌟 想要变身计算机视觉小能手?快来「小白玩转Python」公众号!

回复Python视觉实战项目,解锁31个超有趣的视觉项目大礼包!🎁

f9f0c02595478f86f5c6411f2e34a44a.png

本文仅供学习交流使用,如有侵权请联系作者删除

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值