拓冰建站拓冰建站
首页 / 资讯中心 / 正文

YOLOv5+ArcFace实战:从零搭建人脸识别门禁系统全流程

简介面向深度学习和计算机视觉开发者这份基于YOLOv5与ArcFace的人脸识别项目资源包整合了实时目标检测与人脸识别两项前沿技术覆盖人脸检测、特征提取、身份识别及活体检测流程适用于安防监控、门禁考勤等实际场景。压缩包内共51个文件以26个Python脚本为主干涵盖模型训练、测试、数据预处理与推理调用同时包含2个预训练权重、7个YAML模型配置、4张测试图像以及活体检测相关代码整体仅3.41MB便于快速获取与部署。资源已有1498人学习下载。内容按检测、识别、活体检测等模块清晰组织附有说明文档与训练、测试脚本能够帮助读者理解从人脸检测到识别比对的完整实现思路适合具备一定基础、希望快速上手完整人脸识别项目的开发者参考。 先聊点实在的这套“YOLOv5 ArcFace”方案我前后大概花了三周时间从零跑通最后落地成一个人脸识别门禁的Demo。当时选型的时候也不是没纠结过开源的SDK一大堆商用接口也方便但考虑到数据要留在本地、后续要接入自己的业务系统最后还是决定自己从头搭一套。今天把整个项目的来龙去脉、踩过的坑、调参经验一次说清楚想自己动手做一套人脸识别系统的朋友可以直接拿走。这套项目的核心链路不复杂先用YOLOv5把画面里的人脸框出来再用ArcFace把框出来的人脸转成一个512维的特征向量最后拿这个向量去和底库里的注册特征做余弦相似度比对超过阈值就算识别成功。听起来简单但每个环节都藏着不少细节下面逐个拆开讲。1. 项目背景与技术选型思路1.1 为什么选“YOLOv5 ArcFace”这套组合先说检测端。早期人脸检测大家都用MTCNN轻量归轻量但实际场景里一旦出现侧脸、遮挡、低分辨率漏检率就上来了。后来RetinaFace、SCRFD这些精度确实更好但部署复杂度也跟着上来了。YOLOv5的优势在于它把目标检测的整个链路做得极其成熟——训练、验证、导出、部署都有现成脚本网上资料还铺天盖地遇到问题基本都能搜到答案。而且YOLOv5本质上是通用检测器你不仅可以用它检测人脸后续想顺手检测一下人体、车辆也完全没问题一个模型多个用途性价比很高。再说识别端。ArcFaceAdditive Angular Margin Loss是当前人脸识别领域最主流的方案之一它在Softmax基础上引入了角度间隔让模型学到的特征在余弦空间里类内更紧凑、类间更分散。相比FaceNet的Triplet Loss那套需要精心构造三元组的方案ArcFace的损失函数简洁稳定训练收敛也更省心。InsightFace开源仓库里提供了大量预训练模型包括ResNet50、MobileFaceNet这些backbone版本拿来即用做二次开发非常方便。我的最终结论检测用YOLOv5识别用ArcFace两者各司其职链路短、可控性强。1.2 这套方案的适用场景和边界这套方案不是万能的。落地之前务必要先搞清楚它的能力边界否则后面心态容易崩。在设备端你需要一块还说得过去的GPU哪怕是GTX 1060 6G这种入门级显卡跑YOLOv5sArcFace的推理也够用。纯CPU跑的话检测一帧640×640大约要300ms识别一次也要100ms上下实时性会很勉强。在数据上ArcFace这类深度学习模型的识别效果极度依赖注册照片的画质。你给底库传一张十年前的模糊证件照然后指望现场摄像头能认出人来这不现实。在人数规模上如果你的底库有几百万张人脸那用暴力遍历所有特征做相似度计算就慢了必须上Milvus、Faiss这类向量检索库。但日常项目里几千人的底库直接Numpy矩阵运算就能搞定毫秒级返回。在交互方式上这套方案默认是“离线本地识别”不依赖外部API数据不出内网对隐私敏感的政企项目来说反而是加分项。一句话总结这套方案适合做中小规模千人级、有GPU资源、要求数据本地化的人脸识别系统。2. 整体流程与核心模块拆解2.1 从视频流到识别结果一条完整链路很多人第一次接触人脸识别项目时容易被各种名词绕晕检测、关键点、对齐、特征提取、比对、阈值……其实整个链路跟我们去火车站刷身份证过闸机很类似。过程拆开就是这样摄像头采集一帧画面。YOLOv5在这帧画面里找出所有人脸输出每个脸的位置框x1, y1, x2, y2和置信度。把框出来的人脸区域裁下来用关键点模型或者YOLOv5同时输出的关键点做人脸对齐把人脸摆正并缩放到112×112或160×160像素。把对齐后的人脸图像送入ArcFace特征提取模型得到一个512维的浮点数组这就是这张脸的“数字指纹”。拿这个512维向量和底库里的所有人脸向量算余弦相似度取最大值如果大于设定阈值比如0.45就判定为底库中对应的人。这里面有一个很容易被新手忽略的关键点识别不是拿“照片”直接比而是拿“特征向量”比。这跟你把一张照片缩放到不同大小还是同一张照片是一个道理因为向量是对人脸本质特征的压缩表示对光照、角度、表情有一定鲁棒性但绝非完全不变。2.2 检测、对齐、识别三个环节各管什么事这三个环节各自的职责必须拎清否则出了问题都没法定位检测负责回答“人脸的框在哪”。它不管你是谁只负责把人脸从背景里找出来。YOLOv5框不准后面识别做得再好也无济于事相当于你把一个陌生人塞进了比对程序。对齐负责回答“人脸怎么摆正”。摄像头里人脸的姿态千奇百怪低头、歪头、侧脸都有。ArcFace模型训练时输入的是标准正脸如果直接把歪着的人脸送进去提取的特征会差很多。所以需要用双眼、鼻尖、嘴角这五个关键点做仿射变换把人脸校正到标准位置。这一步的精度直接决定识别率的上限。识别负责回答“这个人是谁”。它把对齐后的人脸编码成特征向量再和底库比对。这个环节的模型是事先训练好的通常不需要你自己训练直接用InsightFace的预训练权重即可。三者是流水线关系任何一环出问题最终结果都会跟着崩。3. 环境搭建与YOLOv5检测器实战3.1 环境配置照着抄就行先说环境。我当时的配置是Ubuntu 20.04 Python 3.8 PyTorch 1.12 CUDA 11.3现在Python 3.10、PyTorch 2.x也都没问题YOLOv5官方仓库一直在更新适配性很好。# 克隆YOLOv5仓库并安装依赖 git clone https://github.com/ultralytics/yolov5.git cd yolov5 pip install -r requirements.txt # 验证环境 python detect.py --source data/images/bus.jpg --weights yolov5s.ptYOLOv5自带的人脸检测能力其实很弱因为预训练权重是在COCO数据集上训练的COCO里有person类但没有face类所以你必须用自己的数据集微调出来一个专门检测人脸的模型。这一步数据是爹后面细说。ArcFace这边我直接用的InsightFace的Python库一行命令装好省去自己处理模型文件的麻烦。pip install insightface pip install onnxruntime-gpu # 如果有GPU用GPU版推理3.2 用你自己的数据集训练YOLOv5人脸检测器说句实话训练人脸检测器最繁琐的不是模型调参而是数据准备。你要么用WIDER Face这种公开数据集要么自己标注几百张业务场景里的照片。我建训练集时把公开数据集和自己采集的照片混合了大约2万张效果比单纯用公开数据集好很多因为业务场景的光线、角度、摄像头位置都和公开数据集不太一样。标注工具用的是LabelImg保存成YOLO格式的txt文件每一行是class x_center y_center width height坐标都是归一化到0~1之间的比例值。人脸检测通常只设一个类别命名为face。数据准备好后修改data.yamltrain: /data/face_dataset/images/train val: /data/face_dataset/images/val nc: 1 names: [face]开始训练python train.py --img 640 --batch 16 --epochs 100 --data data.yaml --weights yolov5s.pt --device 0这里有几个参数直接关乎训练效果。--img设成640是速度与精度的折中太低小脸检测不到太高显存不够速度也慢。--batch根据自己的显存调整显存不够就把batch调小。--weights强烈建议用yolov5s.pt预训练权重做迁移学习而不是从零开始训练收敛速度快得多精度也更好。训练到第50轮左右就可以看验证集效果了挑选mAP最高的权重即可。3.3 检测环节的参数细节与避坑训练完模型加载推理时有两个参数你必须关注conf_thres置信度阈值和iou_thresNMS阈值。conf_thres设太低比如0.1会出现大量误检把背景里的纹理误认为人脸设太高比如0.7又会漏检模糊或侧脸。我用下来0.25~0.5之间比较合适具体看你的场景。iou_thres控制NMS对重叠框的抑制力度一般保持默认的0.45即可。另外有个小细节如果画面存在大量小脸比如教室后排的学生建议把--img提到800甚至960代价是推理时间变长。如果非要保持速度可以试试给图像做金字塔缩放或者用SAHI切片推理但这些属于进阶操作基础版先把分辨率拉起来。4. ArcFace特征提取与识别比对4.1 用InsightFace快速上手特征提取InsightFace的Python库封装得很好几行代码就能完成对齐和识别完全不用自己处理太多底层细节import numpy as np import insightface from insightface.app import FaceAnalysis # 初始化模型buffalo_l是包含检测、关键点、识别的一体化模型包 app FaceAnalysis(namebuffalo_l) app.prepare(ctx_id0, det_size(640, 640)) # 读取图像获取人脸信息 img cv2.imread(person.jpg) faces app.get(img) for face in faces: # 512维识别向量 embedding face.normed_embedding # 人脸框坐标 bbox face.bbox # 5个关键点坐标 kps face.kps需要特别说明的是buffalo_l这个模型包里的检测器是SCRFD效果已经非常好了但你既然训练了自己的YOLOv5模型完全可以通过修改face.det_model来用自己训练的YOLOv5代替内置检测器识别和关键点模型继续用ArcFace的这样能把你场景下的检测效果和识别效果同时拉满。4.2 特征比对与阈值选择数学原理与工程权衡识别比对的核心是余弦相似度。设两个512维特征向量为A和B余弦相似度计算如下cos(A, B) Σ(A_i * B_i) / (√Σ(A_i²) * √Σ(B_i²))几何意义是两个向量在多维空间中的夹角余弦值取值在-1到1之间。越接近1代表两个向量方向越一致也就是两张脸越像。一方面当两个向量经过L2归一化后即模长为1余弦相似度等价于点积InsightFace返回的normed_embedding已经做了归一化所以直接用np.dot就能算相似度。阈值怎么定LFW等公开数据集上ArcFace能达到99%以上的准确率但那是实验室条件下的结果。真实场景我建议按下面的经验来场景说明建议阈值余弦相似度备注考勤打卡室内光线稳定0.45~0.50阈值偏低通过率高门禁控制要求安全0.55~0.60宁可拒绝也别放错安防监控画面复杂0.50~0.55结合多帧投票更稳调阈值最靠谱的办法还是你拿一批真实场景的正样本对同一个人的两张照片和负样本对两个不同的人算出相似度的分布取两者之间间隔的中值。我当年就是这么干的自己实际场景采了1000对正负样本画成直方图以后一目了然。4.3 我在比对环节踩过的坑底库特征没归一化InsightFace返回的特征已经归一化了但从其他渠道获取的模型不一定。如果底库特征和查询特征归一化方式不一致余弦相似度全是乱的识别结果毫无意义。建议统一先做一次L2归一化再入库。只看单帧对比就下结论实时监控里忽明忽暗、低头抬头都会导致单帧相似度波动很大。我后来改成5帧连续检测取相似度均值稳定性提升非常明显。底库照片质量没过关底库照片不清晰、光照太暗、角度太偏识别率必然崩。入库前我加了个质量评分逻辑清晰度和人脸大小低于阈值的直接拒掉宁缺毋滥。5. 系统联调与性能优化5.1 端到端流程打通整体流程串起来以后代码结构大致是这样import cv2 import numpy as np import insightface # 初始化ArcFace识别模型关键点对齐特征提取 recognizer insightface.app.FaceAnalysis(namebuffalo_l) recognizer.prepare(ctx_id0, det_size(640, 640)) # 加载训练好的YOLOv5检测器 import torch detector torch.hub.load(ultralytics/yolov5, custom, pathbest.pt, force_reloadTrue) detector.conf 0.4 detector.iou 0.45 # 注册底库 def register_face(image, person_id): faces recognizer.get(image) if len(faces) 0: embedding faces[0].normed_embedding # 这里把embedding和person_id存入向量数据库/表 return embedding else: return None # 实时识别 def recognize(frame): results detector(frame) dets results.xyxy[0].cpu().numpy() # x1 y1 x2 y2 conf class for det in dets: x1, y1, x2, y2, conf, cls det.astype(int) face_crop frame[y1:y2, x1:x2] # 识别模型自身会再检测一次但这里我们可以手动对齐裁剪区域 face recognizer.get(face_crop) if len(face) 0: emb face[0].normed_embedding scores np.dot(db_embeddings, emb) best_idx np.argmax(scores) if scores[best_idx] 0.5: return person_ids[best_idx], scores[best_idx] return None, 0.0这里有个细节recognizer.get()本身就是“检测对齐特征提取”一步到位的接口但如果你已经用YOLOv5检测到人脸框了可以直接裁出人脸区域再调用一次get()或者用get_feat这类接口跳过重复检测既减少计算量又保证了流程一致性。实际项目中更推荐的方式还是让YOLOv5负责框选然后把坐标传给ArcFace做对齐和特征提取。5.2 推理速度优化实测对比用YOLOv5s ArcFaceResNet50在几类设备上的单帧推理耗时实测如下设备检测耗时(ms)识别耗时(ms)单帧总耗时(ms)可实时?GTX 1080 Ti81018流畅RTX 3060 Laptop121527流畅CPUi7-9700280120400不流畅Jetson Nano354075基本可用如果你部署在边缘设备上有几个提速手段把YOLOv5导出为TensorRT engine用FP16精度推理速度能再快30%~50%。ArcFace的backbone从ResNet50换成MobileFaceNet特征维度不变还是512维但推理耗时能降一半以上识别精度略微下降大多数场景能接受。用ONNX Runtime代替PyTorch原生推理免去Python侧的开销适合部署在服务器上。5.3 多线程处理摄像头采集和识别解耦一套实时识别系统不能是“采一帧、算一帧”的串行结构否则画面会卡到没法看。正确做法是生产者-消费者模式一个线程负责读摄像头并做检测把检测到的人脸框塞进队列另一个线程专门做人脸识别从队列里取结果把识别结果异步通知业务系统。队列可以用Python的queue.Queue设置最大长度防止内存被撑爆。实测下来生产者-消费者模式能让整体吞吐量提升2~3倍视频流处理不再卡顿。6. 常见问题与排查技巧实录6.1 我踩过的坑和解决方案速查表现象可能原因解决方法检测漏掉了远处小脸输入分辨率太低增大det_size或YOLO的--img尺寸识别总是失败对齐不准或注册照片质量差检查关键点是否正确对齐重新注册高质量底库照片一帧里识别出多个“同一人”NMS没生效检查NMS阈值改用agnostic_nmsTrue跨类别抑制换了张照片就认不出来了光照影响太大对图像做直方图均衡化多角度注册多张底库照片CPU上跑得巨慢模型太重/未量化换MobileFaceNet尝试INT8量化降低输入分辨率摄像头画质太差硬件瓶颈换高清USB摄像头适当调低帧率用多帧投票保证准确率底库中某人频繁误识别成他人底库照片太相似双胞胎或相似面孔调高阈值给该人员增加多张不同角度的底库照片6.2 独家经验生产环境里真正的“坑”在哪几个常规文档里不会告诉你的点阈值不是全局统一的。室内门禁和户外露天场景的光照条件完全不同硬要用同一个相似度阈值大概率两头不讨好。更科学的做法是按时间段或场景动态切换阈值——白天阈值高一点夜间采用红外补光时阈值适当降一降。底库容量不是越大越好。底库一旦超过几千人特征之间的余弦相似度分布会变得密集出现“相似得分普遍升高”的现象导致误识率上升。这时候传统的固定阈值就失效了建议改用Top-1加相对距离判断即“最高分与第二高分的差值是否足够大”能显著降低错认概率。特征向量需要定期更新。人的脸会随着年龄、发型、体重变化注册时存入的底库特征会逐渐“过期”。我测试过一个用户隔了一年后的照片相似度从0.6降到了0.42差点认不出来。所以系统需要设计一个“自动更新”机制连续多次被识别为同一个人的高置信度特征可以去更新底库里的旧特征保证系统的长期可用性。7. 这套方案还能怎么扩展聊到这儿基础的人脸识别系统已经能跑通了。最后简单说说扩展方向。如果你做了毕设或者公司内部项目后续可以考虑这几个方向人脸质量评估在注册和识别之前用BLUR、光照、姿态等维度给每张人脸打分只对质量分超过阈值的人脸做特征提取。能解决很多“极端角度识别失败”的问题。活体检测目前方案只能识别“脸”但识别不出照片、视频、面具。加一个红外活体或者RGB活体检测模块判断“镜头前的人是不是活的”这是商业落地的硬要求。人脸检索系统把特征向量存到Milvus支持“以图搜图”可以从几百万人脸库里快速找到同一个人。端侧部署用NCNN或者MNN把YOLOv5和ArcFace模型跑到手机或树莓派上实现完全的本地离线识别。我试过在树莓派5上部署自己训练的YOLOv5s加上ArcFace的MobileFaceNet一帧大约150ms流畅度和精度平衡得很好。我在做这个项目的过程中最大的体会是人脸识别项目真正难的不是模型本身而是把检测、对齐、识别、对比、入库、部署这一整条链路按一个整体去考虑在真实场景里把各个模块的阈值和参数调对。这套方案网上资料很多、坑也不少但只要你按照上面的流程一步步来稳扎稳打是能跑出一个生产可用级别的系统的。希望这篇记录能帮你少走一些弯路。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门