使用RetinaFace及FaceNet算法实现特定人物识别

  1. 1. 前言
    1. 1.1 人脸检测与人脸识别
    2. 1.2 RetinaFace人脸检测
    3. 1.3 FaceNet人脸特征提取及匹配
  2. 2. 本地运行RetinaFace人脸检测官方示例
    1. 2.1 本地测试环境
    2. 2.2 RetinaFace人脸检测
  3. 3. 将RetinaFace和FaceNet封装成特定人物识别服务
    1. 3.1 目录结构及使用说明
    2. 3.2 测试运行特定人物识别的服务
  4. 4. Docker部署特定人物识别服务
    1. 4.1 编写Dockerfile及部署脚本
    2. 4.2 服务器上使用Docker部署服务
  5. 5. 参考资料

1. 前言

1.1 人脸检测与人脸识别

人脸检测是对人脸进行识别和处理的第一步,主要用于检测并定位图片中的人脸,返回高精度的人脸框坐标及人脸特征点坐标。人脸识别会进一步提取每个人脸中所蕴涵的身份特征,并将其与已知的人脸进行对比,从而识别每个人脸的身份。目前人脸检测 / 识别的应用场景逐渐从室内演变到室外,从单一限定场景发展到广场、车站、地铁口等场景,人脸检测 / 识别面临的要求也越来越高,比如:人脸尺度多变、数量冗大、姿势多样包括俯拍人脸、戴帽子口罩等的遮挡、表情夸张、化妆伪装、光照条件恶劣、分辨率低甚至连肉眼都较难区分等。随着深度学习的发展,基于深度学习技术的人脸检测 / 识别方法取得了巨大的成功,本文主要介绍人脸检测的深度学习算法 RetinaFace 和人脸识别的深度学习算法 FaceNet。

1.2 RetinaFace人脸检测

Retinaface是Insightface团队在2019年提出的新人脸检测模型,该模型在 WiderFace 数据集上刷新了AP。原模型使用mxnet框架进行搭建,目前社区也有其他框架复现的版本,其中最让人熟知的莫过于Pytorch版的Retinaface。Retinaface是基于检测网络RetinaNet的改进版,添加了SSH网络的三层级联检测模块,提升检测精度。

RetinaFace人脸检测简介

论文原文:https://arxiv.org/pdf/1905.00641.pdf

项目地址1(MXNet实现):https://github.com/deepinsight/insightface/tree/master/RetinaFace

项目地址2(Pytorch实现):https://github.com/biubug6/Pytorch_Retinaface(本文示例使用这个)

预训练模型:https://drive.google.com/open?id=1oZRSG0ZegbVkVwUd8wUIQx8W7yfZ_ki1

1.3 FaceNet人脸特征提取及匹配

Google工程师Florian Schroff,Dmitry Kalenichenko,James Philbin提出了人脸识别FaceNet模型,该模型没有用传统的softmax的方式去进行分类学习,而是抽取其中某一层作为特征,学习一个从图像到欧式空间的编码方法,然后基于这个编码再做人脸识别、人脸验证和人脸聚类等。

FaceNet主要用于验证人脸是否为同一个人,通过人脸识别这个人是谁。FaceNet的主要思想是把人脸图像映射到一个多维空间,通过空间距离表示人脸的相似度。同个人脸图像的空间距离比较小,不同人脸图像的空间距离比较大。这样通过人脸图像的空间映射就可以实现人脸识别,FaceNet中采用基于深度神经网络的图像映射方法和基于triplets(三联子)的loss函数训练神经网络,网络直接输出为128维度的向量空间。

FaceNet的网络结构如下图所示,其中Batch表示人脸的训练数据,接下来是深度卷积神经网络,然后采用L2归一化操作,得到人脸图像的特征表示,最后为三元组(Triplet Loss)的损失函数。

FaceNet人脸识别简介

论文原文:https://arxiv.org/pdf/1503.03832.pdf

项目地址:https://github.com/davidsandberg/facenet

预训练模型:facenet的原作者提供了两个预训练的模型,分别是基于CASIA-WebFace和VGGFace2人脸库训练的。

Model name LFW accuracy Training dataset Architecture
20180408-102900 0.9905 CASIA-WebFace Inception ResNet v1
20180402-114759 0.9965 VGGFace2 Inception ResNet v1

2. 本地运行RetinaFace人脸检测官方示例

2.1 本地测试环境

在本地使用Mac运行测试程序,用CPU运行,使用官方的预训练模型,不自己训练模型了。

  • PC型号及配置:Macbook Pro2021,M1Pro芯片,16GB内存,512GB存储

  • 系统版本:macos Monterey 12.6

2.2 RetinaFace人脸检测

Step1:下载 源码预训练模型(放在 Retinaface_model_v2 目录里)并安装项目依赖,项目结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.
├── 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

Step2:修改一下参数并运行人脸检测程序detect.py

1
2
3
4
5
6
7
8
9
10
11
12
13
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()

程序运行起来后,会用curve目录里的test.jpg作为测试文件,生成效果如下:

测试RetinaFace人脸检测

3. 将RetinaFace和FaceNet封装成特定人物识别服务

3.1 目录结构及使用说明

使用 Flask 将 RetinaFace 和 FaceNet 封装成特定人物识别服务,代码我已在Github上开源,项目地址:https://github.com/Logistic98/face_identify

项目目录结构如下:

1
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
.
├── 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 // 测试服务

使用说明:

  • [1] 运行环境:项目代码里我使用的是CPU运行方式。如果有GPU,可以修改一下配置,将其改成GPU方式运行(需要注意的是,PyTorch 及 Tensorflow 的依赖需要安装对应GPU版本的)。

  • [2] 人脸底库更换:人脸底库放在 save_face_database 目录,制作人脸底库的时候注意只保留人脸,左侧脸30度+右侧脸30度+正脸各2张,更换人脸底库后,需要修改一下 face_identify.py 程序的配置,将如下配置改成自己的。

    1
    2
    3
    4
    5
    database_path = 'core/save_face_database'
    vector_database = get_all_basedata(database_path)
    dic_info_person = {}
    dic_info_person['baideng'] = ['拜登']
    dic_info_person['telangpu'] = ['特朗普']

3.2 测试运行特定人物识别的服务

安装好依赖之后,先启动 server.py 服务,再执行 server_test.py 即可本地测试。

1
2
$ python3 server.py 
$ python3 server_test.py

测试效果如下:

测试运行特定人物识别的服务

4. Docker部署特定人物识别服务

4.1 编写Dockerfile及部署脚本

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 基于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

install.sh

1
2
3
#!/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

4.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后台运行。

1
2
3
$ chmod u+x install.sh && ./install.sh
$ docker exec -it face_identify /bin/bash
$ python server.py

docker打包成功

性能指标及资源占用:接口请求速度约2.5s(包含网络请求的损耗),存储占用约4.15GB,内存占用约1.72GB。

1
2
$ docker images                            // 查看镜像的占用空间
$ docker stats --no-stream face_identify // 查看容器的CPU、内存等指标占用率(不带 --no-stream 参数的话可以实时刷新)

运行算法的系统资源占用

5. 参考资料

[1] 人脸算法系列(二):RetinaFace论文精读 from 腾讯云

[2] Retinaface论文翻译及理解 from 知乎

[3] 聪明的人脸识别4——Pytorch 利用Retinaface+Facenet搭建人脸识别平台 from CSDN

[4] 人脸检测之Retinaface算法:论文阅读及源码解析 from CSDN

[5] 从零开始学人脸检测之Retinaface篇(内含魔改版GhostNet+mbv2)from 知乎

[6] 人脸检测:RetinaFace from CodeAntenna

[7] RetinaFace人脸检测简要介绍 from CSDN

[8] Pytorch-RetinaFace 详解 from 知乎

[9] 人脸检测算法(一)from 知乎

[10] 人脸检测算法综述 from 知乎

[11] InsightFace力作:RetinaFace单阶段人脸检测器 from giantpandacv

[12] 适合ARM 的轻量级人脸检测算法汇总 from CSDN

[13] 如何应用 MTCNN 和 FaceNet 模型实现人脸检测及识别 from InfoQ

[14] 谷歌人脸识别系统FaceNet解析 from 知乎

[15] 利用MTCNN和facenet实现人脸检测和人脸识别 from CSDN

[16] FaceNet源码解读:史上最全的FaceNet源码使用方法和讲解(一)(附预训练模型下载) from CSDN

[17] 新版本tensorflow无法使用GPUoptions from CSDN

[18] 关于出现Object arrays cannot be loaded when allow_pickle=False报错的解决方法 from CSDN

[19] “属性错误:’int’对象没有属性’值’”是什么意思?你如何修复它(python、tensorflow、tensorflow2.0、开发)from Quora

[20] import tensorflow.compat.v1 as tf报错,无compat module解决办法 from CSDN