TL;DR — 本文介绍
face-light开源项目的设计思路、技术选型、三组核心实验的完整数据分析,以及从基线到蒸馏的优化路径。项目代码已开源:github.com/lechan775/face-light。
实时人脸检测与识别是边缘智能视觉的典型场景——从安防门禁、机器人交互到移动端身份核验,都需要在有限算力下完成"检测 → 对齐 → 识别"的端到端流水线。
现有的工业级方案(如 InsightFace)精度顶尖,但模型体积大、部署链路重;而轻量化领域缺少一套"从训练到部署"的完整开源管道。face-light 试图填补这个空白:纯 PyTorch 实现、单文件训练脚本、一行命令 ONNX 导出,目标是让研究者能在自己的数据集上快速复现和迭代。
项目源自一项本科毕业设计——"基于深度学习的人脸识别边缘端实时检测技术",但代码设计从一开始就按可复现开源项目的标准来写。
选择 SCRFD-500M 而非更流行的 YOLO 系列,出于三点考虑:
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]
MobileFaceNet 是移动端人脸识别的事实标准骨干:112×112 输入,纯倒残差结构,512 维嵌入。搭配 ArcFace 的加性角度边距损失。
蒸馏策略是本项目的核心优化手段:
| 损失项 | 权重 | 含义 |
|---|---|---|
L_cls (ArcFace) | 1.0 | 标准分类监督 |
L_feat (Cosine) | 18.0 | 学生/教师 embedding 方向一致 |
L_rel (SmoothL1) | 32.0 | 学生/教师 embedding 间的相对关系矩阵一致 |
L_feat 保证每个样本的 embedding 方向跟教师对齐,L_rel 更进一步:保证 batch 内任意两个样本的相似度关系也跟教师一致——这相当于在 embedding 空间做结构蒸馏。
检测和识别分开训练,不是做不到端到端,而是刻意为之:
共三组实验,从易到难递进:
| 实验 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 sampler | 26 (early stop) |
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
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 拉高,掩盖高难样本上的表现瓶颈。
| 指标 | 初始值 (epoch 0) | 最优值 (epoch 144) | 最终值 (epoch 164) |
|---|---|---|---|
| total_loss | 1.8406 | — | 0.9377 |
| cls_loss | 0.0347 | — | 0.0018 |
| box_loss | 0.6332 | — | 0.3455 |
| dfl_loss | 2.1583 | — | 0.9791 |
| AP50 | — | 0.5458 | — |
分析:
| 指标 | 初始值 (epoch 0) | 最优值 (epoch 29) | 最终值 (epoch 44) |
|---|---|---|---|
| train_loss | 63.5178 | — | 34.1785 |
| LFW accuracy | 0.5383 | 0.7502 | — |
| TAR@FAR=1e-4 | 0.0000 | — | 0.0000 |
分析:
| 指标 | 初始值 (epoch 0) | 最优值 (epoch 15) | 最终值 (epoch 25) |
|---|---|---|---|
| total_loss | 61.2342 | — | 23.5628 |
| cls_loss | 43.32 | — | 13.02 |
| feat_loss | 0.9842 | — | 0.5783 |
| rel_loss | 0.0062 | — | 0.0042 |
| LFW accuracy | — | 0.9558 | — |
| TAR@FAR=1e-3 | — | 0.0856 | — |
| TAR@FAR=1e-4 | — | 0.0416 | — |
| EER | — | 0.2549 | — |
分析:
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%)
三组实验的关系不是割裂的,而是构成了一个完整的优化路径:基线暴露问题 → 蒸馏解决区分度 → 下一步走向更强的检测器和更细粒度的数据策略。
基线实验证明了 MobileFaceNet 从零训练无法在有限数据上产生有区分度的 embedding。而引入教师蒸馏后,即使只训练 26 个 epoch,accuracy 就从 75% 跃升到 95.6%。这不是简单的"精度提升",而是从不可用到基本可用的质变。
基线实验用了 accuracy 做早停指标,蒸馏实验用了 TAR@FAR=1e-4。后者在低 FAR 场景下严格得多——模型可能在 accuracy 已经平稳时,TAR 仍在缓慢爬升。实践建议:始终用业务场景的最终指标做早停,而不是训练阶段的代理指标。
三组实验使用了同一套代码框架,但不同版本的数据(原始版 vs 清洗后版)。蒸馏实验之所以比基线好,除了蒸馏本身,数据清洗(去除低质量身份、平衡类别分布)也贡献了相当一部分收益。
bashgit clone https://github.com/lechan775/face-light.git
cd face-light
pip install -r requirements.txt
bashpython 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
bashpython 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
本项目使用了以下开源工作:
⭐ GitHub: lechan775/face-light · MIT License


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