3、深度学习人脸检测(一):基于滑动窗口的CNN方法、OverFeat、多尺度检测策略

说实话,在深度学习还没火起来那会儿,做人脸检测基本靠手工特征加分类器。Viola-Jones 框架、HOG + SVM,这些我都调过。但到了 2013 年左右,大家发现卷积神经网络在图像分类上表现太猛了,自然就有人想:能不能把 CNN 也用到检测上?

嗯,这条路最开始走得挺朴素的。说白了就是——把分类器当检测器用。

3.1 从分类到检测:滑动窗口的朴素思想

你想想看,图像分类的任务是判断一张图里有没有人脸。那检测呢?检测不仅要判断有没有,还得告诉我人脸在哪儿。最直接的想法就是:把图像切成很多小窗口,每个窗口送进 CNN 分类器,判断是不是人脸。

这就是基于滑动窗口的 CNN 方法。我在 2014 年刚接触这个思路时,觉得挺笨的,但确实管用。

核心流程:

  1. 定义固定大小的检测窗口(比如 64×64 像素)
  2. 在图像上以固定步长滑动这个窗口
  3. 每个窗口区域送入 CNN 做二分类(人脸 / 非人脸)
  4. 收集所有被判定为人脸的窗口位置
  5. 用非极大值抑制(NMS)合并重叠的检测框

这里有个坑,我踩过。窗口大小和步长怎么选?窗口太小,大脸检测不到;窗口太大,小脸又漏了。步长设小了,计算量爆炸;步长设大了,定位精度下降。我曾经在一个项目里为了调这两个参数,跑了整整两天的实验。

我的经验:步长一般设为窗口尺寸的 10%~20%。比如 64×64 的窗口,步长取 8~12 像素比较合理。这样既不会漏检太多,计算量也能接受。

3.2 多尺度检测策略:解决尺度变化问题

人脸在图像里的尺寸变化太大了。近景人脸可能占几百像素,远景人脸可能只有几十像素。固定窗口肯定不行。

怎么办?两个思路:

  • 图像金字塔:把输入图像缩放到多个尺度,在每个尺度上跑固定窗口
  • 特征金字塔:在 CNN 的不同层上做检测,利用网络自身的多尺度特征

2013 年那会儿,大家主要用图像金字塔。我做过一个实验,把一张 1920×1080 的图像缩放了 8 个尺度,每个尺度跑一遍滑动窗口。结果呢?一张图跑了 40 多秒。嗯,那时候 GPU 也没现在这么强。

尺度策略 优点 缺点 典型应用
图像金字塔 实现简单,检测精度高 计算量大,内存消耗高 OverFeat、早期 CNN 检测
特征金字塔 计算共享,效率高 深层特征分辨率低,小目标差 SSD、FPN
多尺度训练 模型自适应尺度变化 训练复杂度高 MTCNN、RetinaFace

图像金字塔的缩放因子一般取 0.7~0.9。我习惯用 0.8,这样每层尺度变化不大,检测框的连续性比较好。

3.3 OverFeat:滑动窗口 CNN 的集大成者

2013 年,纽约大学的 Sermanet 等人提出了 OverFeat。说实话,这篇我反复读了好几遍。它把滑动窗口、多尺度检测和 CNN 整合到了一个框架里,算是那个时代的标杆。

OverFeat 的核心贡献有三个:

  1. 全卷积化:把 CNN 最后的全连接层改成卷积层,这样网络可以接受任意尺寸的输入
  2. 多尺度推理:对输入图像构建金字塔,每个尺度都过一遍网络
  3. 联合训练:分类、定位、检测三个任务共享特征提取层

注意:OverFeat 的全卷积化思想后来被广泛应用。但它的多尺度推理是在测试时做的,训练时还是用固定尺寸。这意味着训练和测试的分布其实不完全一致。我在复现时发现,如果训练时加入多尺度数据增强,检测效果能再提升 2~3 个点。

OverFeat 的检测流程是这样的:

  • 输入图像经过 5 个卷积层提取特征
  • 在最后一层卷积特征图上,用滑动窗口做分类和回归
  • 每个空间位置预测一个类别分数和边界框偏移
  • 在不同尺度上重复这个过程
  • 最后合并所有尺度的检测结果

我记得当时在 LFW 数据集上跑 OverFeat,检测率能到 90% 以上。虽然现在看这个数字不高,但在 2013 年,这已经是碾压传统方法了。

3.4 知识结构图:滑动窗口 CNN 检测流程

下面这张图展示了基于滑动窗口的 CNN 人脸检测的完整流程。我把它画出来,方便你理解各个模块之间的关系。

滑动窗口 CNN 人脸检测流程 滑动窗口 CNN 人脸检测流程 输入图像 图像金字塔(多尺度缩放) 缩放因子 0.8,共 6~8 层 滑动窗口采样 窗口 64×64,步长 8~12 像素 CNN 特征提取 5 层卷积 + 全卷积化 分类(人脸/非人脸)+ 边界框回归 每个窗口输出置信度 + 偏移量 NMS 合并 → 最终检测结果 关键参数 窗口大小:64×64 步长:8~12 像素 缩放因子:0.8 OverFeat 创新 全卷积化 多尺度推理 联合训练

3.5 滑动窗口 CNN 的局限性

虽然滑动窗口 CNN 在当年取得了不错的效果,但它的缺点也很明显。我总结了几点:

  • 计算冗余:相邻窗口有大量重叠区域,CNN 重复提取特征,效率很低
  • 窗口数量爆炸:一张 1080p 图像,如果步长 8 像素,缩放 6 层,窗口数量轻松超过 10 万
  • 定位精度差:滑动窗口的步长决定了定位的离散程度,步长越大,定位越粗糙
  • 难以处理极端宽高比:固定窗口假设人脸是正方形的,但实际人脸可能有倾斜、遮挡

一个真实案例:我曾经在一个安防项目中用滑动窗口 CNN 检测监控画面中的人脸。1080p 的视频流,每帧要处理 15 万个窗口,在 GTX 1080 上只能跑到 3 FPS。后来我改用全卷积网络,直接回归检测框,速度提升到了 25 FPS。嗯,这就是技术迭代的力量。

3.6 从滑动窗口到全卷积的演进

OverFeat 的一个重要贡献是证明了全卷积化的可行性。为什么全卷积能提速?

你想想看,滑动窗口的本质是在输入图像的不同位置重复计算相同的卷积操作。而全卷积网络一次前向传播就能计算出所有位置的响应。说白了,就是把循环计算变成了矩阵运算,GPU 最喜欢这种模式了。

OverFeat 的做法是:

  • 把最后三个全连接层改成 1×1 和 3×3 的卷积层
  • 这样网络可以接受任意尺寸的输入
  • 输出特征图上的每个空间位置对应一个检测结果

这个思路后来被 YOLO、SSD 等单阶段检测器继承和发展。可以说,OverFeat 是连接传统滑动窗口和现代全卷积检测器的桥梁。

我的建议:如果你想深入理解现代人脸检测算法,一定要把 OverFeat 的吃透。它虽然简单,但包含了检测任务的所有核心要素:多尺度、滑动窗口、回归、NMS。后面的算法再花哨,底层逻辑都没变。

3.7 本章小结

基于滑动窗口的 CNN 方法虽然现在看来有些笨重,但它奠定了深度学习人脸检测的基础。OverFeat 作为这个时期的代表作,提出了全卷积化、多尺度推理等关键思想,影响了后续几乎所有检测算法。

在实际项目中,如果你需要快速验证一个检测思路,滑动窗口 + 轻量 CNN 仍然是一个可行的方案。但如果是生产环境,我建议直接上全卷积网络或者基于锚点的检测器。毕竟,效率就是生命。