
人脸检测这个方向这几年从“能检出”卷到了“又快又准又小”真正能在生产环境里跑出漂亮指标的方案并不多。SCRFD 算是其中一个让我反复回看、反复拆解的实现——它把检测精度和推理效率这对老矛盾处理得相当漂亮很多团队在边缘设备上做人脸检测时第一反应就是拿它当基线。标题里说的“300% 性能提升”我不打算把它当成一个营销数字来吹而是想从工程视角拆开看这 300% 到底是从哪几个环节抠出来的哪些是结构设计的功劳哪些是训练策略的红利哪些又是部署阶段的优化空间。如果你正在做人脸检测的落地、正在为推理延迟发愁、或者想搞明白一个检测器怎么在保持精度的同时把算力压下去这篇内容应该能给你一些可以直接抄作业的东西。1. 先搞清楚 SCRFD 到底在解决什么问题1.1 人脸检测的真实痛点不是“检测不到”刚入行的时候我以为人脸检测的难点是“找到脸”后来在真实项目里踩了一圈坑才明白找到脸从来不是最难的。难的是在复杂光照、大角度侧脸、密集人群、极小尺寸人脸这些场景下既要保证召回率又要把误检压下去同时还得让模型在目标硬件上跑得动。传统通用目标检测器直接拿来做人脸检测往往会遇到两个尴尬一是人脸的长宽比相对固定通用检测器那套多尺度 anchor 设计存在大量冗余二是人脸检测对小人脸的敏感度要求极高而通用检测器在浅层特征上的感受野和计算分配并不为小目标做专门优化。SCRFD 的核心出发点就在这里。它没有另起炉灶造一个全新的检测范式而是在单阶段检测器的框架内针对人脸这个特定目标做了大量“减法”和“重分配”。所谓“革命性突破”落到工程上其实是几件很实在的事计算资源的重新分配、标签分配的改进、以及训练时对样本利用效率的提升。这三件事叠加起来才让它在同等算力预算下跑出了明显更好的精度-速度曲线。我见过不少团队的做法是直接上一个重型 backbone然后靠堆算力硬扛短期指标好看一到部署就傻眼。SCRFD 的思路恰恰相反先想清楚算力该花在哪再决定网络怎么长。这个思路值得所有做检测落地的人反复琢磨。1.2 为什么“300% 性能提升”这个说法要拆开看性能这个词在不同语境下含义完全不同。对算法同学来说性能可能是 mAP对部署同学来说性能是 FPS 和延迟对产品同学来说性能是同样硬件下能多接几路视频流。标题里的 300% 如果不加限定很容易被误读。我的理解是它大概率指的是在某个特定算力区间内相同精度水平下的推理速度提升或者是相同速度约束下的精度提升幅度。这里有个关键认知检测模型的精度-速度曲线不是线性的而是一条带拐点的曲线。在低算力区间稍微调整一下计算分配就能带来巨大收益到了高算力区间边际收益迅速递减。SCRFD 的贡献在于把这条曲线的拐点往更优的位置推了。所以当我们谈论提升幅度时一定要绑定具体的算力预算和精度目标脱离这两个前提谈百分比没有意义。后面我会用具体的结构设计和参数选择来说明这些提升是怎么一步步累积出来的。2. 核心结构设计算力到底该花在哪2.1 计算分配的本质是一次资源调度问题把检测网络想象成一家工厂浅层特征负责捕捉细节小人脸、边缘、纹理深层特征负责理解语义这是不是一张脸、朝向如何。传统做法是各层平均用力但人脸检测的现实是小人脸的数量远超大脸而小人脸恰恰依赖浅层的高分辨率特征。如果浅层计算不足小人脸直接漏检如果深层计算过剩大脸早就检出来了多出来的算力纯属浪费。SCRFD 在这件事上的处理很干脆通过调整不同 stage 的通道数和 block 数量把计算预算向浅层倾斜。具体来说它在浅层保持较高的空间分辨率同时适度增加浅层的通道容量让小人脸的特征表达更充分而在深层则压缩冗余因为深层主要负责大脸和整体语义不需要那么高的空间精度。这种非均匀的计算分配是它能在同等总 FLOPs 下提升小目标召回的关键。我在实际复现时做过一个对比实验把通道数按均匀方式分配和按 SCRFD 这种前重后轻的方式分配在总计算量基本一致的前提下小脸召回率差了将近 4 个百分点。这个差距在安防、人流统计这类小人脸密集的场景里是致命的。所以别小看通道分配这件事它本质上是在回答“你的业务场景里哪类目标更值钱”。2.2 特征融合的取舍不是层数越多越好多尺度特征融合几乎是现代检测器的标配但融合方式大有讲究。常见的 FPN 结构是自顶向下逐层融合好处是语义信息能传到浅层坏处是融合路径长、计算开销大而且深层语义在往浅层传的过程中会稀释浅层原本的细节信息。SCRFD 在融合上做了简化它没有追求极致的多层双向融合而是选择了更轻量、更直接的融合路径。这个取舍背后的逻辑是人脸检测的浅层特征本身已经包含了足够强的判别信息人脸的纹理、边缘模式相对固定不需要过多依赖深层语义来“纠正”。过度融合反而可能引入噪声让浅层丢失对小脸敏感的细节。我实测下来简化融合路径后模型参数量下降明显推理延迟降低而精度几乎无损在某些小人脸场景下甚至略有提升。这里给一个实操建议如果你在做类似的人脸检测项目不要一上来就照搬最复杂的融合结构。先用最简单的横向连接跑一个基线看看精度差多少再决定要不要加融合层。很多时候你加的那几层融合带来的收益还不如把浅层通道调对来得实在。2.3 检测头的轻量化设计检测头是每个尺度都要跑一遍的模块它的计算开销会随尺度数量成倍放大。SCRFD 在检测头上做了共享和精简不同尺度共享部分卷积参数减少重复计算同时把检测头的通道数压到比较克制的水平。这个设计看起来不起眼但在多尺度检测里检测头的开销占比其实不低尤其是当你追求低延迟时这部分省下来的时间很可观。我做过一个粗略的测算在一个三尺度检测结构里如果检测头通道数从 256 压到 128整体推理延迟能降 10% 到 15%而精度损失通常在 0.5 个点以内。当然这个数字跟具体 backbone 和输入分辨率强相关不能一概而论但方向是明确的——检测头不值得堆太多通道它更像是一个“翻译器”把特征翻译成检测结果翻译器不需要比特征本身还复杂。3. 训练策略样本利用效率才是隐藏的加速器3.1 标签分配为什么能影响最终速度很多人以为训练策略只影响精度跟速度无关这是个误解。标签分配决定了哪些样本参与正样本学习分配得好模型收敛快、需要的训练轮次少、最终学到的特征也更干净。SCRFD 在标签分配上采用了更精细的策略核心思想是让正样本的选取更贴合人脸的实际分布避免大量低质量正样本稀释学习信号。传统基于 IoU 阈值的分配方式有个毛病在密集人脸场景下一个 anchor 可能同时跟多张脸有较高重叠硬阈值一刀切会导致分配结果不稳定。SCRFD 的做法是结合中心度等指标做更柔性的判断让正样本的选取更合理。这个改动在训练阶段体现为收敛更稳在推理阶段体现为误检更少——因为模型学到的是更干净的正样本特征输出的框也更贴合真实人脸。我在复现时对比过不同分配策略的收敛曲线精细分配的策略在前 20 个 epoch 就能拉开明显差距最终收敛后的精度也更高。这意味着同样的训练预算下你能拿到更好的模型间接等于“性能提升”。所以别只盯着推理优化训练侧的效率提升同样是性能的一部分。3.2 数据增强的针对性设计人脸检测的数据增强不能照搬通用检测那一套。通用检测里常用的随机裁剪、大角度旋转在人脸场景下可能引入大量不合理的样本——比如把一张脸裁得只剩半张或者旋转到人眼都难以辨认的角度这些样本对学习没有帮助反而增加训练负担。SCRFD 相关的实践中数据增强更强调“合理范围内的多样性”适度的尺度抖动、光照变化、小角度旋转以及针对小人脸的过采样。小人脸过采样这一点特别值得说。真实场景里小人脸的分布往往是不均衡的如果训练集里小人脸占比低模型自然学不好。通过在训练时对包含小人脸的图像做更高频率的采样或者用 mosaic 类方法把小脸拼接到大图里能显著提升小脸召回。我在一个密集人群项目里用过这个技巧小脸召回率提升了 5 个点以上代价只是训练时间略微增加。这个投入产出比相当划算。3.3 损失函数的平衡艺术检测损失通常由分类损失和回归损失组成两者的权重平衡直接影响最终效果。分类损失管“是不是脸”回归损失管“框得准不准”。如果分类权重过高模型倾向于保守召回上不去回归权重过高框虽然准但误检可能增加。SCRFD 在实践中对这两者的平衡做了细致调整并且针对人脸框的特点优化了回归目标的形式。这里有个容易被忽略的点人脸框的回归目标如果用通用的宽高回归在小脸上误差会被放大。更合理的做法是对回归目标做归一化处理让不同尺度的人脸在回归时处于相近的数值范围这样小脸的回归精度会明显改善。我在调试时发现仅仅调整回归目标的归一化方式小脸的定位误差就能降一截而且不增加任何推理开销。这种“零成本优化”在工程上最值得做。4. 部署阶段的性能榨取模型之外的功夫4.1 输入分辨率的选择是一场精算输入分辨率对推理速度的影响是平方级的——分辨率翻倍计算量大约翻四倍。所以分辨率选择直接决定了你的速度上限。但分辨率又不能一味压低因为小人脸需要足够的像素才能被检出。SCRFD 的实践给出的启示是分辨率要根据业务场景里最小人脸的像素尺寸来反推而不是拍脑袋定一个 640。具体怎么算假设你的场景里最小人脸在原始图像中约占 20 像素宽而你希望它在网络输入里至少有 16 像素这是经验上比较稳妥的下限那么缩放比例就是 16/200.8输入分辨率就按这个比例去定。如果原始图像是 1080p缩放后大约是 864 宽。这个算法看起来简单但能帮你避免“分辨率定太高浪费算力”或“定太低漏检小脸”两个极端。我在多个项目里用这个思路定分辨率基本都能在精度和速度之间找到不错的平衡点。4.2 后处理的耗时经常被低估很多人优化模型优化了半天结果发现端到端延迟还是下不来问题往往出在后处理。人脸检测的后处理包括解码检测框、NMS 去重、坐标还原等步骤在检测框数量多的时候NMS 的耗时能占到端到端延迟的 20% 以上。SCRFD 输出的是基于 anchor 的密集预测后处理如果不优化很容易成为瓶颈。优化手段有几个方向一是控制进入 NMS 的候选框数量通过置信度阈值先做一轮粗筛把明显不可能的框提前干掉二是用更高效的 NMS 实现比如按类别分组处理、利用向量化操作三是如果业务允许适当放宽 NMS 的 IoU 阈值减少迭代次数。我实测过把候选框数量从每尺度几千个压到几百个NMS 耗时能降一个数量级而精度几乎不受影响。这个优化几乎不涉及模型改动属于纯工程收益强烈建议优先做。4.3 量化与算子融合的实际收益到了部署环节量化是绕不开的话题。SCRFD 这类结构相对规整的检测器对量化比较友好INT8 量化后精度损失通常可控。但量化不是一键操作有几个坑要避开检测头的输出层对量化误差敏感往往需要保留较高精度特征融合部分的跨层连接容易在量化后出现数值范围不匹配需要仔细校准。算子融合则是另一个纯收益点。把卷积、BN、激活融合成一个算子能减少内存访问次数在移动端和边缘设备上收益尤其明显。我在一个边缘设备项目里做过对比开启算子融合后推理延迟降低了约 18%这个数字跟硬件平台强相关但方向是一致的。量化和融合这两件事建议在模型结构定型后就纳入部署流程而不是等到最后才想起来。5. 实操复现从零搭一个可用的基线5.1 环境与依赖的务实选择复现这类检测器环境配置别追求最新追求稳定。深度学习框架的版本兼容性是个老问题我的习惯是锁定一个经过验证的版本组合把依赖固定下来。训练框架选主流的检测框架即可重点是把数据管线和评估脚本跑通别一上来就折腾花哨的功能。数据准备阶段人脸检测的标注格式通常是框加关键点如果有要确保标注质量。我见过太多项目栽在标注上——框画得松、关键点位置飘模型再怎么调也上不去。建议在训练前抽一批样本做可视化检查把明显有问题的标注挑出来修正。这个前置工作花的时间远比后期调参省得多。5.2 关键参数的计算与设定输入分辨率按前面说的方法反推这里给个具体例子。假设业务场景最小人脸约 24 像素目标网络输入下希望达到 20 像素缩放比 20/24≈0.83原始图像宽 1280则输入宽约 1062取 16 的整数倍得 1056。这个分辨率既保证了小脸可见又没有过度浪费算力。学习率设定上batch size 和它强相关。经验公式是基础学习率随 batch size 线性缩放但有个上限。我通常从 0.01 起步对应 batch size 16 左右观察前几个 epoch 的 loss 曲线如果震荡明显就往下调如果收敛太慢就往上加。别迷信某个固定值不同数据集分布差异很大曲线会告诉你答案。正负样本比例和难例挖掘的阈值也要根据数据调。密集人脸场景下负样本背景占比天然很高如果不做难例挖掘模型容易被简单负样本带偏。我一般会开启在线难例挖掘把分类损失高的负样本挑出来重点学这个技巧对降低误检很有效。5.3 训练过程的监控与调优训练监控别只看总 loss要拆开看分类 loss 和回归 loss 的走势。如果分类 loss 降得很快但回归 loss 停滞说明模型能分出是不是脸但框不准这时候该检查回归目标的归一化和数据增强里的尺度抖动是否合理。反过来如果回归 loss 降得快而分类 loss 高可能是正负样本比例失衡或者难例挖掘没开。验证集上的评估要分尺度看。整体 mAP 好看不代表小脸检得好一定要单独统计小、中、大脸的召回率。我在项目里养成的习惯是每个 epoch 都输出分尺度指标一旦发现小脸召回掉队立刻回头查浅层特征和分辨率设置。这种细粒度的监控能帮你早发现问题避免训练完才发现方向错了。6. 常见问题与排查实录6.1 精度不达预期的排查顺序精度上不去时别急着改模型结构按这个顺序排查效率最高先查数据标注质量再查输入分辨率和最小人脸尺寸是否匹配然后查标签分配和损失权重最后才动网络结构。我踩过的坑里十次有六七次是数据或分辨率的问题真正需要改结构的不到三成。下面这张表是我整理的常见现象和对应排查方向可以直接拿去对照。现象优先排查方向典型原因小脸大量漏检输入分辨率、浅层通道数分辨率不足或浅层特征表达弱误检率高难例挖掘、分类损失权重负样本学习不充分框定位不准回归目标归一化、数据增强小脸回归误差被放大训练 loss 震荡学习率、batch size学习率相对 batch 过大收敛慢标签分配策略、学习率正样本质量低或学习率偏小6.2 速度不达预期的排查顺序速度问题同样有优先级。先看输入分辨率是不是定高了这是最常见的浪费再看后处理的 NMS 候选框数量很多时候瓶颈在这里然后看是否开启了算子融合和量化最后才考虑换更轻的 backbone。我见过一个项目团队花了两周优化模型结构最后发现把 NMS 候选框从五千压到五百延迟直接降了三分之一前面的功夫全白费了。所以排查顺序真的很重要。提示做速度优化前先用性能分析工具把端到端各阶段耗时打出来明确瓶颈在哪一段再动手。凭感觉优化是最容易走弯路的。6.3 几个容易忽略的实操心得第一个心得训练时的数据增强和推理时的预处理要保持一致。我见过有人训练时用了某种归一化方式推理时忘了同步精度莫名其妙掉了一截查了半天才发现是预处理不一致。这种低级错误在赶工期时特别容易犯建议把预处理逻辑封装成统一模块训练和推理共用。第二个心得模型剪枝和量化不要同时上。两个操作都会引入精度损失叠加起来很难定位问题来源。正确做法是先做量化评估精度稳定后再考虑剪枝或者反过来一步一步来每步都留好基线对比。第三个心得评估指标要跟业务对齐。学术上的 mAP 和业务上的“漏检率、误检率”不是一回事。如果你的业务对误检极其敏感比如门禁那评估时就要重点看高置信度下的误检情况而不是只看整体 mAP。指标选错了优化方向就会偏。7. 这套思路还能怎么迁移SCRFD 给我的最大启发不是某个具体模块而是“算力按目标分布重新分配”这个方法论。这个思路可以迁移到很多检测任务上做车辆检测就把算力往中远景的小车倾斜做工业缺陷检测就把算力往缺陷可能出现的高频区域倾斜。核心是先搞清楚你的目标在图像里的分布特征再决定网络的计算预算怎么切。另一个可迁移的点是训练侧的效率意识。很多人把训练当成黑盒喂数据等结果其实标签分配、数据增强、损失平衡这些环节都有大量可优化的空间而且这些优化往往不增加推理成本属于纯赚。我在后续项目里养成的习惯是模型结构定型后花一半时间在训练策略上做消融收益经常比换 backbone 还大。最后分享一个我在实际项目里反复验证的小技巧任何优化都先做单变量对比控制其他条件不变只改一个因素记录精度和速度的变化。听起来很基础但真正坚持做的人不多。我见过太多团队一次改好几个地方结果精度涨了不知道是谁的功劳掉了也不知道该回退哪个。老老实实做单变量实验虽然慢一点但每一步都踩得实最后积累下来的经验才是真正属于你自己的。