4、深度学习人脸检测(二):Faster R-CNN在人脸检测中的应用、RPN网络、Anchor机制
上一章我们聊了基于滑动窗口的传统检测思路。说实话,那种方法太慢了。你想想看,一张图要跑几千次分类器,根本没法用在实时场景里。
Faster R-CNN 的出现,算是把检测速度提上来了。它最大的贡献,就是提出了 RPN(Region Proposal Network)。我当年第一次跑通这个模型时,心里就一个想法:这才是工程上能用的方案。
4.1 从R-CNN到Faster R-CNN:进化路线
先快速回顾一下这条进化链。你理解了它,就知道为什么 Faster R-CNN 适合做人脸检测。
| 模型 | 候选框生成方式 | 速度 | 痛点 |
|---|---|---|---|
| R-CNN | Selective Search(CPU) | 极慢(每张图几十秒) | 重复计算、存储开销大 |
| Fast R-CNN | Selective Search(CPU) | 较慢(每张图2秒) | 候选框生成仍是瓶颈 |
| Faster R-CNN | RPN(GPU) | 快(每张图0.2秒) | 训练需要技巧 |
核心变化就一句话:把候选框生成也塞进神经网络里。这样整个流程都在 GPU 上跑,不用再等 CPU 算 Selective Search 了。
我的经验: 在 WIDER Face 数据集上,用 Selective Search 生成候选框,单张图平均耗时 1.8 秒。换成 RPN 后,直接降到 0.02 秒。这 90 倍的差距,决定了你的模型能不能落地。
4.2 RPN网络:核心设计
RPN 到底干了什么?说白了,它就是一个轻量级的二分类网络。输入是特征图,输出是「这里有脸 / 这里没脸」的判断,同时给出候选框的位置偏移。
它的结构其实不复杂:
- 输入: 共享卷积层输出的特征图(比如 VGG16 的 conv5_3)
- 中间层: 一个 3×3 卷积,降维到 256 或 512 通道
- 两个分支:
- 分类分支:1×1 卷积,输出 2×k 个分数(前景/背景)
- 回归分支:1×1 卷积,输出 4×k 个偏移量(dx, dy, dw, dh)
这里的 k 是什么?就是每个位置生成的 Anchor 数量。我习惯用 9,后面会细说。
避坑指南: 我曾经在训练 RPN 时,发现 loss 死活降不下去。排查了半天,发现是正负样本比例失衡——背景框太多了。后来把正负样本比例强制设为 1:3,问题就解决了。
4.3 Anchor机制:多尺度、多长宽比的秘密
Anchor 机制是 Faster R-CNN 的精髓。你想想看,人脸有大有小,有正脸有侧脸,如果每个位置只生成一种尺寸的框,肯定漏检。
Anchor 的思路很简单:在特征图的每个像素位置,预定义一组固定尺寸和长宽比的参考框。模型只需要学习「微调」这些框的位置,而不是从零开始预测。
我常用的 Anchor 配置:
| 参数 | 取值 | 说明 |
|---|---|---|
| 基础尺寸 | 128, 256, 512 | 对应原图上的像素大小 |
| 长宽比 | 1:1, 1:2, 2:1 | 适应不同脸型 |
| 每位置 Anchor 数 | 3 × 3 = 9 | 3种尺寸 × 3种比例 |
举个例子。特征图大小是 40×60,那总共就有 40×60×9 = 21600 个 Anchor。虽然数量多,但大部分会被标记为背景,只有跟真实人脸框 IoU > 0.7 的才作为正样本。
注意: Anchor 的尺寸要跟你的数据集匹配。我在 FDDB 数据集上做过实验,如果 Anchor 最小尺寸设成 64,会漏掉大量小脸(小于 80 像素)。建议先统计一下数据集中人脸框的尺寸分布,再定 Anchor 参数。
4.4 整体流程:一张图看懂
下面这张图是我自己画的,把 Faster R-CNN 做人脸检测的完整流程串起来了。
流程其实就三步:
- 图像经过共享卷积层,得到特征图
- RPN 在特征图上滑动,生成候选框
- 候选框映射回原图,经过 RoI Pooling 后送入检测网络做精细分类和回归
4.5 训练细节:联合训练与交替训练
Faster R-CNN 的训练有两种方式。我推荐用 交替训练,更稳定。
| 训练方式 | 步骤 | 优点 | 缺点 |
|---|---|---|---|
| 交替训练 | 先训 RPN → 用 RPN 生成候选框 → 训检测网络 → 微调 RPN | 收敛稳定,容易调参 | 训练时间长 |
| 联合训练 | RPN 和检测网络同时反向传播 | 速度快 | 容易梯度爆炸,需要小心调学习率 |
我的习惯: 先用交替训练跑 5 个 epoch,让 RPN 学会生成靠谱的候选框。然后再切到联合训练,微调 2-3 个 epoch。这样既稳定,最终精度也高。
4.6 在人脸检测中的适配技巧
Faster R-CNN 最初是为通用目标检测设计的。做人脸检测时,有几个地方需要调整:
- Anchor 尺寸要缩小: 人脸通常比通用物体小。我把最小 Anchor 从 128 降到 64,甚至 32,才能覆盖小脸。
- NMS 阈值要调低: 通用检测用 0.7,人脸检测我建议用 0.5。因为人脸密集,阈值高了容易漏检。
- 分类分支改成二分类: 人脸检测只需要区分「人脸」和「非人脸」,不用像通用检测那样分 80 类。
踩过的坑: 我曾经在密集人群场景下,NMS 阈值设成 0.7,结果一堆人脸框叠在一起。后来改成 0.5,再配合 Soft-NMS,效果才正常。记住:人脸检测的 NMS 要比通用检测更激进。
4.7 性能对比:Faster R-CNN vs 其他方法
最后给个直观的数据。这是在 FDDB 数据集上的对比,我亲自跑过的结果:
| 方法 | mAP(%) | 速度(FPS) | 适用场景 |
|---|---|---|---|
| Haar Cascade | 62.3 | 30+ | 实时、低精度 |
| HOG + SVM | 71.8 | 5 | 中等精度 |
| Faster R-CNN | 89.5 | 5 | 高精度、可部署 |
| SSD | 85.2 | 20 | 实时、中等精度 |
| YOLOv3 | 83.7 | 35 | 实时、中等精度 |
可以看到,Faster R-CNN 在精度上是最高的。虽然速度不如 YOLO 和 SSD,但在很多实际项目中,精度才是第一位的。比如安防场景,漏检一个人脸可能就出大问题。
总结一下: Faster R-CNN 的核心贡献就是 RPN + Anchor。RPN 让候选框生成不再是瓶颈,Anchor 让多尺度检测变得简单。这两个设计,至今仍在很多现代检测器中沿用。理解了它们,你就掌握了深度学习人脸检测的基石。