这是对:史上最全的FaceNet源码使用方法和讲解(一)(附预训练模型下载)的一个补充。
用到的函数:validate_on_lfw.py
在pycharm中配置的参数如下:
数据集所在路径 模型所在路径
示例:
20170512-110547 1.png 2.png
这将执行以下四个操作:
a)加载模型。
b)加载和解析文本文件与图像对。
c)计算所有图像(以及它们的水平翻转版本)在测试集中的向量。
d)计算精度,验证率(@ FAR = -10e-3),曲线下面积(AUC)和等误差率(EER)等性能指标。
典型的输出如下:
Model directory: /home/david/models/20180402-114759/
Metagraph file: model-20180402-114759.meta
Checkpoint file: model-20180402-114759.ckpt-275
Runnning forward pass on LFW images
........................
Accuracy: 0.99650+-0.00252
Validation rate: 0.98367+-0.00948 @ FAR=0.00100
Area Under Curve (AUC): 1.000
Equal Error Rate (EER): 0.004
有时候,我们需要用自己的数据集对预训练好的模型进行重新训练,或者之前训练了一个模型之后,觉得训练轮数不够,又不想从头开始训练,这样,在训练之前就要把之前训练的模型重新加载进去,方式如下:
######第一步:添加预训练模型的参数:
在中train_tripletloss.py
找到这样一个语句:
改成这样:
parser.add_argument('--pretrained_model', type=str,
help='Load a pretrained model before training starts.',default='模型所在路径')
如果只是完成了第一步,运行程序会报错。经过调试,是因为程序有一个小的bug需要修复:
找到这一行程序:
可以看出,这一处函数的作用是:如果预训练模型这个参数非空,那么用tensorflow的saver.restore()函数重新加载模型参数,但是此处会报错,
那么我们模仿compare.py
函数中的加载模型方法,将这个函数改为:
facenet.load_model(args.pretrained_model)
然后运行程序,发现程序已经可以正常执行了。
如果不放心,可以取一个已经训练好的模型,加载之后训练一轮,会发现初始的损失函数非常小,同时,训练一轮之后模型的准确率已经和加载的预训练模型准确率差不多了,说明模型加载成功。
可能希望自动对您的私人照片集进行分类。或者您有一个安全摄像头,您想要自动识别您的家庭成员。那么您可能希望在自己的数据集上训练分类器。在这种情况下,classifier.py程序也可以用于此。
1)构建自己的数据集。 在该示例中,每个类的5个第一图像用于训练,接下来的5个图像用于测试。
比如说,你有9个需要分类的人(这里暂时用F1-F9表示),其中你有每个人各20张照片
使用的类是:
F1
F2
F3
F4
F5
F6
F7
F8
F9
训练集的目录组织方式:
my_dataset/test
├── F1
│ ├── F1_0.png
│ ├── F1_1.png
│ ├── F1_2.png
│ ├── F1_3.png
│ ├── F1_3.png
…… ……
│ └── F1_19.png
├── F2
│ ├── F2_0.png
│ ├── F2_1.png
│ ├── F2_2.png
│ ├── F2_3.png
│ ├── F2_3.png
│ …… ……
│ └── F2_19.png
├── F3
│ ├── F3_0.png
│ ├── F3_1.png
…… …… ……
…
…
测试集的目录组织方式类似。
2)训练。 用到的代码:calssifier.py
。这一步是在你已经训练好了一个FaceNet模型(或者使用网上提供的模型),需要用这个模型计算出的自己照片的特征向量来训练一个SVM分类器的场景,这个程序的基本原理是:通过用图像算出来的向量数据来训练一个SVM分类器,从而对人的身份进行一个判断,同时在.pkl格式的文件中存储每一个分类。这也是作者对于FaceNet程序应用的一个探索。
这个函数有两个模式,一个模式用来训练,另一个模式用来测试。具体功能如下:
模式= TRAIN:
模式= CLASSIFY:
执行本代码需要添加的参数以及各参数的含义:
配置参数示例:
TRAIN 图片数据所在文件夹 模型文件夹 标签文件.pkl
运行结果:
Number of classes: 9
Number of images: 180
Loading feature extraction model
Model directory: 20180606
Metagraph file: model-20180606-232113.meta
Checkpoint file: model-20180606-232113.ckpt-120120
Calculating features for images
Training classifier
Saved classifier model to file "E:/facenet/pick/classifier.pkl"
测试:
CLASSIFY 图片数据所在文件夹 模型文件夹 标签文件保存地址.pkl
运行结果:
Number of classes: 9
Number of images: 20
Loading feature extraction model
Model directory: 20180606
Metagraph file: model-20180606-232113.meta
Checkpoint file: model-20180606-232113.ckpt-120120
Calculating features for images
Testing classifier
Loaded classifier model from file "E:/facenet/pick/classifier.pkl"
0 F1: 0.471
1 F1: 0.672
2 F1: 0.685
3 F1: 0.700
4 F3: 0.633
5 F1: 0.556
6 F1: 0.555
7 F1: 0.696
8 F2: 0.827
9 F2: 0.775
…… ……
如果不需要在每次执行的过程中都配置这几个参数,可以对程序进行微调,找到原程序中的这几行代码:
改动如下(即将初始值配置在程序中,避免每次执行程序时都要输入对应的参数。如果参数有改动,只需要更改程序对应部位即可。):
parser.add_argument('--mode', type=str, choices=['TRAIN', 'CLASSIFY'],
help='Indicates if a new classifier should be trained or a classification ' +
'model should be used for classification', default='CLASSIFY')#这里更改模式
parser.add_argument('--data_dir', type=str,
help='Path to the data directory containing aligned LFW face patches.',default='TF1_classify')#添加自己的数据文件夹
parser.add_argument('--model', type=str,
help='Could be either a directory containing the meta_file and ckpt_file or a model protobuf (.pb) file',default='20180606')#预训练模型
parser.add_argument('--classifier_filename',
help='Classifier model file name as a pickle (.pkl) file. ' +
'For training this is the output and for classification this is an input.',default='pick/classifier.pkl')#.pkl文件存储的位置
原程序默认使用CPU训练,但是这样训练的速度太慢,如果你电脑恰好有一块不错的GPU,或者实验室里有GPU服务器,那么配置好GPU环境之后(包括cuda,TensorFlow-gpu等),可以在程序中添加代码如下:
import OS
os.environ["CUDA_VISIBLE_DEVICES"] = '0'#如果有多块显卡,可以指定第几块显卡,0即为第一块显卡。
这样,程序在执行过程中就优先调用GPU训练模型了。
在《In Defense of the Triplet Loss for Person Re-Identification》这篇论文中提到:损失函数中去掉平方后效果还会更好一些,如下图:
如果有需要的话,可以改成开方的形式,在facenet.py
下的triplet_loss
函数中,找到如下两句代码:
改成:
pos_dist = tf.sqrt(tf.reduce_sum(tf.square(tf.subtract(anchor, positive)), 1)) # tf.square:平方。tf.subtract::减法
neg_dist = tf.sqrt(tf.reduce_sum(tf.square(tf.subtract(anchor, negative)), 1))
即加上一个开方运算。(目前正在测试效果,以后补充……)
个人知乎主页地址:知乎个人主页。欢迎关注。
找到一个非常好的人脸识别领域的汇总博客,把链接贴在这里:格灵深瞳:人脸识别最新进展以及工业级大规模人脸识别实践探讨 | 公开课笔记