由於個人興趣和工程實踐的要求,最近一直在學習人臉識別的相關知識,並且完成了一套完整的從人臉檢測到人臉識別的程序,指導老師認為效果還不錯可以應用於實際項目中。自己總結了一下在整個工程里遇到的問題,記為隨筆與大家交流。個人水平十分有限,難免有紕漏,望諒解。
本文只記錄一些個人心得,具體的算法和技術不再贅述,如果展開講絕不是一兩篇博文隨筆能夠說清楚的。
整個人臉識別流程分為三個部分(1)人臉檢測;(2)人臉特征提取;(3)基於歐幾里得距離的比較。
人臉識別和圖片分類不同,我們不能像在圖片分類工程中一樣針對每一個分類提供大量的訓練集去訓練我們的模型。在人臉識別的網絡模型中,我們所需要的結果並不是最后全連接層輸出的置信度結果,而是經過CNN網絡提取的特征值。這些特征值的維度根據網絡模型的選用和輸入圖片像素的不同而變化。
由於需求不同,我們對於神經網絡的訓練方式自然不同。通常可以選擇基於三元組損失的訓練方式和基於中心損失的訓練方式。但是基於三元組損失的訓練方式難以定義且難以收斂,所以多選擇基於中心損失的訓練方法,簡單來說中心損失就是為訓練集的每一個分類設置一個中心,通過優化提取特征和這個中心之間的距離來達到優化的效果。在這里需要注意:盡管我們是基於中心損失去訓練神經網絡,但這樣的效果並不會很好。所以我們的損失定義應該是中心損失和傳統的分類損失的加權結合。
至於訓練集,有很多可選的訓練集,但大多需要科學上網甚至正式申請才能夠下載。我使用的訓練集是casia-webface,很好獲取。
我們應該在開始人臉識別之前,應該預先處理數據庫中的圖片。我認為比較好的方法是將提取的特征值(一個數組)記錄在(.txt)文檔里,在啟動服務的時候統一讀取進來。
在從視頻流中獲取圖像的時候有一個要注意的地方,通常可能會選擇用opencv來獲取圖片,但是opencv的圖片格式是bgr與我們的訓練集rgb圖片格式不同。可以通過數組方式交換圖層或者選用更簡單的VideoCapture來獲取圖片。
不同的人提取的特征值自然有所差別,通常的做法是將特征值reshape為一個一維數組,然后對不同的人臉的特征值之間求歐幾里得距離,同一個人的照片求得的歐氏距離會更小(建議為了放大不同人臉之間距離的差距,可以省略開方的步驟)。這里我們為距離設置一個閾值(THRESGOLD),當求得的歐氏距離小於這個閾值時認為兩張照片出自同一個人。這里閾值的設置沒有一個標准,畢竟准確率和識別成功率難以兼得,可以通過自己的測試選定一個合適的值。比如我選用的Res-net模型,求得的特征值長度為2048,當閾值小於17時基本不會出錯,但同時也會難識別;如果讓人臉很端正地靠近攝像頭,測得的歐式距離基本在14以內。
在實際應用中我們是在一個很大的數據庫中比對人臉特征,最簡單的做法當然是在一個for循環里將本次取得的特征值和數據庫里的特征值逐一求得距離,這也是我一開始沒有做好的地方。在這里個人建議:為了充分利用計算資源,首先將圖片特征值轉換為narray格式,然后擴展為一個與數據庫特征值數量對應的矩陣,如[15000,2048]。然后將該矩陣和數據庫特征值整體求歐幾里得距離。這是因為numpy庫是用C語言編寫的,它可以繞過Python的GIL而實現真正的多線程運算。經過我的測試,利用矩陣整體運算的方法可以使搜索速度提升2至3倍。這在數據庫數據較少時對整體速度的提升很有限,但一旦該當數據庫的數據上升到以萬為單位時,多線程的矩陣運算對整體識別速度的提升是十分有效的。
拋磚引玉,在這里附上我的完整的識別流程:
1.加載神經網絡檢測模型MTCNN和特征提取模型Res-Net,返回網絡的輸入和輸出節點。
2.啟動會話。
3.啟動獲取數據庫的全體特征向量(在數據庫中由.txt格式保存)。
4.啟動攝像頭:
a) 從視頻流里截取一幀圖片,轉為numpy三維數組格式。
b) 將圖片作為輸入,由MTCNN模型計算,計算結果返回boundingbox回歸框標定檢測結果的四個點。裁剪圖片,通過回歸點計算目標面積(這里的目標面積可以用於目標距離的相對距離的表示),將裁減后的統一化像素為256x256。
c) 將檢測后的圖片作為Res-Net的輸入,返回(16x128=2048)的特征值。(Res-Net的返回值是(n*128)的形式,根據輸入像素的不同返回不同的n。)
d) 將2048長度的特征值與數據庫加載的用戶特征計算歐氏距離,取最小的歐式距離。
(為了充分利用計算資源這里首先將圖片特征值轉換為narray格式,然后擴展為一個與數據庫特征值數量對應的矩陣,如[15000,2048]。然后將該矩陣和數據庫特征值整體求歐幾里得距離。注:在這里我為了放大差距並沒有做開方運算,所以並不是一個標准的歐氏距離。)
e) 標定一個閾值(或者轉換為相似度),當最小的歐氏距離小於閾值時認為確定識別。(經過反復測試,准確率和識別成功率難以兼得。當閾值小於17時基本不會出錯,但同時也會難識別;如果以人臉簽到的標准讓人臉很端正地靠近攝像頭,測得的歐式距離基本在14以內;為了保證識別速度,暫時將閾值調高,並通過多次確認的方式提高准確率)
f) 將識別結果和目標面積加入一個全局字典。在字典中查找,當發現同一個目標在一定時間內連續被識別出三次以上時(多次識別以保證正確率),認為正式識別。同時通過計算目標面積的變化可以判斷目標是否有靠近的傾向。