SCRFD 人脸检测:0.67M 参数、4.2ms,InsightFace 里这个轻量检测器怎么做到的
2026/9/11 3:25:25 网站建设 项目流程

SCRFD 人脸检测:0.67M 参数、4.2ms,InsightFace 里这个轻量检测器怎么做到的

【免费下载链接】insightfaceState-of-the-art 2D and 3D Face Analysis Project项目地址: https://gitcode.com/GitHub_Trending/in/insightface

SCRFD 是 InsightFace 仓库中最实用的轻量级人脸检测模块,基于 ONNX 推理单张 VGA 图像只要 4.2ms,0.67M 参数的 2.5GF 版本在 WIDER Face 三个子集上全面超过 RetinaFace。如果你要落地实时人脸检测,这篇文章讲清楚它凭什么快、最小推理流程怎么写、哪个规格适合你,以及生产环境里几个真实的坑。

先回答"够不够用":WIDER Face 上的精度-速度权衡

SCRFD 的评测数据都写在 detection/scrfd/README.md 里,精度、FLOPs、推理耗时统一在 VGA 分辨率下测得,这是对比各检测器时最可信的口径。预训练模型部分给出的规格如下:

规格Params(M)FLOPsWIDER EasyMediumHardInfer(ms)
SCRFD_500M0.570.5G90.5788.1268.513.6
SCRFD_2.5G0.672.5G93.7892.1677.874.2
SCRFD_10G3.8610G95.1693.8783.054.9

两个值得注意的信号:

  • Hard 子集才是分水岭。RetinaFace(MobileNet 0.25)在 Hard 上只有 47.32,SCRFD_500M 拉到 68.51,小脸和遮挡场景的提升全部体现在这里。所以如果你的业务涉及多人合影、远距离监控,至少用 2.5G 版本。
  • 速度差异主要看 FLOPs 而不是参数量。500M 到 10G 参数量涨了 6 倍多,耗时只从 3.6ms 到 4.9ms,说明计算量被压得很低,瓶颈在 CPU 访存而非模型容量。README 还给了 0.5G 版在 Ryzen 9 3950X 上单线程(OMP_NUM_THREADS=1、无 mkldnn)的实测:640x480 输入 28.3ms,Original-Size 输入时 Hard 能到 82.03——原始分辨率输入对小脸更友好,代价是耗时,这个取舍后面会再提。

多人室内合影正是 Hard 子集那类场景:人脸尺度差异大、有低头侧脸。这类图片是检验一个检测器小脸召回率最直接的素材。

最小可运行推理流程

推理参考实现在 detection/scrfd/tools/scrfd.py,它用 onnxruntime 加载 ONNX 模型,自己实现了 blob 归一化、距离解码(distance2bbox)和 NMS。跑通的最短路径如下,模型从 README 的 Pretrained-Models 表下载(2.5G 带关键点版 SCRFD_2.5G_KPS):

# 来源: detection/scrfd/tools/scrfd.py import cv2, onnxruntime from detection.scrfd.tools.scrfd import SCRFD det = SCRFD(model_file='scrfd_2.5gkps.onnx') det.prepare(-1) # ctx_id<0 表示 CPUExecutionProvider img = cv2.imread('group.jpg') bboxes, kpss = det.detect(img, 0.5, input_size=(640, 640)) # bboxes: [x1,y1,x2,y2,score]; kpss: 5 个关键点(眼睛/鼻尖/嘴角), 无 KPS 版为 None

调用链只有四步:构造 session、选 provider、读图、detect。输入图像内部会自动做 keep-ratio 缩放并 pad 到input_size,输出的框已经映射回原图坐标,不需要自己算逆变换。

几个容易踩的坑,都是从这个脚本的实现细节里看出来的:

  1. 动态输入要显式给input_sizetools/scrfd2onnx.py导出的 ONNX 默认是动态输入,此时必须传input_size,否则detect里的断言直接失败。想省一次网络往返,可以用--shape 640 640导出固定尺寸模型再交给 onnx-simplifier 优化。
  2. pad 区域会引入边界假框detect把缩放后的图放进左上角、右下角留黑边,黑边区域偶尔会出低分框。thresh传 0.5 基本可以滤掉;如果追求高召回把阈值压到 0.2 以下,记得把边界框丢弃或收紧nms_thresh
  3. 选对 KPS 版本。输出张量个数(6/9/10/15)决定模型是否带关键点、走 3 层还是 5 层 FPN。后续要做人脸对齐、注册识别,直接选_KPS版,2.5G_KPS 比 2.5G 多 0.15M 参数,Hard 精度 77.13 vs 77.87,几乎无损。
  4. 阈值口径别混test_widerface.py评测用score_thr=0.02,demo 用 0.5,nms的 IoU 阈值默认 0.45。同一张图两种阈值结果差异很大,对账时先确认口径。

0.67MB 模型怎么塞进端侧

先澄清一个常见的单位混淆:README 里 0.67 是参数量(M),不是文件大小。2.5G 版 ONNX(fp32)实际下载下来约 2.7MB,量化后更小。这个量级意味着它可以直接打进手机 APP 的安装包,也可以放进 Web 端 WASM 推理——仓库 README 的 Demo 一节列了 ncnn、MNN、TNN、ONNXRuntime 的 C++ 移植,端侧部署基本不用自己写前处理。

端侧的两个实操建议:

  • 输入尺寸按业务选prepare之后的detect接受任意input_size。小脸密集场景(监控、街景)用 640x640 甚至更高;单人脸刷脸场景 320x320 足够,耗时近似按面积缩放,0.5G 版在 320x240 下单线程 11.4ms(README 实测)。
  • GPU 服务侧直接转 TensorRTtrtexec --onnx=scrfd_2.5g.onnx --saveEngine=scrfd_2.5g.trt --fp16一条命令,fp16 对精度影响很小,延迟还能再压一截。多实例并发时建议每线程一个InferenceSession,onnxruntime 的 session 本身不是为高频多线程共享设计的。

为什么它能"又快又准":三个设计点

这部分点到为止,细节看 configs/scrfd/scrfd_2.5g.py:

  • 多尺度锚点AnchorGeneratorbase_sizes=[16,64,256]strides=[8,16,32]、每层 2 个 scale,相当于给不同焦段各配一台镜头——stride 8 那层负责几十像素的小脸,stride 32 那层负责大脸,不用一套锚框硬扛全尺度。
  • PAFPN 颈部in_channels=[24,48,48,80]压到out_channels=24,通道数小,特征融合开销低,这也是 FLOPs 能压到 2.5G 的关键。
  • ATSS 样本分配assigner=dict(type='ATSSAssigner', topk=9),按局部统计量动态挑正样本,替代固定 IoU 阈值,训练配置里allowed_border=-1pos_weight=-1就是配套写法。

值得一提的是这些规格不是调出来的,是搜出来的:仓库search_tools/里保留了两阶段网络搜索的完整流程(先生成 64 个候选 backbone 配置训练 80 轮,按 WIDER Hard mAP 选优,再以最优者为模板做整体搜索),detection/scrfd/search_tools/ 可以直接照着复现。这解释了为什么参数量和 FLOPs 能卡得这么"整"。

上图展示了检测框之上的完整分析链路:关键点、眼开合、活体、口罩、年龄性别。SCRFD 输出的 bbox 加 KPS 就是这一整条链路的入口——python-package/insightface/ 里的app/face_analysis.py把检测、对齐、识别、属性串在一起,做完检测之后的事不用自己接。

最后收一个判断:单人实时场景选 0.5G(3.6ms),多人/小脸密集选 2.5G,离线高精度再上 10G;对 Hard 子集精度有硬指标的话,记得优先验证原始分辨率输入的效果,README 里 82.03 vs 68.51 的差距说明输入尺寸本身就是你手里最大的调优旋钮。

【免费下载链接】insightfaceState-of-the-art 2D and 3D Face Analysis Project项目地址: https://gitcode.com/GitHub_Trending/in/insightface

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询