TensorFlow+FaceNet+训练模型
1、目录结构介绍
1.1、faceNet简介
FaceNet是Google提出的用于人脸识别(recognition,k-NN),验证(verification, two persons),聚类(clustering, find common people among these faces)。与用于分类的神经网络(MobileNet、GoogleNet、VGG16/19、ResNet等)不同的是FaceNet选择了一种更直接的端到端的学习和分类方式,同时生成更少的参数量。

输入 Batch,有一个提取特征的深度神经网络(论文中用的是ZF-Net和Inceptio),然后对网络提取到的特征做 L2-normalization,之后通过embedding编码生成128d的向量,优化三元组损失函数得到最优模型。

总体流程:
- 一组图像通过分类模型(如论文中提到的ZFNet、Inception V1)提取特征。
- 将提取到的特征进行L2 normalize,得到embedding结果(即一张图片使用128维向量表示)
- 将得到的embedding结果作为输入,计算triplet loss。
- l2 normalize.参考tf.nn.l2_normalize方法的实现。
- output = x / sqrt(max(sum(x**2), epsilon))
漏了一个文件件介绍就是models,这个文件夹下面放的是facent采用的CNN卷积中不同网络结构的不同实现代码比如Inception-ResNet-v1.

2、模型准备
2.1、下载FaceNet源码
下载地址:facenet源码
-
Triplet loss training
目标:使用 Triplet loss 训练模型。
步骤: -
安装 TensorFlow。
-
下载 davidsandberg/facenet 并设置 Python Paths。
-
准备训练数据,包括下载数据、Face alignment(使用 align_dataset_mtcnn.py)。
-
使用 train_tripletloss.py 训练。
-
在 TensorBoard 上查看训练过程。
- MTCNN部分:用于人脸检测和人脸对齐,输出160×160大小的图像;
- CNN部分:可以直接将人脸图像(默认输入是160×160)映射到欧几里得空间,空间距离的长度代表了人脸图像的相似性。只要该映射空间生成、人脸识别,验证和聚类等任务就可以轻松完成;
2.2、下载预训练模型
facenet提供了两个预训练模型,分别是基于CASIA-WebFace和MS-Celeb-1M人脸库训练的,不过需要去谷歌网盘下载,这里给其中一个模型的百度网盘的链接:链接百度网盘地址密码: 12mh

- model.meta:模型文件,该文件保存了metagraph信息,即计算图的结构;
- model.ckpt.data:权重文件,该文件保存了graph中所有遍历的数据;
- model.ckpt.index:该文件保存了如何将meta和data匹配起来的信息;
- pb文件:将模型文件和权重文件整合合并为一个文件,主要用途是便于发布,详细内容可以参考博客https://blog.csdn.net/yjl9122/article/details/78341689
- 一般情况下还会有个checkpoint文件,用于保存文件的绝对路径,告诉TF最新的检查点文件(也就是上图中后三个文件)是哪个,保存在哪里,在使用tf.train.latest_checkpoint加载的时候要用到这个信息,但是如果改变或者删除了文件中保存的路径,那么加载的时候会出错,找不到文件;
配置环境法1
将facebet文件夹加到python引入库的默认搜索路径中,将facenet文件整个复制到anaconda3安装文件目录下lib\site-packages下:

然后把剪切src目录下的文件,然后删除facenet下的所有文件,粘贴src目录下的文件到facenet下,这样做的目的是为了导入src目录下的包(这样import align.detect_face不会报错)。
在Anaconda Prompt中运行python,输入import facenet,不报错即可:

https://blog.csdn.net/xingwei_09/article/details/79161931
https://www.cnblogs.com/zyly/p/9703614.html
2.3、数据预处理(align_dataset_mtcnn.py)
MTCNN的实现主要在文件夹src/align中,文件夹的内容如下:

- detect_face.py:定义了MTCNN的模型结构,由P-Net、R-Net、O-Net组成,这三个网络已经提供了预训练的模型,模型数据分别对应文件det1.npy、det2.npy、det3.npy。
- align_dataset_matcnn.py:是使用MTCNN的模型进行人脸检测和对齐的入口代码
使用脚本align_dataset_mtcnn.py对LFW数据库进行人脸检测和对齐的方法通过在jupyter notebook中运行如下代码:
run src/align/align_dataset_mtcnn.py \
datasets/lfw/raw \
datasets/lfw/lfw_mtcnnpy_160 \
--image_size 160 --margin 32 \
--random_order
如果是在anaconda prompt中运行,将run改为python。
该命令会创建一个datasets/lfw/lfw_mtcnnpy_160的文件夹,并将所有对齐好的人脸图像存放到这个文件夹中,数据的结构和原先的datasets/lfw/raw一样。参数–image_size 160 --margin 32的含义是在MTCNN检测得到的人脸框的基础上缩小32像素(训练时使用的数据偏大),并缩放到160×160大小,因此最后得到的对齐后的图像都是160×160像素的,这样的话,就成功地从原始图像中检测并对齐了人脸。
"""Performs face alignment and stores face thumbnails in the output directory."""
# MIT License
#
# Copyright (c) 2016 David Sandberg
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from scipy import misc
import sys
import os
import argparse
import tensorflow as tf
import numpy as np
import facenet
import align.detect_face
import random
from time import sleep
#args:参数,关键字参数
def main(args):
sleep(random.random())
#设置对齐后的人脸图像存放的路径
output_dir = os.path.expanduser(args.output_dir)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
# Store some git revision info in a text file in the log directory保存一些配置参数等信息
src_path, _ = os.path.split(os.path.realpath(__file__))
facenet.store_revision_info(src_path, output_dir, ' '.join(sys.argv))
#获取lfw数据集 获取每个类别名称以及该类别下所有图片的绝对路径
dataset = facenet.get_dataset(args.input_dir)
print('Creating networks and loading parameters')
#建立MTCNN网络,并预训练(即使用训练好的网络初始化参数)
with tf.Graph().as_default():
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=args.gpu_memory_fraction)
sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, log_device_placement=False))
with sess.as_default():
pnet, rnet, onet = align.detect_face.create_mtcnn(sess, None)
minsize = 20 # minimum size of face
threshold = [0.6, 0.7, 0.7] # three steps's threshold
factor = 0.709 # scale factor
# Add a random key to the filename to allow alignment using multiple processes
random_key = np.random.randint(0, high=99999)
bounding_boxes_filename = os.path.join(output_dir, 'bounding_boxes_%05d.txt' % random_key)
#每个图片中人脸所在的边界框写入记录文件中
with open(bounding_boxes_filename, "w") as text_file:
nrof_images_total = 0
nrof_successfully_aligned = 0
if args.random_order:
random.shuffle(dataset)
#获取每一个人,以及对应的所有图片的绝对路径
for cls in datase
#每一个人对应的输出文件夹
output_class_dir = os.path.join(output_dir, cls.name)
if not os.path.exists(output_class_dir):
os.makedirs(output_class_dir)
if args.random_order:
random.shuffle(cls.image_paths)
#遍历每一张图片
for image_path in cls.image_paths:
nrof_images_total += 1
filename = os.path.splitext(os.path.split(image_path)[1])[0]
output_filename = os.path.join(output_class_dir, filename + '.png')
print(image_path)
if not os.path.exists(output_filename):
try:
img = misc.imread(image_path)
except (IOError, ValueError, IndexError) as e:
errorMessage = '{}: {}'.format(image_path, e)
print(errorMessage)
else:
if img.ndim < 2:
print('Unable to align "%s"' % image_path)
text_file.write('%s\n' % (output_filename))
continue
if img.ndim == 2:
img = facenet.to_rgb(img)
img = img[:, :, 0:3]
#人脸检测,bounding_boxes表示边界框,形状为[n,5],5对应x1,y1,x2,y2,score
#人脸关键点坐标形状为[n,10],左右眼、鼻子、左右嘴角五个位置,每个位置对应一个x和y所以有10个参数
bounding_boxes, _ = align.detect_face.detect_face(img, minsize, pnet, rnet, onet, threshold, factor)
#边界框个数
nrof_faces = bounding_boxes.shape[0]
if nrof_faces > 0:
#【n,4】人脸框
det = bounding_boxes[:, 0:4]
img_size = np.asarray(img.shape)[0:2]
if nrof_faces > 1:
#一张图片中检测多个人脸
bounding_box_size = (det[:, 2] - det[:, 0]) * (det[:, 3] - det[:, 1])
img_center = img_size / 2
offsets = np.vstack([(det[:, 0] + det[:, 2]) / 2 - img_center[1], (det[:, 1] + det[:, 3]) / 2 - img_center[0]])
offset_dist_squared = np.sum(np.power(offsets, 2.0), 0)
index = np.argmax(bounding_box_size - offset_dist_squared * 2.0) # some extra weight on the centering
det = det[index, :]
det = np.squeeze(det)
bb = np.zeros(4, dtype=np.int32)
#边界框缩小margin区域,并进行裁切后缩放到统一尺寸
bb[0] = np.maximum(det[0] - args.margin / 2, 0)
bb[1] = np.maximum(det[1] - args.margin / 2, 0)
bb[2] = np.minimum(det[2] + args.margin / 2, img_size[1])
bb[3] = np.minimum(det[3] + args.margin / 2, img_size[0])
#print(bb)
cropped = img[bb[1]:bb[3], bb[0]:bb[2], :]
scaled = misc.imresize(cropped, (args.image_size, args.image_size), interp='bilinear')
nrof_successfully_aligned += 1
misc.imsave(output_filename, scaled)
text_file.write('%s %d %d %d %d\n' % (output_filename, bb[0], bb[1], bb[2], bb[3]))
else:
print('Unable to align "%s"' % image_path)
text_file.write('%s\n' % (output_filename))
print('Total number of images: %d' % nrof_images_total)
print('Number of successfully aligned images: %d' % nrof_successfully_aligned)
def parse_arguments(argv):
#解析命令行参数
parser = argparse.ArgumentParser()
#定义参数 input_dir、output_dir为外部参数名
parser.add_argument('input_dir', type=str, help='Directory with unaligned images.')
parser.add_argument('output_dir', type=str, help='Directory with aligned face thumbnails.')
parser.add_argument('--image_size', type=int,
help='Image size (height, width) in pixels.', default=182)
parser.add_argument('--margin', type=int,
help='Margin for the crop around the bounding box (height, width) in pixels.', default=44)
parser.add_argument('--random_order',
help='Shuffles the order of images to enable alignment using multiple processes.', action='store_true')
parser.add_argument('--gpu_memory_fraction', type=float,
help='Upper bound on the amount of GPU memory that will be used by the process.', default=1.0)
#解析
return parser.parse_args(argv)
if __name__ == '__main__':
main(parse_arguments(sys.argv[1:]))
调用align.detect_face.detect_face()函数进行人脸检测,返回校准后的人脸边界框的位置、score、以及关键点坐标;
对人脸框进行处理,从原图中裁切(先进行了边缘扩展32个像素)、以及缩放(缩放到160×160 )等,并保存相关信息到文件
def detect_face(img, minsize, pnet, rnet, onet, threshold, factor):
# im: input image
# minsize: minimum of faces' size
# pnet, rnet, onet: caffemodel
# threshold: threshold=[th1 th2 th3], th1-3 are three steps's threshold
# fastresize: resize img from last scale (using in high-resolution images) if fastresize==true
factor_count=0
total_boxes=np.empty((0,9))
points=[]
h=img.shape[0]
w=img.shape[1]
#最小值 假设是250x250
minl=np.amin([h, w])
#假设最小人脸 minsize=20,由于我们P-Net人脸检测窗口大小为12x12,
#因此必须缩放才能使得检测窗口检测到完整的人脸 m=0.6
m=12.0/minsize
minl=minl*m
# creat scale pyramid不同尺度金字塔,保存每个尺度缩放尺度系数0.6 0.6*0.7 ...
scales=[]
while minl>=12:
scales += [m*np.power(factor, factor_count)]
minl = minl*factor
factor_count += 1
# first stage
for j in range(len(scales)):
#缩放图像
scale=scales[j]
hs=int(np.ceil(h*scale))
ws=int(np.ceil(w*scale))
#归一化【-1,1】之间
im_data = imresample(img, (hs, ws))
im_data = (im_data-127.5)*0.0078125
img_x = np.expand_dims(im_data, 0)
img_y = np.transpose(img_x, (0,2,1,3))
out = pnet(img_y)
out0 = np.transpo

本文介绍了FaceNet的原理及其在人脸识别中的应用,包括模型结构、数据预处理、模型训练和比对程序的运行。通过使用MTCNN进行人脸检测和对齐,然后使用TensorFlow和FaceNet进行特征提取和比对。文章还提供了预训练模型的下载和训练新模型的步骤。
最低0.47元/天 解锁文章
766

被折叠的 条评论
为什么被折叠?



