跑通FaceNet人脸识别

原创:杨其泓

一、前言

FaceNet是一个十分经典的人脸识别模型,并且具有较好的性能,但要实现使用自己的数据进行人脸识别,还需要对模型进行重新训练。本文将介绍跑通一个简单FaceNet的全部流程,以及踩坑记录。

二、方案技术路线

1. 人脸检测:使用 Dlib 中预先训练的模型检测面部;

2. 人脸校准:使用 Dlib 的实时姿势估计与 OpenCV 的仿射变换来尝试使眼睛和下唇在每个图像上出现在相同位置;

3. 卷积网络:使用深度神经网络把人脸图片映射为 128 维单位超球面上的一个点;

4. 分类:使用三元损失函数对每张图片对应的超球面的点(128维向量)比较相似度以此进行分类。

图片来源:https://cmusatyalab.github.io/openface/


三、参考

3.1 论文

FaceNet: A Unified Embedding for Face Recognition and Clustering.

论文链接:https://arxiv.org/abs/1503.03832

3.2 代码

Github代码链接:https://github.com/foamliu/FaceNet

3.3 数据

训练集

CelebFaces Attributes Dataset (CelebA) 是一个大型的人脸数据集,有10,177个身份和202,599张人脸图像。

 数据链接:

http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html

Celeba数据集是香港中文大学的公开数据集,所以支持百度网盘下载!选择Baidu Drive即可将数据集转存至自己的网盘,Celeba数据集大约有22个G(解压后24左右),所以最好要弄个百度网盘SVIP账号再下。

TODO:数据集详细介绍

测试集

LFW (Labled Faces in the Wild)人脸数据集:是目前人脸识别的常用测试集,共有13233张图像,每张图像均给出对应的人名,共有5749人,尺寸为250X250。

数据官网链接:

http://vis-www.cs.umass.edu/lfw/

(官网链接有详细的数据说明及介绍,看不懂数据是啥的可以来看这个)

数据直接下载链接:

http://vis-www.cs.umass.edu/lfw/lfw-funneled.tgz

(直接下载链接是下下来就能用来跑的)

Linux中直接下载:

$ wget http://vis-www.cs.umass.edu/lfw/lfw-funneled.tgz

$ tar -xvf lfw-funneled.tgz

$ wget http://vis-www.cs.umass.edu/lfw/pairs.txt

$ wget http://vis-www.cs.umass.edu/lfw/people.txt

其实执行前两行就行,后两个文件在Github的文件夹中有了已经。

如果是在自己电脑本地下载验证数据集,可以看到它里面分了好几个文件,里面不光有图片,还有好几个label的txt,但是label文件其实在Github上的data里有了,所以其实用到的就是那个图片。

TODO:数据集详细介绍

3.4 模型权重

Dlib人脸校准模型

shape_predictor_5_face_landmarks.dat.bz2链接:

http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2

本项目的人脸检测部分直接使用DLIB来实现,并且通过DLIB的关键点来进行人脸平面对齐,所以需要下载相关模型权重。

FaceNet 人脸识别模型

model.10-0.0156.hdf5链接:

https://github.com/foamliu/FaceNet/releases/download/v1.0/model.10-0.0156.hdf5

这个是作者训练好的一个模型,可以直接用来预测。(模型保存的名称是epoch数-损失,但在后续训练过程中,大家可能会发现在第10个epoch不可能训练到这样的精度,我认为可能是训练中断后重新训练,但是没有调整初始计数造成的)

3.5 配置环境

硬件环境:

系统:Linux

4个RTX2080ti GPU,显存12G(训练使用了俩,只用一个的话会OOM内存溢出)

主要依赖项:

TensorFlow-gpu==1.13.1

Keras==2.2.4

OpenCV-python==4.2.0.32

Dlib==1.19.0

四、代码运行

4.1 前期准备

数据:

将两套数据文件解压后放在data文件夹中,data文件夹如下图所示:

模型:

将两个模型权重放在models文件夹中(因为训练的时候存了很多权重这里就不截图了)。

4.2 数据预处理

进入FaceNet-master/目录,运行:

$ python pre-process.py

这里主要是通过DLIB对Celeba数据进行预处理,包括人脸检测、人脸5特征点检测、人脸对齐等。总共 202,599张人脸图像中,5600张无法被 dlib 标定。因此 202599 - 5600 = 196999 张被用于训练。大约耗时15-20分钟左右。

4.3 模型训练

运行:

$ python train.py

4.4 模型评估

运行:

$ python lfw_eval.py

使用LFW数据集对模型进行验证,输出结果为ROC曲线面积。

五、踩坑记录

5.1 DLIB安装

DLIB可能需要如下前置配置(根据系统差异配置可能有所不同):

X11(xquartz)

Cmake

前置配置安装完成后,一般可用pip install dlib直接安装。

5.2 Keras预训练权重下载

此套代码的核心模型是keras自带的inception_resnet_v2,:

这个代码在执行的时候,会自动去下载这个模型的预训练权重(keras自己公布的几个重点模型的预训练权重),文件大小大约在209M,但是下载会很卡,解决方法是重新下,不停的重新下,或者尝试科学上网,这个在我的mac上极其有效,如果还是下不下来,可以在百度找这个模型权重的文件手动下载,百度上说下载完成后保存在.models文件中(mac或linux中.开头的文件应该是隐藏文件),但是我找了好久都没有找到这个文件夹,后来才发现,他是在我的根目录里!而不是site-packges下面的keras里:

找到位置,下对文件,放进来就ok了。

5.3 get_random_triplets函数

data_generator.py文件中使用了函数get_random_triplets():

但是,在utils.py文件中定义的这个函数并没有输入项,

所以那个括号里的‘train’是多余的,需要删除,要不会报错。

5.4 np.array大计算量报错

我的环境里,最开始keras的版本是2.1.5(好像是,反正是2.1开头的),在进行训练时,报:

StopIteration: ufunc 'true_divide' output (typecode 'd') could not be coerced to provided output parameter (typecode 'B') according to the casting rule ''same_kind''

这个错误的本质是:在对numpy的dnarray数组使用类似+=的运算符时候(比如y+=c),如果数组复杂到一定程度,这样的自加运算就会报如上的错。解决方案就是不使用+=等写法(不使用数学符号的写法),转而使用add等api,但是程序报这个错的具体位置是在keras里,有一行使用了/=,所以这里使用上述修改方法是不稳妥的,毕竟是要改keras源码,一是有大量的此类计算符的话难以处理,二是还要做备份,所以这条路暂时走不通,继而我想到,提高keras版本是否能解决此问题,高本版的keras是否对此进行了优化,结果是,是的,提高版本即可(但要注意keras和TensorFlow的版本匹配关系,不能过高)。

5.5 OOM显存溢出

这个Facenet使用的是keras内部自带的inception_resnet_v2网络,共计5000多万个可训练参数,输入图片大小为139*139,默认batchsize为128,因此训练这个模型的显存占用是极大的,我的显卡是12G显存,实际能用的是10个g多一点,只使用一块卡的话会直接报显存溢出OOM,我还尝试过两块卡,batchsize为256,依然溢出,所以应该视情况对batchsize进行控制,或者考虑换用其他模型(这个其实我一上来就想换过,毕竟是直接走keras调用的,但是由于调用的地方很多以及需要模型指定层的输出,所以还不能随便替换,需要提前去了解一下其他模型的及具体结构)。

5.6 数据缺失

我一开始下载了Celeba数据,就开始尝试进行模型训练了,但是后来报了‘nonetype object has no attribute’,经过判断我发现是image为空,也就是没有读到数据,后来发现:这套github的代码使用了Celeba数据及LFW数据,前者用来训练,候着用来验证及出精确度,但是并不是按常用的方法将训练集拆分成一定比例进行训练、验证,用单独的数据及测试,而是直接调用训练集进行训练,在每个epoch的出验证集损失的时候直接调用LFW数据(可以通过看fit_generator的参数来证明这点),并在进行模型评估的时候只使用LFW数据,这也就意味着,必须同时下好这两套数据才能顺利进行训练。

5.7 Accuracy计算

模型评估代码的最后,会自动打印模型accuracy,我第一反应是常规上理解的accuracy,也就是PP=TP/(TP+FP),然而,这里虽然print写的是accuracy,但实际上计算的是ROC曲线下的面积,也就是AUC。计算关键部位代码如下:

这几个评价指标的区别到底是什么呢?

图片来源:https://www.deeplearn.me/1522.html


如图所示,正确率的计算公式就是TP/(TP+FP);

而ROC曲线是由tpr=TP/(TP+FN)和fpr=FN/(TP+N)计算而来的。

ROC曲线的特性在于:当测试集中的正负样本的分布变化的时候,ROC 曲线能够保持不变。

你可能感兴趣的:(跑通FaceNet人脸识别)