Google在2015年提出透過深度學習的方式處理人臉辨識的系統FaceNet
該論文的連結可參考此處
很快的這個方法就席捲了人臉辨識的應用
許多過去傳統的人臉辨識演算法都不敵FaceNet
在論文中提到,其採用LFW人臉資料庫進行benchmark
並以99.63%的準確率,打破了過去的紀錄
而在YouTubeFaces人臉資料庫也進行了測試
依舊創下高達95.12%的準確率
若是想要研究人臉辨識,一定要認識FaceNet
關於原文版本如果不好閱讀,可參考下面這篇翻譯版
中文翻譯的易讀版
核心的部份這邊就不多談了
簡單說一下FaceNet的運作流程
一般認為深度學習的方式就是透過訓練資料進行學習
訓練好的Model能夠辨識各種不同種類的物件
因此當你input一個圖檔,他能output一個類別名稱給你
例如傳入一張貓的圖片,就會輸出"貓"這個類別出來,如下圖:
那人臉辨識要怎麼運作??
傳入一張周杰倫的照片,就會輸出"周杰倫"這個類別出來嗎?
但深度學習的訓練需要大量的資料以及時間
人臉辨識有辦法做嗎?
每次要增加一個人,是不是要準備大量的照片? 然後還要很長的訓練時間?
上述這樣實在太不合乎使用邏輯了
因此FaceNet的做法並非輸出分類結果
而是輸出量化特徵值,如下圖:
FaceNet的產出就是Embeddings(128或512個特徵值)
(舊版的Pre-Trained Model產生128個特徵值、新版的產生512特徵值)
當你傳入一張周杰倫的照片,FaceNet輸出128個特徵值
當你傳入一張郭富城的照片,FaceNet輸出128個特徵值
只要將兩個結果做歐式距離(Euclidean Distance)的計算
值越小代表這兩張臉越相似,值越大代表差異越大
因此這樣的作法是不是很簡單呢!!
基本上的流程會如下圖:
1. 先進行人臉偵測,取出人臉的影像
2. 人臉影像前置處理(resize、prewhiten)
3. 把處理後的影像給FaceNet進行運作
4. 取得特徵值並計算歐式距離
5. 計算的distance小於閥值則認為是同一個人
(正常計算出來的dinstance介於0~2之間)
因此當你開始要研究如何實作的時候
google上只能找到python...
(廢話...原作者就已經提供python的程式了...)
或是頂多找到c++的程式
因此這大概又是全世界第一篇用C#來實作的介紹...
要用C#跑TensorFlow,前面的文章有介紹過幾個
大致上就是TensorFlowSharp以及EmguTF
這裡以EmguTF作為範例
首先先下載FaceNet已經處理好的Pre-Trained Models
可直接在GitHub的頁面下載
下載下來後
只要取其中的.pb檔即可,如下圖:
依照原有既定的邏輯
要先處理人臉偵測,而人臉偵測可以參考上一篇介紹的方法
整個範例採用EmguTF套件與EmguCV套件來實作
這裡實作了,如何讀入剛剛所下載的Pre-Trained Model
並建立TFSession 與 TFGraph
接著透過EmguCV把人臉的影像讀進來
偵測出人臉後,把人臉的影像節取出來,並進行Resize
FaceNet需Resize至160x160的大小
resize後的image需轉換成Tensor物件
轉換程式可以參考EmguTF的範例程式TensorConvert.cs
這裡使用的版本如下:
將影像的Mat傳入,取得該影像的Tensor物件:tensorImage
以上都算是比較簡單的部分
再來的處理就比較麻煩
第一個是Session Run的實作
來看一下原始Python的Source Code:compare.py
在sess.run裡面會帶入一個參數feed_dict,包含images跟一個False
但是在EmguTF的Tensor物件並沒有帶入bool的建構式
所以必須自行在EmguTF的Source Code加入一個新的建構式
才能建立一個new Tensor(false)物件
接著透過以下的程式進行處理
Session Run的方式如下,並取得特徵值boxes
boxes就是一個一維陣列(128或512個值)
利用這個值,進行歐式距離的計算
即可求出每個人臉的差異結果
Distance的求法很簡單,如下:
用上述的方法就可以求出兩個相同長度的一維陣列的歐式距離
以上的做法可以順利把人臉的影像傳進去給FaceNet
並取得一個一為陣列boxes的值
於是開始著手進行準備資料
收集了150個人的人臉照片,平均一個人1~6張不等作為訓練照片
藝人的照片占多數為主
接著再準備上述150個人,另外500張人臉照片作為測試
500張測試照,角度不同,甚至還有黑白照片
但依據這樣的實作會發現
計算出來的distance值,好像不太準耶??
無論Threshold的值如何訂,準確率都很低
大概只有不到20%... 整個傻眼...
在仔細研究原專案的Source Code:facenet.py
會發現該專案把影像傳給FaceNet時
會先進行一些前處理,包含一個叫做prewhiten的方法
這個看似簡單的方法,卻至關重要!!
裡面使用了叫做Numpy的python套件
是一個方便處理矩陣運算的工具套件
np.mean、np.std、np.maximum、np.multiply...一連四個矩陣運算
如果今天要改實作到別的語言...
只能去爬Numpy中這幾個方法的邏輯
然後...自己實作
也可以參考C++的source code,裡面有OpenCV的語法可以參考
實作完成後,將人臉影像進行上述的影像處理運算
再傳入FaceNet取得特徵值進行比對
實測了目前GitLab提供的兩個新的Model
20180408-102900.pb 以及 20180402-114759.pb
(這兩個Model會產出512個特徵值)
以及一個舊的Model
20170512-110547.pb
(產出128個特徵值)
一樣的測試資料,閥值訂在0.8
20180408-102900.pb ==> 70.3%
20180402-114759.pb ==> 84.5%
20170512-110547.pb ==> 93.8%
舊版的Model實測出:93.8%的準確率!!!
AMAZING!!
雖然不太理解為什麼舊版的測試效果反而比較好 XDD
而且版本之間的準確率落差還蠻巨大
由於藝人的照片是上google隨便亂抓的
有奇怪的光源、角度、甚至不同年代的妝容
因此藝人的照片算是拉低了很多辨識率
但就以20170512-110547.pb 的實測結果
辨識率還是相當驚人呢!!!
而後續提出的新的Model
也提出了新的計算距離的算法
可嘗試使用cosine similarity來計算兩個一維陣列的距離
或許還可以得到更好的辨識效果呢!!
請問一下,你的明星人面庫是那裡下載的?謝
回覆刪除自己上網抓的
刪除