Fork me on GitHub

FeceNet模型学习

问题引入

原来的做法:提取图片特征,建立特征之间相互关联的模型,然后利用SVM进行分类判断(例如:有四个轮子的方形物体就是汽车,有翅膀的就是鸟)。这种分类器一来类别比较少,通过不同特征之间的组合就能确定;二来不同类别的特征之间差距较大(例如:人就不可能有轮子)
做人脸识别时,不同的人就是一个类别,而且每个人都有鼻子、眼睛、耳朵等,它的区别仅仅在于眼睛大还是小,鼻子高还是低,当然这都是特征,但是属于更深层次的特征。
所以,如果这里仍然使用CIFAR10那样的模型,是否还能够较好的识别一张图里面的人是谁呢?所以这里是要进行人脸识别的。

论文模型的理论依据:对于人脸特征距离而言,相同个体的差距总是小于不同个体
解决方法:提取两张图片之间的特征,计算特征之间的欧氏距离,小于距离阈值即为同一个体


论文关键点

损失函数:并不是传统的softmax,而是triplet loss
三元组(Anchor,Negative,Positive):Anchor表示当前图像,Negative表示和当前图像不同类的图像,Positive表示和当前图像同一类的图像
目标:减小Anchor与Positive之间的距离,增大Anchor与Negative之间的距离

triplet loss:以下是损失函数,其中α是一个常量,表示Positive/Negative的边界;

损失函数分析

参数α

当参数 α 值越小时,loss 也就较容易的趋近于 0,于是 Anchor 与 Positive 不需要拉的太近,Anchor 与 Negative 不需要拉的太远,就能使得 loss 很快趋近于 0。这样训练得到的结果,不能够很好的区分相似的图像。
当参数 α 值越大时,就需要使得网络参数要拼命地拉近 Anchor、Positive 之间的距离,拉远 Anchor、Negative 之间的距离。但如果参数 α 值设置的太大,很可能最后 loss 保持一个较大的值,难以趋近于0。
简而言之,参数 α 值设置的越小,loss 很容易趋近于 0 ,但很难区分相似的图像。margin 值设置的越大,loss 值较难趋近于 0,甚至导致网络不收敛,但可以较有把握的区分较为相似的图像。因此,设置一个合理的参数 α 值很关键,这是衡量相似度的重要指标。

三元组

损失函数涉及到一个完整的三元组,这个三元组的选择至关重要。
理论上来说应该选择距离最远的Positive、距离最近的Negative去进行训练,在训练中使得Positive不断逼近,Negative不断拉远,但是这样会造成局部极值(不是很能理解),导致网络无法收敛至最优。解决方法是:

(1)对于Positive,在mini-batch中挑选所有的 anchor-positive 图像对,这样可以使得训练的过程更加稳固。???
(2)对于Negative,采用 semi-hard 约束,也就是距离大于 ||Anchor-Positive|| 的Negative。

具体实施:在单个个体中选择40张图片作为正样本Positive,随机筛选其他人脸图片作为负样本,负样本要求 ||Anchor-Negative||>||Anchor-Positive||。


Facenet Structure


以上就是论文FaceNet模型的结构,稍微解释一下:
Batch:是指输入的人脸图像样本,这里的样本是已经经过人脸检测找到人脸并裁剪到固定尺寸(例如160x160)的图片样本,比如通过MTCNN处理的。
Deep Architecture:指的是采用一种深入学习架构,例如imagenet历年冠军网络中的ZF,googlenet等,也就是说这里的模型结构是用的已有的比较优秀的,你也可以根据自己需求选择其他模型。
L2 :是指特征归一化(使其特征的 ||f(x)||2 = 1,这里是2次方的意思,这样所有图像的特征都会被映射到一个超球面上)
Embeddings:就是前面经过深度学习网络,L2归一化后生成的特征向量(这个特征向量就代表了输入的一张样本图片)。
Triplet Loss: 这里就是模型的损失函数,从它的计算公式可以看出,它需要三个样本作为输入(之前的都是DoubleSample或者是SingleSample)。


研究内容:影响人脸识别精度的因素

这相当于是一个对比试验,控制几个主要的变量,来研究每个变量对人脸识别精度的影响。
(1)CNN网络:两种,GoogLeNet,Zeiler&Fergus architecture。
(2)训练集大小:当然是越大越好。
(3)特征维度大小:对比了64/128/256/512四种不同维度,最终确定128维精度最好。
(4)图片质量好坏:图片质量越高结果越好。
最终的结果是,该模型在LFW数据集上能够取得98%以上的识别精度;如果前期的人脸检测效果很好,最后的人脸识别精度甚至可以达到99.5%以上。


应用

人脸识别(这个人是谁?)
人脸验证(两个图是否是一个人?)
人脸聚类(查找相似人群?)

代码解析


上述图片是模型源码文件,实际上需要的内容在src文件夹中已经囊括了,但是红色下划线的部分也是需要关注的,包括src/align中的内容。

compare.py

比较两个图像的相似度,需要输入三个参数:模型路径,图像1路径,图像2路径
其中模型是训练好的,在models/facenet文件夹中有;如果没有,可以去GitHub上面下载(需要翻墙),GitHub目前给出的两个模型都是最新的训练好的,选任意一个都可以;或者在百度网盘下载(密码:4dcn)。
输入:

输出:

align_dataset_mtcnn.py

人脸对齐程序,这里要用到数据集LFW;服务器上已经下载好了,在 datasets/lfw;
运行时需要输入三个参数:输入图像文件夹,输出图像文件夹,指定裁剪后图片大小;
之所以需要裁剪是因为这里采用的是GoogLeNet模型,该模型要求输入图像规格是160*160,而LFW数据集的格式是250*250,所以需要进行预处理;
还有,运行时需要导入 src/facenet.py 模块,而这部分脚本在align_dataset_mtcnn.py中有写,只是import方式有误,直接运行会报错“No model named src”,需要改成如下形式:

输入:

输出:

train_tripletloss.py

训练数据,仍然需要用到上面下载的LFW数据集,这里需要对脚本做两处修改
一是LFW数据集路径的修改
二是 data/pairs.txt 路径的修改
输入:python train_tripletloss.py
输出:

cluster.py实现人脸聚类

使用mtcnn进行人脸检测并对齐剪裁
使用facenet进行embedding(映射)
对embedding的特征向量使用欧氏距离进行聚

predict.py人脸识别,判断输入图像是谁

使用mtcnn进行人脸检测并对齐剪裁
使用facenet进行embedding(映射)
执行predict.py进行人脸识别(需要训练好的SVM模型)

inception_resnet_v1.py

定义了GoogLeNet_v1的结构,主要包括3个block、2个reduction
在该网络中,block被当做一个块,循环利用;reduction则用来合并特征,可以看做全连接层

lfw.py

定义了处理LFW数据的方式

-------------本文结束感谢您的阅读-------------
ChengQian wechat
有问题可以通过微信一起讨论!