# 1. 前言
# 1.1 人脸检测与人脸识别
人脸检测是对人脸进行识别和处理的第一步,主要用于检测并定位图片中的人脸,返回高精度的人脸框坐标及人脸特征点坐标。人脸识别会进一步提取每个人脸中所蕴涵的身份特征,并将其与已知的人脸进行对比,从而识别每个人脸的身份。目前人脸检测 / 识别的应用场景逐渐从室内演变到室外,从单一限定场景发展到广场、车站、地铁口等场景,人脸检测 / 识别面临的要求也越来越高,比如:人脸尺度多变、数量冗大、姿势多样包括俯拍人脸、戴帽子口罩等的遮挡、表情夸张、化妆伪装、光照条件恶劣、分辨率低甚至连肉眼都较难区分等。随着深度学习的发展,基于深度学习技术的人脸检测 / 识别方法取得了巨大的成功,本文主要介绍人脸检测的深度学习算法 RetinaFace 和人脸识别的深度学习算法 FaceNet。
# 1.2 RetinaFace人脸检测
Retinaface是Insightface团队在2019年提出的新人脸检测模型,该模型在 WiderFace 数据集上刷新了AP。原模型使用mxnet框架进行搭建,目前社区也有其他框架复现的版本,其中最让人熟知的莫过于Pytorch版的Retinaface。Retinaface是基于检测网络RetinaNet的改进版,添加了SSH网络的三层级联检测模块,提升检测精度。
论文原文:https://arxiv.org/pdf/1905.00641.pdf (opens new window)
项目地址1(MXNet实现):https://github.com/deepinsight/insightface/tree/master/RetinaFace (opens new window)
项目地址2(Pytorch实现):https://github.com/biubug6/Pytorch_Retinaface (opens new window)(本文示例使用这个)
预训练模型:https://drive.google.com/open?id=1oZRSG0ZegbVkVwUd8wUIQx8W7yfZ_ki1 (opens new window)
# 1.3 FaceNet人脸特征提取及匹配
Google工程师Florian Schroff,Dmitry Kalenichenko,James Philbin提出了人脸识别FaceNet模型,该模型没有用传统的softmax的方式去进行分类学习,而是抽取其中某一层作为特征,学习一个从图像到欧式空间的编码方法,然后基于这个编码再做人脸识别、人脸验证和人脸聚类等。
FaceNet主要用于验证人脸是否为同一个人,通过人脸识别这个人是谁。FaceNet的主要思想是把人脸图像映射到一个多维空间,通过空间距离表示人脸的相似度。同个人脸图像的空间距离比较小,不同人脸图像的空间距离比较大。这样通过人脸图像的空间映射就可以实现人脸识别,FaceNet中采用基于深度神经网络的图像映射方法和基于triplets(三联子)的loss函数训练神经网络,网络直接输出为128维度的向量空间。
FaceNet的网络结构如下图所示,其中Batch表示人脸的训练数据,接下来是深度卷积神经网络,然后采用L2归一化操作,得到人脸图像的特征表示,最后为三元组(Triplet Loss)的损失函数。
论文原文:https://arxiv.org/pdf/1503.03832.pdf (opens new window)
项目地址:https://github.com/davidsandberg/facenet (opens new window)
预训练模型:facenet的原作者提供了两个预训练的模型,分别是基于CASIA-WebFace和VGGFace2人脸库训练的。
Model name | LFW accuracy | Training dataset | Architecture |
---|---|---|---|
20180408-102900 (opens new window) | 0.9905 | CASIA-WebFace | Inception ResNet v1 (opens new window) |
20180402-114759 (opens new window) | 0.9965 | VGGFace2 | Inception ResNet v1 (opens new window) |
# 2. 封装部署人脸识别服务
# 2.1 本地运行RetinaFace人脸检测官方示例
在本地使用Mac运行测试程序,用CPU运行,使用官方的预训练模型,不自己训练模型了。
PC型号及配置:Macbook Pro2021,M1Pro芯片,16GB内存,512GB存储
系统版本:macos Monterey 12.6
Step1:下载 源码 (opens new window)、预训练模型 (opens new window)(放在 Retinaface_model_v2 目录里)并安装项目依赖,项目结构如下:
.
├── LICENSE.MIT
├── README.md
├── Retinaface_model_v2
│ ├── Resnet50_Final.pth
│ ├── mobilenet0.25_Final.pth
│ └── mobilenetV1X0.25_pretrain.tar
├── convert_to_onnx.py
├── curve
├── data
├── detect.py
├── layers
├── models
├── test_fddb.py
├── test_widerface.py
├── train.py
├── utils
└── widerface_evaluate
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Step2:修改一下参数并运行人脸检测程序detect.py
parser = argparse.ArgumentParser(description='Retinaface')
parser.add_argument('-m', '--trained_model', default='./Retinaface_model_v2/Resnet50_Final.pth',
type=str, help='Trained state_dict file path to open') # 默认路径为 ./weights/Resnet50_Final.pth
parser.add_argument('--network', default='resnet50', help='Backbone network mobile0.25 or resnet50')
parser.add_argument('--cpu', action="store_true", default=True, help='Use cpu inference') # 默认False,由于用不了GPU,就改成CPU运行
parser.add_argument('--confidence_threshold', default=0.02, type=float, help='confidence_threshold')
parser.add_argument('--top_k', default=5000, type=int, help='top_k')
parser.add_argument('--nms_threshold', default=0.4, type=float, help='nms_threshold')
parser.add_argument('--keep_top_k', default=750, type=int, help='keep_top_k')
parser.add_argument('-s', '--save_image', action="store_true", default=True, help='show detection results')
parser.add_argument('--vis_thres', default=0.6, type=float, help='visualization_threshold')
args = parser.parse_args()
2
3
4
5
6
7
8
9
10
11
12
13
程序运行起来后,会用curve目录里的test.jpg作为测试文件,生成效果如下:
# 2.2 封装成特定人物识别服务
# 2.2.1 目录结构及使用说明
使用 Flask 将 RetinaFace 和 FaceNet 封装成特定人物识别服务,代码我已在Github上开源。
项目目录结构如下:
.
├── core // 核心算法模块(包括 RetinaFace 和 FaceNet 及相关处理)
│ ├── data
│ │ ├── __init__.py
│ │ ├── config.py
│ │ ├── data_augment.py
│ │ └── wider_face.py
│ ├── facenet
│ │ ├── facenet.py
│ │ ├── get_database_vector.py
│ │ └── start_facenet.py
│ ├── layers
│ │ ├── __init__.py
│ │ ├── functions
│ │ └── modules
│ ├── models // 算法模型
│ │ ├── Retinaface_model_v2
│ │ ├── facenet
│ │ ├── net.py
│ │ └── retinaface.py
│ ├── save_face_database // 人脸底库
│ │ ├── baideng
│ │ └── telangpu
│ ├── utils
│ │ ├── box_utils.py
│ │ ├── compare_vector.py
│ │ ├── nms
│ │ └── timer.py
│ └── face_identify.py // 人脸识别服务的主入口(用于给Flask调用)
├── log.py
├── code.py
├── response.py
├── server.py // 使用Flask封装好的服务
└── server_test.py // 测试服务
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
使用说明:
[1] 运行环境:项目代码里我使用的是CPU运行方式。如果有GPU,可以修改一下配置,将其改成GPU方式运行(需要注意的是,PyTorch 及 Tensorflow 的依赖需要安装对应GPU版本的)。
[2] 人脸底库更换:人脸底库放在 save_face_database 目录,制作人脸底库的时候注意只保留人脸,左侧脸30度+右侧脸30度+正脸各2张,更换人脸底库后,需要修改一下 face_identify.py 程序的配置,将如下配置改成自己的。
database_path = 'core/save_face_database' vector_database = get_all_basedata(database_path) dic_info_person = {} dic_info_person['baideng'] = ['拜登'] dic_info_person['telangpu'] = ['特朗普']
1
2
3
4
5
# 2.2.2 测试运行特定人物识别的服务
安装好依赖之后,先启动 server.py 服务,再执行 server_test.py 即可本地测试。
$ python3 server.py
$ python3 server_test.py
2
测试效果如下:
# 2.3 Docker部署特定人物识别服务
# 2.3.1 编写Dockerfile及部署脚本
Dockerfile
# 基于python3.7镜像创建新镜像
FROM python:3.7
# 创建容器内部目录
RUN mkdir /code
ADD . /code/
WORKDIR /code
# 安装项目依赖
# RUN export https_proxy=http://xxx.xxx.xxx.xxx:xxx # 国内服务器建议设置代理
RUN apt update && apt install libgl1-mesa-glx -y
RUN pip install torch==1.10.0+cpu torchvision==0.11.1+cpu torchaudio==0.10.0+cpu -f https://download.pytorch.org/whl/cpu/torch_stable.html
RUN wget https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow_cpu-2.6.0-cp37-cp37m-manylinux2010_x86_64.whl
RUN pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow_cpu-2.6.0-cp37-cp37m-manylinux2010_x86_64.whl
RUN rm -f tensorflow_cpu-2.6.0-cp37-cp37m-manylinux2010_x86_64.whl
RUN pip install Flask==2.0.2
RUN pip install Flask_Cors==3.0.10
RUN pip install pre_request==2.1.5
RUN pip install opencv_python==4.4.0.46
RUN pip install numpy==1.19.5
RUN pip install scikit_learn==1.0.2
# 放行端口
EXPOSE 5007
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
install.sh
#!/bin/bash
docker build -t face_identify_image .
docker run -itd -p 5007:5007 --name face_identify -e TZ="Asia/Shanghai" face_identify_image:latest
2
3
# 2.3.2 服务器上使用Docker部署服务
服务器环境:Debian 11 x86_64 系统,8GB内存,160GB存储,2x Intel Xeon CPU,无GPU,带宽1 Gigabit,Docker version 20.10.17
部署测试:将整个项目上传到服务器上,执行 install.sh 安装脚本,部署成功后改一下 server_test.py 的 IP 对其进行功能测试。正式部署使用nohup后台运行。
$ chmod u+x install.sh && ./install.sh
$ docker exec -it face_identify /bin/bash
$ python server.py
2
3
性能指标及资源占用:接口请求速度约2.5s(包含网络请求的损耗),存储占用约4.15GB,内存占用约1.72GB。
$ docker images // 查看镜像的占用空间
$ docker stats --no-stream face_identify // 查看容器的CPU、内存等指标占用率(不带 --no-stream 参数的话可以实时刷新)
2
# 3. Deepface人脸识别和分析
# 3.1 Deepface概述及安装
# 3.1.1 Deepface简介
Deepface是一个用于Python的轻量级面部识别和面部属性分析(年龄,性别,情绪和种族)框架。它是一个混合面部识别框架,包装了最先进的模型:VGG-Face, Google FaceNet, OpenFace, Facebook DeepFace, DeepID, ArcFace, Dlib 和 SFace。实验显示,人类在面部识别任务上的准确率为97.53%,而这些模型已经达到并超过了该准确度水平。
项目地址:https://github.com/serengil/deepface (opens new window)
# 3.1.2 Deepface安装
可以通过pip、conda、源码等方式安装,我这里采用了源码安装的方式,所需的模型会在之后首次运行时自动下载。
// 方式一
$ pip3 install deepface
// 方式二
$ conda install -c conda-forge deepface
// 方式三
$ git clone https://github.com/serengil/deepface.git
$ cd deepface
$ pip3 install -e .
2
3
4
5
6
7
8
9
10
# 3.2 Deepface使用示例
在该项目的 ./tests/dataset
目录下,有很多测试数据,下面的使用示例就使用这些数据。
# 3.2.1 验证人脸是否同一人
这个用来验证面部配对为同一人或不同的人,它需要精确的图像路径作为输入,也支持传递numpy或base64编码的图像。
# -*- coding: utf-8 -*-
from deepface import DeepFace
result = DeepFace.verify(img1_path="tests/dataset/img1.jpg", img2_path="tests/dataset/img2.jpg")
print(result)
>>> 输出结果
{
'verified': True,
'distance': 0.25551901561553336,
'threshold': 0.4,
'model': 'VGG-Face',
'detector_backend': 'opencv',
'similarity_metric': 'cosine',
'facial_areas': {
'img1': {
'x': 345,
'y': 211,
'w': 769,
'h': 769
},
'img2': {
'x': 516,
'y': 192,
'w': 512,
'h': 512
}
},
'time': 2.14
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 3.2.2 面部属性分析
Deepface还配备了强大的面部属性分析模块,包括年龄、性别、面部表情(包括愤怒、恐惧、中立、悲伤、厌恶、快乐和惊讶)以及种族(包括亚洲人,白人,中东人,印度人,拉丁美洲人和黑人)预测。性别模型的准确度为 97.44%,精确度为 96.29%,召回率为 95.05% 。
# -*- coding: utf-8 -*-
from deepface import DeepFace
objs = DeepFace.analyze(img_path="tests/dataset/img4.jpg", actions=['age', 'gender', 'race', 'emotion'])
print(objs)
>>> 输出结果
[
{
'age': 31,
'region': {
'x': 419,
'y': 301,
'w': 919,
'h': 919
},
'face_confidence': 10.600495017308276,
'gender': {
'Woman': 99.99980926513672,
'Man': 0.0001894966089821537
},
'dominant_gender': 'Woman',
'race': {
'asian': 0.05465123616591261,
'indian': 0.08727372165672818,
'black': 0.0038303477576379545,
'white': 91.42375690653837,
'middleeastern': 5.098592254687279,
'latinohispanic': 3.3318944028741835
},
'dominant_race': 'white',
'emotion': {
'angry': 0.0634299241937697,
'disgust': 2.502598874798423e-05,
'fear': 0.16904905205592513,
'happy': 92.4351155757904,
'sad': 0.4689138848334551,
'surprise': 0.23647076450288296,
'neutral': 6.626990437507629
},
'dominant_emotion': 'happy'
}
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 4. 参考资料
[1] 人脸算法系列(二):RetinaFace论文精读 from 腾讯云 (opens new window)
[2] Retinaface论文翻译及理解 from 知乎 (opens new window)
[3] 聪明的人脸识别4——Pytorch 利用Retinaface+Facenet搭建人脸识别平台 from CSDN (opens new window)
[4] 人脸检测之Retinaface算法:论文阅读及源码解析 from CSDN (opens new window)
[5] 从零开始学人脸检测之Retinaface篇(内含魔改版GhostNet+mbv2)from 知乎 (opens new window)
[6] 人脸检测:RetinaFace from CodeAntenna (opens new window)
[7] RetinaFace人脸检测简要介绍 from CSDN (opens new window)
[8] Pytorch-RetinaFace 详解 from 知乎 (opens new window)
[9] 人脸检测算法(一)from 知乎 (opens new window)
[10] 人脸检测算法综述 from 知乎 (opens new window)
[11] InsightFace力作:RetinaFace单阶段人脸检测器 from giantpandacv (opens new window)
[12] 适合ARM 的轻量级人脸检测算法汇总 from CSDN (opens new window)
[13] 如何应用 MTCNN 和 FaceNet 模型实现人脸检测及识别 from InfoQ (opens new window)
[14] 谷歌人脸识别系统FaceNet解析 from 知乎 (opens new window)
[15] 利用MTCNN和facenet实现人脸检测和人脸识别 from CSDN (opens new window)
[16] FaceNet源码解读:史上最全的FaceNet源码使用方法和讲解(一)(附预训练模型下载) from CSDN (opens new window)
[17] 新版本tensorflow无法使用GPUoptions from CSDN (opens new window)
[18] 关于出现Object arrays cannot be loaded when allow_pickle=False报错的解决方法 from CSDN (opens new window)
[19] “属性错误:'int'对象没有属性'值'”是什么意思?你如何修复它(python、tensorflow、tensorflow2.0、开发)from Quora (opens new window)
[20] import tensorflow.compat.v1 as tf报错,无compat module解决办法 from CSDN (opens new window)