天天看點

基于TensorFlow的Facenet 人臉識别實作說明

1. 開發環境

OS:ubuntu16.04

tensorflow版本:1.12.0

python版本:3.6.8

2. 下載下傳源碼到本地

facenet官方github: https://github.com/davidsandberg/facenet.git 

git clone https://github.com/davidsandberg/facenet.git
           

在requirements.txt檔案看到要安裝相關的依賴庫,自己用pip指令安裝一下就好了

 tensorflow==1.7

scipy

scikit-learn

opencv-python

h5py

matplotlib

Pillow

requests

psutil

配置環境,gedit ~/.bashrc,添加“export PYTHONPATH=$(pwd)/src”,然後source ~/.bashrc,這樣環境就配置完成了。

3.下載下傳LFW資料集

點選網址下載下傳:http://vis-www.cs.umass.edu/lfw/lfw.tgz

cd facenet

,mkdir -p datasets/lfw/raw

,這個指令是在你下載下傳的facenet所在檔案夾下建立

datasets/lfw/raw

這幾個檔案夾,然後将你下載下傳的LFW資料集解壓到

raw

這個檔案夾下。

基于TensorFlow的Facenet 人臉識别實作說明

4.資料預處理

  • 對LFW圖檔預處理

lfw的圖檔原圖尺寸為 250*250,我們要修改圖檔尺寸,使其大小和預訓練模型的圖檔輸入尺寸一緻,即160*160,轉換後的資料集存儲在 facenet/datasets/lfw/raw檔案夾内。

  • LFW人臉資料集對齊

align_dataset_mtcnn.py 會對dataset的圖檔進行人臉檢測,進一步細化人臉圖檔,然後再把人臉圖檔尺寸修改為160×160的尺寸。進入到facenet/src 目錄下,把align_dataset_mtcnn.py 檔案拷貝到src目錄:

cd facenet/src
python ./src/align/align_dataset_mtcnn.py ./datasets/lfw/raw ./datasets/lfw/lfw_mtcnnpy_160 --image_size 160 --margin 32 --random_order --gpu_memory_fraction 0.25
           

列印如下表示成功:

基于TensorFlow的Facenet 人臉識别實作說明

5.結果比對

請檢視

facenet/data/pairs.txt

的資料,比對的人名和編号如下:

A 1 4,表示A的第一張和第四張是一個人。相反另一種表示就是不比對的。

6.遇到的問題

問題一:

ValueError: Input 0 of node Reshape was passed int32 from batch_join:1 incompatible with expected int64.

解決辦法:打開

validate_on_lfw.py

,找到這三個地方,

data_flow_ops.FIFOQueue,labels_placeholder,control_placeholder

,将他們的

tf.int32

全部換成

tf.int64

重新運作即可。

其它問題:在執行的之後有到一兩個問題,但是發現我解壓的

20170512-110547

檔案夾的内容被不明力量的給修改了,你可以檢查一下自己的,然後重新解壓即可。

validate_on_lfw.py流程解析

源代碼如下:

"""Validate a face recognizer on the "Labeled Faces in the Wild" dataset (http://vis-www.cs.umass.edu/lfw/).
Embeddings are calculated using the pairs from http://vis-www.cs.umass.edu/lfw/pairs.txt and the ROC curve
is calculated and plotted. Both the model metagraph and the model parameters need to exist
in the same directory, and the metagraph should have the extension '.meta'.
"""
# 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

import tensorflow as tf
import numpy as np
import argparse
import facenet
import lfw
import os
import sys
from tensorflow.python.ops import data_flow_ops
from sklearn import metrics
from scipy.optimize import brentq
from scipy import interpolate

def main(args):
  
    with tf.Graph().as_default():
      
        with tf.Session() as sess:
            
            # Read the file containing the pairs used for testing
            # 讀入pairs檔案
            pairs = lfw.read_pairs(os.path.expanduser(args.lfw_pairs))

            # Get the paths for the corresponding images
            # 擷取檔案路徑和是否比對的關系對
            paths, actual_issame = lfw.get_paths(os.path.expanduser(args.lfw_dir), pairs)
            
            image_paths_placeholder = tf.placeholder(tf.string, shape=(None,1), name='image_paths')
            labels_placeholder = tf.placeholder(tf.int64, shape=(None,1), name='labels')
            batch_size_placeholder = tf.placeholder(tf.int32, name='batch_size')
            control_placeholder = tf.placeholder(tf.int64, shape=(None,1), name='control')
            phase_train_placeholder = tf.placeholder(tf.bool, name='phase_train')
 
            nrof_preprocess_threads = 4
            image_size = (args.image_size, args.image_size)
            eval_input_queue = data_flow_ops.FIFOQueue(capacity=2000000,
                                        dtypes=[tf.string, tf.int64, tf.int64],
                                        shapes=[(1,), (1,), (1,)],
                                        shared_name=None, name=None)
            eval_enqueue_op = eval_input_queue.enqueue_many([image_paths_placeholder, labels_placeholder, control_placeholder], name='eval_enqueue_op')
            image_batch, label_batch = facenet.create_input_pipeline(eval_input_queue, image_size, nrof_preprocess_threads, batch_size_placeholder)
     
            # Load the model
            # 加載模型
            input_map = {'image_batch': image_batch, 'label_batch': label_batch, 'phase_train': phase_train_placeholder}
            facenet.load_model(args.model, input_map=input_map)

            # Get output tensor
            # 擷取輸入輸出的張量
            embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0")
#              
            coord = tf.train.Coordinator()
            tf.train.start_queue_runners(coord=coord, sess=sess)

            evaluate(sess, eval_enqueue_op, image_paths_placeholder, labels_placeholder, phase_train_placeholder, batch_size_placeholder, control_placeholder,
                embeddings, label_batch, paths, actual_issame, args.lfw_batch_size, args.lfw_nrof_folds, args.distance_metric, args.subtract_mean,
                args.use_flipped_images, args.use_fixed_image_standardization)

              
def evaluate(sess, enqueue_op, image_paths_placeholder, labels_placeholder, phase_train_placeholder, batch_size_placeholder, control_placeholder,
        embeddings, labels, image_paths, actual_issame, batch_size, nrof_folds, distance_metric, subtract_mean, use_flipped_images, use_fixed_image_standardization):
    # Run forward pass to calculate embeddings
    # 使用前向傳播來驗證
    print('Runnning forward pass on LFW images')
    
    # Enqueue one epoch of image paths and labels
    nrof_embeddings = len(actual_issame)*2  # nrof_pairs * nrof_images_per_pair
    nrof_flips = 2 if use_flipped_images else 1
    nrof_images = nrof_embeddings * nrof_flips
    labels_array = np.expand_dims(np.arange(0,nrof_images),1)
    image_paths_array = np.expand_dims(np.repeat(np.array(image_paths),nrof_flips),1)
    control_array = np.zeros_like(labels_array, np.int32)
    if use_fixed_image_standardization:
        control_array += np.ones_like(labels_array)*facenet.FIXED_STANDARDIZATION
    if use_flipped_images:
        # Flip every second image
        control_array += (labels_array % 2)*facenet.FLIP
    sess.run(enqueue_op, {image_paths_placeholder: image_paths_array, labels_placeholder: labels_array, control_placeholder: control_array})
    
    embedding_size = int(embeddings.get_shape()[1])
    assert nrof_images % batch_size == 0, 'The number of LFW images must be an integer multiple of the LFW batch size'
    nrof_batches = nrof_images // batch_size
    emb_array = np.zeros((nrof_images, embedding_size))
    lab_array = np.zeros((nrof_images,))
    for i in range(nrof_batches):
        feed_dict = {phase_train_placeholder:False, batch_size_placeholder:batch_size}
        emb, lab = sess.run([embeddings, labels], feed_dict=feed_dict)
        lab_array[lab] = lab
        emb_array[lab, :] = emb
        if i % 10 == 9:
            print('.', end='')
            sys.stdout.flush()
    print('')
    embeddings = np.zeros((nrof_embeddings, embedding_size*nrof_flips))
    if use_flipped_images:
        # Concatenate embeddings for flipped and non flipped version of the images
        embeddings[:,:embedding_size] = emb_array[0::2,:]
        embeddings[:,embedding_size:] = emb_array[1::2,:]
    else:
        embeddings = emb_array

    assert np.array_equal(lab_array, np.arange(nrof_images))==True, 'Wrong labels used for evaluation, possibly caused by training examples left in the input pipeline'
    # 使用十折交叉驗證計算準确率和驗證率
    tpr, fpr, accuracy, val, val_std, far = lfw.evaluate(embeddings, actual_issame, nrof_folds=nrof_folds, distance_metric=distance_metric, subtract_mean=subtract_mean)
    
    print('Accuracy: %2.5f+-%2.5f' % (np.mean(accuracy), np.std(accuracy)))
    print('Validation rate: %2.5f+-%2.5f @ FAR=%2.5f' % (val, val_std, far))
    
    # 得到auc和等錯誤率eer的值
    auc = metrics.auc(fpr, tpr)
    print('Area Under Curve (AUC): %1.3f' % auc)
    eer = brentq(lambda x: 1. - x - interpolate.interp1d(fpr, tpr)(x), 0., 1.)
    print('Equal Error Rate (EER): %1.3f' % eer)
    
def parse_arguments(argv):
    parser = argparse.ArgumentParser()
    
    parser.add_argument('lfw_dir', type=str,
        help='Path to the data directory containing aligned LFW face patches.')
    parser.add_argument('--lfw_batch_size', type=int,
        help='Number of images to process in a batch in the LFW test set.', default=100)
    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')
    parser.add_argument('--image_size', type=int,
        help='Image size (height, width) in pixels.', default=160)
    parser.add_argument('--lfw_pairs', type=str,
        help='The file containing the pairs to use for validation.', default='data/pairs.txt')
    parser.add_argument('--lfw_nrof_folds', type=int,
        help='Number of folds to use for cross validation. Mainly used for testing.', default=10)
    parser.add_argument('--distance_metric', type=int,
        help='Distance metric  0:euclidian, 1:cosine similarity.', default=0)
    parser.add_argument('--use_flipped_images', 
        help='Concatenates embeddings for the image and its horizontally flipped counterpart.', action='store_true')
    parser.add_argument('--subtract_mean', 
        help='Subtract feature mean before calculating distance.', action='store_true')
    parser.add_argument('--use_fixed_image_standardization', 
        help='Performs fixed standardization of images.', action='store_true')
    return parser.parse_args(argv)

if __name__ == '__main__':
    main(parse_arguments(sys.argv[1:]))
           

問題二:KeyError: "The name 'decode_image/cond_jpeg/is_png' refers to an Operation not in the graph."

解決辦法:2.在facenet.py代碼中找到create_input_pipeline 再添加一行語句 with tf.name_scope("tempscope"):就可以完美解決(貌似Tensorflow 1.10及以上版本才修複這個bug)。

基于TensorFlow的Facenet 人臉識别實作說明

https://github.com/davidsandberg/facenet/issues/852

https://www.twblogs.net/a/5c7bd842bd9eee31cea5e951/zh-cn

6.下載下傳已訓練的模型

選擇20170512-110547這個 model 下載下傳,如果沒辦法越牆可以在處model下載下傳此訓練好的模型。下載下傳後把其解壓到虛拟環境下的任何你喜歡的目錄,比如我的,解壓後存放的路徑為 ./facenet/models/20170512-110547

7.測試模型準确率

python ./src/validate_on_lfw.py ./datasets/lfw/lfw_mtcnnpy_160 ./models/facenet/20170512-110547

結果如下:

2019-07-22 11:20:19.900552: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA

2019-07-22 11:20:20.007808: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:964] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero

2019-07-22 11:20:20.008594: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1432] Found device 0 with properties:

name: GeForce GTX 1080 Ti major: 6 minor: 1 memoryClockRate(GHz): 1.582

pciBusID: 0000:01:00.0

totalMemory: 10.92GiB freeMemory: 10.30GiB

2019-07-22 11:20:20.008611: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1511] Adding visible gpu devices: 0

2019-07-22 11:20:20.211275: I tensorflow/core/common_runtime/gpu/gpu_device.cc:982] Device interconnect StreamExecutor with strength 1 edge matrix:

2019-07-22 11:20:20.211304: I tensorflow/core/common_runtime/gpu/gpu_device.cc:988]      0

2019-07-22 11:20:20.211324: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1001] 0:   N

2019-07-22 11:20:20.211525: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 9959 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1080 Ti, pci bus id: 0000:01:00.0, compute capability: 6.1)

WARNING:tensorflow:From /home/ubuntu/code/mywork/facenet/src/facenet.py:135: batch_join (from tensorflow.python.training.input) is deprecated and will be removed in a future version.

Instructions for updating:

Queue-based input pipelines have been replaced by `tf.data`. Use `tf.data.Dataset.interleave(...).batch(batch_size)` (or `padded_batch(...)` if `dynamic_pad=True`).

WARNING:tensorflow:From /home/ubuntu/anaconda3/lib/python3.6/site-packages/tensorflow/python/training/input.py:734: QueueRunner.__init__ (from tensorflow.python.training.queue_runner_impl) is deprecated and will be removed in a future version.

Instructions for updating:

To construct input pipelines, use the `tf.data` module.

WARNING:tensorflow:From /home/ubuntu/anaconda3/lib/python3.6/site-packages/tensorflow/python/training/input.py:734: add_queue_runner (from tensorflow.python.training.queue_runner_impl) is deprecated and will be removed in a future version.

Instructions for updating:

To construct input pipelines, use the `tf.data` module.

Model directory: ./models/facenet/20170512-110547

Metagraph file: model-20170512-110547.meta

Checkpoint file: model-20170512-110547.ckpt-250000

2019-07-22 11:20:22.297420: W tensorflow/core/graph/graph_constructor.cc:1265] Importing a graph with a lower producer version 21 into an existing graph with producer version 27. Shape inference will have run different parts of the graph with different producer versions.

WARNING:tensorflow:The saved meta_graph is possibly from an older release:

'model_variables' collection should be of type 'byte_list', but instead is of type 'node_list'.

WARNING:tensorflow:From ./src/validate_on_lfw.py:83: start_queue_runners (from tensorflow.python.training.queue_runner_impl) is deprecated and will be removed in a future version.

Instructions for updating:

To construct input pipelines, use the `tf.data` module.

Runnning forward pass on LFW images

............

Accuracy: 0.99183+-0.00320

Validation rate: 0.97467+-0.01477 @ FAR=0.00133

Area Under Curve (AUC): 1.000

Equal Error Rate (EER): 0.007

2019-07-22 11:21:03.284365: W tensorflow/core/kernels/queue_base.cc:285] _4_FIFOQueueV2_1: Skipping cancelled dequeue attempt with queue not closed

2019-07-22 11:21:03.284965: W tensorflow/core/kernels/queue_base.cc:277] _2_input_producer/fraction_of_32_full/fraction_of_32_full: Skipping cancelled enqueue attempt with queue not closed

2019-07-22 11:21:03.285518: W tensorflow/core/kernels/queue_base.cc:285] _4_FIFOQueueV2_1: Skipping cancelled dequeue attempt with queue not closed

2019-07-22 11:21:03.285981: W tensorflow/core/kernels/queue_base.cc:285] _1_FIFOQueueV2: Skipping cancelled dequeue attempt with queue not closed

2019-07-22 11:21:03.285992: W tensorflow/core/kernels/queue_base.cc:285] _1_FIFOQueueV2: Skipping cancelled dequeue attempt with queue not closed

2019-07-22 11:21:03.286087: W tensorflow/core/kernels/queue_base.cc:285] _4_FIFOQueueV2_1: Skipping cancelled dequeue attempt with queue not closed

2019-07-22 11:21:03.286098: W tensorflow/core/kernels/queue_base.cc:285] _4_FIFOQueueV2_1: Skipping cancelled dequeue attempt with queue not closed

2019-07-22 11:21:03.286542: W tensorflow/core/kernels/queue_base.cc:285] _1_FIFOQueueV2: Skipping cancelled dequeue attempt with queue not closed

2019-07-22 11:21:03.286566: W tensorflow/core/kernels/queue_base.cc:285] _1_FIFOQueueV2: Skipping cancelled dequeue attempt with queue not closed

參考網址:

https://blog.csdn.net/sinat_36742186/article/details/84667702

https://blog.csdn.net/niutianzhuang/article/details/79191167

https://github.com/chenlinzhong/face-login

https://blog.csdn.net/chzylucky/article/details/79680986

https://blog.csdn.net/tmosk/article/details/78087122

https://mp.weixin.qq.com/s/1kgbYScIujSjCRvfPGw0tg?

https://blog.csdn.net/hcstar/article/details/79859025

https://blog.csdn.net/cloudox_/article/details/78646063

https://blog.csdn.net/Gavinmiaoc/article/details/80482197

繼續閱讀