用FaceNet的模型計算人臉之間距離(TensorFlow)
引
2015年Google的研究人員發表了一篇論文:FaceNet: A Unified Embedding for Face Recognition and Clustering,是關於人臉識別的,他們訓練一個網路來得到人臉的128維特徵向量,從而通過計算特徵向量之間的歐氏距離來得到人臉相似程度。在LFW上面取得了當時最好的成績,識別率為99.63%。
傳統的基於CNN的人臉識別方法為:利用CNN的siamese網路來提取人臉特徵,然後利用SVM等方法進行分類。而這篇文章中他們提出了一個方法系統叫作FaceNet,它直接學習影象到歐式空間上點的對映,其中呢,兩張影象所對應的特徵的歐式空間上的點的距離直接對應著兩個影象是否相似。
如上圖所示,直接得出不同人臉圖片之間的距離,通過距離就可以判斷是否是同一個人,閾值大概在1.1左右。
而現在我要做的,就是用訓練好的模型檔案,實現任意兩張人臉圖片,計算其FaceNet距離。然後就可以將這個距離用來做其他的事情了。
環境
- macOS 10.12.6
- Python 3.6.3
- TensorFlow 1.3.0
實現
模型檔案
首先我們需要訓練好的模型檔案,這個可以在FaceNet官方的github中獲取:
注意他們是存放在Google雲盤中的,需要翻牆獲取(沒個翻牆能力連科研都做不好了。。)
程式碼
這裡我們需要FaceNet官方的github
程式碼如下:
# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np
import scipy.misc
import cv2
import facenet
image_size = 200 #don't need equal to real image size, but this value should not small than this
modeldir = './model_check_point/20170512-110547.pb' #change to your model dir
image_name1 = 'x.jpg' #change to your image name
image_name2 = 'y.jpg' #change to your image name
print('建立facenet embedding模型')
tf.Graph().as_default()
sess = tf.Session()
facenet.load_model(modeldir)
images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0")
embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0")
phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0")
embedding_size = embeddings.get_shape()[1]
print('facenet embedding模型建立完畢')
scaled_reshape = []
image1 = scipy.misc.imread(image_name1, mode='RGB')
image1 = cv2.resize(image1, (image_size, image_size), interpolation=cv2.INTER_CUBIC)
image1 = facenet.prewhiten(image1)
scaled_reshape.append(image1.reshape(-1,image_size,image_size,3))
emb_array1 = np.zeros((1, embedding_size))
emb_array1[0, :] = sess.run(embeddings, feed_dict={images_placeholder: scaled_reshape[0], phase_train_placeholder: False })[0]
image2 = scipy.misc.imread(image_name2, mode='RGB')
image2 = cv2.resize(image2, (image_size, image_size), interpolation=cv2.INTER_CUBIC)
image2 = facenet.prewhiten(image2)
scaled_reshape.append(image2.reshape(-1,image_size,image_size,3))
emb_array2 = np.zeros((1, embedding_size))
emb_array2[0, :] = sess.run(embeddings, feed_dict={images_placeholder: scaled_reshape[1], phase_train_placeholder: False })[0]
dist = np.sqrt(np.sum(np.square(emb_array1[0]-emb_array2[0])))
print("128維特徵向量的歐氏距離:%f "%dist)
程式碼的邏輯就是
1. 先匯入模型引數
2. 然後匯入兩張圖片,分別獲取其經過模型後得到的128維特徵向量
3. 最後計算兩個向量的歐氏距離
程式碼中有幾個引數:
* image_size:圖片長寬尺寸,這裡要求輸入的圖片是長寬相等的,但是不要求兩張人臉圖大小一致,這裡設定的尺寸是程式碼中會將人臉圖讀取後重新拉伸壓縮成這個大小,這個尺寸最好比200大,太小了會執行失敗
* modeldir:預訓練好的模型路徑
* image_name1:第一張人臉圖的圖片名
* image_name2:第二張人臉圖的圖片名
實驗
給兩個不同人的人臉圖片,得到的結果如下:
如果比較兩個相同的人臉圖片,得到的距離會是零點幾;如果是兩張一樣的圖,得到的距離會是0,符合要求。