编辑
2026-05-31
科研
00

目录

1. 项目背景
2. 技术选型
2.1 检测器:SCRFD-500M
2.2 识别器:MobileFaceNet + ArcFace + 知识蒸馏
2.3 为什么不端到端?
3. 实验设计
3.1 统一训练配置
3.2 检测训练细节
3.3 识别蒸馏训练细节
4. 实验结果
4.1 检测:DETBASE001
4.2 识别基线:RECBASE001
4.3 识别蒸馏:RECDISTILL001
4.4 三组实验纵向对比
5. 关键发现
5.1 蒸馏是轻量级识别的必要手段
5.2 早停指标的选择很关键
5.3 检测和识别的瓶颈不同
5.4 数据质量 > 模型结构
6. 复现指南
环境
训练检测器
训练识别器(蒸馏)
评估
ONNX 导出
7. 下一步计划
8. 致谢

TL;DR — 本文介绍 face-light 开源项目的设计思路、技术选型、三组核心实验的完整数据分析,以及从基线到蒸馏的优化路径。项目代码已开源:github.com/lechan775/face-light


1. 项目背景

实时人脸检测与识别是边缘智能视觉的典型场景——从安防门禁、机器人交互到移动端身份核验,都需要在有限算力下完成"检测 → 对齐 → 识别"的端到端流水线。

现有的工业级方案(如 InsightFace)精度顶尖,但模型体积大、部署链路重;而轻量化领域缺少一套"从训练到部署"的完整开源管道。face-light 试图填补这个空白:纯 PyTorch 实现、单文件训练脚本、一行命令 ONNX 导出,目标是让研究者能在自己的数据集上快速复现和迭代。

项目源自一项本科毕业设计——"基于深度学习的人脸识别边缘端实时检测技术",但代码设计从一开始就按可复现开源项目的标准来写。


2. 技术选型

2.1 检测器:SCRFD-500M

选择 SCRFD-500M 而非更流行的 YOLO 系列,出于三点考虑:

  1. 专为 face 设计:SCRFD 原生考虑了人脸尺度分布(小脸→大脸),不像通用检测器需要额外的锚点调整
  2. anchor-free 头:用 Quality Focal Loss + Distribution Focal Loss 替代传统 anchor 匹配,代码更短(~200 行的 label assignment)
  3. 极致轻量:STEM 16 通道起,depthwise separable 全链路,总参数量 ~0.57M
Input (3×640×640) → Stem(16ch,s=2) → 4× DSConv + IRB → FPN(out=64) → Shared Head(DSConv×2 → cls:1 + reg:36) → DFL decode → NMS → [x1,y1,x2,y2,conf]

2.2 识别器:MobileFaceNet + ArcFace + 知识蒸馏

MobileFaceNet 是移动端人脸识别的事实标准骨干:112×112 输入,纯倒残差结构,512 维嵌入。搭配 ArcFace 的加性角度边距损失。

蒸馏策略是本项目的核心优化手段:

  • 教师模型:InsightFace buffalo_l(ResNet-50,512d embedding)
  • 蒸馏损失三件套
损失项权重含义
L_cls (ArcFace)1.0标准分类监督
L_feat (Cosine)18.0学生/教师 embedding 方向一致
L_rel (SmoothL1)32.0学生/教师 embedding 间的相对关系矩阵一致

L_feat 保证每个样本的 embedding 方向跟教师对齐,L_rel 更进一步:保证 batch 内任意两个样本的相似度关系也跟教师一致——这相当于在 embedding 空间做结构蒸馏

2.3 为什么不端到端?

检测和识别分开训练,不是做不到端到端,而是刻意为之:

  • 独立迭代:换检测器不影响识别,反之亦然
  • 数据策略不同:检测数据(WIDER Face)和识别数据(身份标注)来源不同、标注成本不同,混在一起反而互相干扰
  • 工程灵活性:部署时检测帧可降频(每 3 帧跑一次),识别只在确认是人脸的帧上跑

3. 实验设计

共三组实验,从易到难递进:

实验 ID任务模型关键策略训练轮数
DET_BASE_001检测SCRFD-500M基线 + 多尺度训练165 (early stop)
REC_BASE_001识别MobileFaceNet + ArcFace基线45 (early stop)
REC_DISTILL_001识别MobileFaceNet + ArcFace + Distill教师蒸馏 + class-balanced sampler26 (early stop)

3.1 统一训练配置

  • 优化器:SGD + momentum=0.9 + weight_decay=5e-4
  • 学习率策略:CosineAnnealingLR + Linear Warmup
  • 混合精度:AMP (autocast + GradScaler)
  • 早停:patience = 10~20 epochs
  • 硬件:单卡 NVIDIA RTX 3060 (12GB) / A800 (80GB)

3.2 检测训练细节

batch_size: 128 input_size: 640 (multi-scale: [512,544,576,608,640,672]) epochs: 200 lr: 0.01 → warmup 5 epochs → cosine decay to 0.0005 augmentation: hflip(0.5) + brightness(0.2) + contrast(0.2) + HSV(0.1) + blur + jpeg_compression

3.3 识别蒸馏训练细节

batch_size: 256 input_size: 112 epochs: 60 lr: 0.008 → warmup 3 epochs → cosine decay augmentation: hflip(0.5) + mild color jitter(0.08) + grayscale(0.02) + gaussian blur(0.02) sampler: class-balanced (power=0.35, replacement) early_stop_metric: TAR@FAR=1e-4 early_stop_metric_secondary: EER

选择 TAR@FAR=1e-4 作为主指标而非简单的 accuracy,是因为在安防场景下,低误识率(FAR=万分之一)下的识别通过率才是真正有价值的指标——accuracy 会被大量 easy negatives 拉高,掩盖高难样本上的表现瓶颈。


4. 实验结果

4.1 检测:DET_BASE_001

指标初始值 (epoch 0)最优值 (epoch 144)最终值 (epoch 164)
total_loss1.84060.9377
cls_loss0.03470.0018
box_loss0.63320.3455
dfl_loss2.15830.9791
AP500.5458

分析

  • cls_loss 从 0.0347 收敛到 0.0018(下降 94.8%),说明 QFL 分类头收敛良好
  • box_loss 从 0.6332 收敛到 0.3455(下降 45.4%),GIoU 回归仍在改善但速度放缓
  • dfl_loss 从 2.1583 降至 0.9791(下降 54.6%),DFL 分布回归也在持续优化
  • AP50=0.5458 偏低,主要原因判断:
    1. 训练数据规模有限(WIDER Face train 子集,约 12,800 张)
    2. 未引入 WIDER Face 的 hard negative mining
    3. 小脸检测是该架构的天然短板(stride=8 的最小检测分辨率有限)

4.2 识别基线:REC_BASE_001

指标初始值 (epoch 0)最优值 (epoch 29)最终值 (epoch 44)
train_loss63.517834.1785
LFW accuracy0.53830.7502
TAR@FAR=1e-40.00000.0000

分析

  • 训练损失下降 46.2%,但 LFW accuracy 仅到 75.02%——远低于 SOTA(~99.8%)
  • TAR@FAR=1e-4 始终为 0:在极端低误识条件下,模型无法区分正负样本对
  • 根因判断:基线实验使用了较早版本的训练数据(可能存在标注噪音),且 ArcFace margin(m=0.7, s=80)的组合在 50 epochs 内未能充分收敛
  • 这组实验虽然有"翻车"的味道,但恰好证明了:仅靠 MobileFaceNet + ArcFace 的 naive 训练,无法在有限数据上收敛到可用水平

4.3 识别蒸馏:REC_DISTILL_001

指标初始值 (epoch 0)最优值 (epoch 15)最终值 (epoch 25)
total_loss61.234223.5628
cls_loss43.3213.02
feat_loss0.98420.5783
rel_loss0.00620.0042
LFW accuracy0.9558
TAR@FAR=1e-30.0856
TAR@FAR=1e-40.0416
EER0.2549

分析

  • 蒸馏将 LFW accuracy 从 75.02%(基线)提升到 95.58%——+20.56 个百分点
  • TAR@FAR=1e-4 从 0 突破到 0.0416——终于有了低 FAR 场景下的识别能力
  • feat_loss 从 0.9842 降到 0.5783,说明学生 embedding 在逐步对齐教师的方向
  • rel_loss 从 0.0062 降到 0.0042,关系矩阵蒸馏也在收敛
  • 但 95.58% 仍然显著低于 buffalo_l 教师(~99.8%)和 SOTA,说明:
    1. 蒸馏权重(cls:1.0 / feat:18.0 / rel:32.0)可能不是最优配比——rel_weight=32 偏高可能过度约束了学生
    2. 仅 26 epochs 就被早停(patience=10, 主指标 TAR@FAR=1e-4 提升缓慢)
    3. class-balanced sampler 的 power=0.35 可能过于激进,导致 long-tail 类别被过度采样

4.4 三组实验纵向对比

REC_BASE_001 ──→ REC_DISTILL_001 LFW accuracy: 75.02% ──→ 95.58% (+27.4%) TAR@FAR=1e-4: 0.0000 ──→ 0.0416 (突破) EER: N/A ──→ 0.2549 DET_BASE_001 AP50: 54.58% cls_loss 收敛: 0.0347 → 0.0018 (-94.8%) box_loss 收敛: 0.6332 → 0.3455 (-45.4%)

三组实验的关系不是割裂的,而是构成了一个完整的优化路径:基线暴露问题 → 蒸馏解决区分度 → 下一步走向更强的检测器和更细粒度的数据策略


5. 关键发现

5.1 蒸馏是轻量级识别的必要手段

基线实验证明了 MobileFaceNet 从零训练无法在有限数据上产生有区分度的 embedding。而引入教师蒸馏后,即使只训练 26 个 epoch,accuracy 就从 75% 跃升到 95.6%。这不是简单的"精度提升",而是从不可用到基本可用的质变

5.2 早停指标的选择很关键

基线实验用了 accuracy 做早停指标,蒸馏实验用了 TAR@FAR=1e-4。后者在低 FAR 场景下严格得多——模型可能在 accuracy 已经平稳时,TAR 仍在缓慢爬升。实践建议:始终用业务场景的最终指标做早停,而不是训练阶段的代理指标。

5.3 检测和识别的瓶颈不同

  • 检测瓶颈在定位(box_loss 收敛速度远慢于 cls_loss),需要更多数据或更强的 backbone
  • 识别瓶颈在区分度(embedding 空间的可分性),可以通过蒸馏和难例挖掘改善

5.4 数据质量 > 模型结构

三组实验使用了同一套代码框架,但不同版本的数据(原始版 vs 清洗后版)。蒸馏实验之所以比基线好,除了蒸馏本身,数据清洗(去除低质量身份、平衡类别分布)也贡献了相当一部分收益。


6. 复现指南

环境

bash
git clone https://github.com/lechan775/face-light.git cd face-light pip install -r requirements.txt

训练检测器

bash
python train_detector.py \ --config configs/train/det_scrfd_base.yaml \ --seed 42 \ --exp-id DET_MY_EXP \ --log-dir runs/train/detection/DET_MY_EXP

训练识别器(蒸馏)

bash
# 确保教师模型已下载至 ~/.insightface/models/buffalo_l/ python train_recognizer_distill.py \ --config configs/train/rec_mobilefacenet_arcface_distill.yaml \ --seed 42 \ --exp-id REC_DISTILL_MY_EXP \ --log-dir runs/train/recognition/REC_DISTILL_MY_EXP

评估

bash
# 检测器 AP50 python tools/eval/eval_detector.py \ --model-path runs/train/detection/DET_MY_EXP/best.pt \ --backend pytorch \ --dataset-root data/processed/detection \ --split val --out-dir runs/eval/detection/DET_MY_EXP # 识别器 TAR@FAR python tools/eval/eval_recognizer.py \ --model-path runs/train/recognition/REC_DISTILL_MY_EXP/best.pt \ --embed-dim 512 \ --pairs-file data/processed/recognition/eval/protocols/lfw/pairs.txt \ --lfw-dir data/processed/recognition/eval/lfw \ --out-dir runs/eval/recognition/REC_DISTILL_MY_EXP

ONNX 导出

bash
python export_onnx.py --task detection --weights best.pt --imgsz 640 640 --out detector.onnx python export_onnx.py --task recognition --weights best.pt --imgsz 112 112 --out recognizer.onnx

7. 下一步计划

  • 检测器升级:尝试 SCRFD-2.5G 或 Nanodet-Plus,配合 WIDER Face 全量数据 + hard negative mining
  • 蒸馏调参:Grid Search 寻找最优 (feat_weight, rel_weight) 组合
  • 引入更多验证协议:CFP-FP、AgeDB-30、自建场景集
  • TensorRT 部署:FP16 量化 + 端到端延迟基准测试
  • 检测-识别联合优化:检测输出的 face crop 质量直接反馈到识别 loss

8. 致谢

本项目使用了以下开源工作:


如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:williams

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!