3、人脸检测基础(下):基于深度学习的人脸检测方法

上一章我们聊了传统方法,说白了就是靠手工特征去猜人脸在哪。这一章咱们进入正题——深度学习时代的人脸检测。我个人习惯把这一章看作是「从规则驱动到数据驱动」的分水岭。你想想看,传统方法遇到大角度、强遮挡、暗光环境基本就歇菜了,但深度学习模型却能扛住大部分极端场景。

3.1 MTCNN:多任务级联卷积网络

MTCNN 是我最早在生产环境中大规模使用的深度学习人脸检测器。2016 年提出,到现在依然有大量嵌入式项目在用。为什么?因为它轻量、快速、且检测+对齐一步到位。

3.1.1 网络结构:三段式级联

MTCNN 的核心思路是「由粗到精」。它把检测拆成三个网络,串行执行:

  1. P-Net(Proposal Network):快速生成候选框。输入 12×12 的图像块,输出人脸置信度和边界框回归值。这一步会扫一遍图像金字塔,产生大量候选框。
  2. R-Net(Refine Network):精筛候选框。输入 24×24,比 P-Net 多了一层全连接,能更准确地区分人脸和非人脸。
  3. O-Net(Output Network):输出最终结果。输入 48×48,除了边界框回归,还会输出 5 个关键点坐标(左眼、右眼、鼻子、左嘴角、右嘴角)。

我在项目中遇到过一个问题:P-Net 的阈值设得太低,候选框数量爆炸,导致 R-Net 和 O-Net 处理不过来。后来我把 P-Net 的阈值从 0.6 提到 0.7,候选框数量直接砍掉一半,速度提升明显,召回率只掉了不到 1%。

关键参数速查表

网络层输入尺寸主要作用输出
P-Net12×12快速生成候选框置信度 + 4 个边界框偏移
R-Net24×24精筛候选框置信度 + 4 个边界框偏移
O-Net48×48输出最终结果 + 关键点置信度 + 4 个边界框偏移 + 10 个关键点坐标

3.1.2 损失函数与训练策略

MTCNN 的损失函数由三部分组成:

  • 人脸分类损失:交叉熵损失,判断是不是人脸。
  • 边界框回归损失:欧氏距离损失,修正候选框位置。
  • 关键点定位损失:欧氏距离损失,只对包含关键点标注的样本计算。

训练时有个小技巧:不同任务使用不同权重的样本。比如 O-Net 训练时,关键点定位的样本只占一小部分,但损失权重可以设高一些,不然关键点学不好。

避坑指南

我曾经在训练 MTCNN 时发现关键点定位一直不准,后来排查发现是数据增强做得不够。人脸检测的数据增强不能只做随机裁剪和翻转,还要加入光照变化和模糊模拟。尤其是跨摄像头场景,不同摄像头的曝光和焦距差异很大,不做增强的话模型泛化能力会很差。

3.2 RetinaFace:单阶段高精度检测器

如果说 MTCNN 是「轻量级选手」,那 RetinaFace 就是「精度怪兽」。它基于特征金字塔和单阶段检测框架,在 WIDER Face 数据集上长期霸榜。我个人在安防项目中用过 RetinaFace,效果确实比 MTCNN 好一截,但代价是计算量翻了好几倍。

3.2.1 核心设计思路

RetinaFace 有几个关键创新点:

  • 特征金字塔(FPN):从不同尺度的特征图上检测人脸,解决多尺度问题。小脸用浅层特征,大脸用深层特征。
  • 上下文模块(SSH):在特征图上增加感受野,让模型能利用人脸周围的上下文信息。比如肩膀、头发这些区域,对人脸检测有辅助作用。
  • 密集回归分支:除了边界框和关键点,还额外回归了 3D 人脸参数(姿态角、形状等)。不过这个分支在工程中我一般会关掉,因为计算量太大,收益有限。

3.2.2 与 MTCNN 的对比

我整理了一张对比表,方便你快速决策:

对比维度MTCNNRetinaFace
网络结构三段级联,串行处理单阶段,端到端
输入尺寸图像金字塔 + 12/24/48固定输入(如 640×640)
关键点输出5 个关键点5 个关键点 + 可选 3D 参数
小脸检测一般,依赖图像金字塔优秀,依赖 FPN
推理速度(GPU)快(~10ms/帧)中等(~30ms/帧)
推理速度(CPU)较快(~50ms/帧)慢(~200ms/帧)
模型大小~2MB~50MB
适用场景嵌入式、移动端、实时服务器端、高精度要求

注意

RetinaFace 的官方实现默认使用 ResNet-50 作为 backbone,显存占用较高。如果你在边缘设备上部署,可以考虑使用 MobileNet 版本的 RetinaFace,精度会下降一些,但速度能提升 3-5 倍。

3.3 工程选型建议

选型这件事,没有银弹。我根据实际项目经验,给出几条建议:

3.3.1 场景一:嵌入式/移动端实时检测

  • 推荐方案:MTCNN(轻量版)或 MobileNet-SSD
  • 理由:模型小、推理快、不需要 GPU。我在树莓派 4B 上跑过 MTCNN,720P 视频能到 15fps,基本够用。
  • 注意:小脸检测能力弱,摄像头安装距离不宜过远。

3.3.2 场景二:服务器端高精度检测

  • 推荐方案:RetinaFace(ResNet-50)或 DSFD
  • 理由:精度高,能处理大角度、遮挡、暗光等复杂场景。我在安防项目中用 RetinaFace 做离线批量检测,召回率能到 98% 以上。
  • 注意:需要 GPU 加速,显存建议 8GB 以上。

3.3.3 场景三:跨摄像头追踪中的检测

  • 推荐方案:RetinaFace + 轻量级跟踪器(如 SORT)
  • 理由:跨摄像头场景下,人脸尺度变化大、光照不一致。RetinaFace 的 FPN 结构能更好地处理多尺度问题。检测 + 跟踪的组合可以降低检测频率,提升整体效率。
  • 注意:不同摄像头的白平衡和曝光参数不同,建议在检测前做简单的图像预处理(直方图均衡化或自适应亮度调整)。

我的个人经验

如果你刚开始做人脸检测项目,我建议先从 MTCNN 入手。它简单、稳定、文档多,踩坑成本低。等你对检测流程熟悉了,再切换到 RetinaFace 追求更高精度。别一上来就上最复杂的模型,否则调试起来会很痛苦。

3.4 本章知识结构图

下面这张图梳理了 MTCNN 和 RetinaFace 的核心流程与选型逻辑:

深度学习人脸检测方法对比 MTCNN:三段级联 P-Net:生成候选框 R-Net:精筛候选框 O-Net:输出+关键点 RetinaFace:单阶段 特征金字塔(FPN) 上下文模块(SSH) 密集回归(框+点+3D) 工程选型建议 嵌入式/移动端 → MTCNN 轻量、快速、低功耗 服务器/高精度 → RetinaFace 高召回、抗遮挡、多尺度 说明:MTCNN 适合资源受限场景,RetinaFace 适合精度优先场景。 跨摄像头追踪建议以 RetinaFace 为主检测器,配合轻量跟踪器使用。

3.5 代码示例:MTCNN 快速上手

这里给一个 MTCNN 的推理代码示例,用的是我常用的 mtcnn 库(基于 TensorFlow 后端):

from mtcnn import MTCNN
import cv2

# 初始化检测器
detector = MTCNN()

# 读取图像
img = cv2.imread('group_photo.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 执行检测
results = detector.detect_faces(img_rgb)

# 遍历结果
for result in results:
    # 边界框
    x, y, w, h = result['box']
    confidence = result['confidence']
    
    # 关键点
    keypoints = result['keypoints']
    left_eye = keypoints['left_eye']
    right_eye = keypoints['right_eye']
    nose = keypoints['nose']
    mouth_left = keypoints['mouth_left']
    mouth_right = keypoints['mouth_right']
    
    # 绘制
    cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
    cv2.circle(img, left_eye, 2, (0, 0, 255), -1)
    cv2.circle(img, right_eye, 2, (0, 0, 255), -1)
    cv2.circle(img, nose, 2, (0, 0, 255), -1)
    cv2.circle(img, mouth_left, 2, (0, 0, 255), -1)
    cv2.circle(img, mouth_right, 2, (0, 0, 255), -1)

cv2.imshow('Detection', img)
cv2.waitKey(0)

小提示

如果你用的是 PyTorch,推荐 facenet-pytorch 库,它包含了 MTCNN 的实现,而且支持 GPU 加速。安装命令:pip install facenet-pytorch。用法和上面类似,但返回的是张量,方便后续接入人脸识别流程。

3.6 本章小结

MTCNN 和 RetinaFace 代表了两种不同的设计哲学:一个追求轻量和实时,一个追求精度和鲁棒性。选哪个,取决于你的硬件条件、场景要求和性能指标。我个人建议:先跑通 MTCNN 做 baseline,再根据实际效果决定是否升级到 RetinaFace。别一上来就追求最先进的模型,工程落地讲究的是「够用就好」。