人臉辨識(Face recognition) 解析與實作

使用 Tensorflow, Keras & OpenCV

Jack Lin
Coding like coffee
11 min readApr 25, 2019

--

source

來自《DeepFace: Closing the gap to human-level performance in face verification》(2014) [1]與《FaceNet: A Unified Embedding for Face Recognition and Clustering》(2015) [2]這兩篇 paper 提出的方法,此外利用OpenCV 來擷取 Webcam 的影像,並使用其提供的 Haar Cascade 分類器進行人臉檢測(Face Detection)

在 Face Recognition (人臉辨識)的問題上,通常會再進一步分成兩個種類 :

  • Face Verification (人臉驗證) :
  1. 給予輸入 image, name/ID
  2. 輸出是否為此人
  3. 視為 1:1 matching problem

e.g. 手機的人臉解鎖

  • Face Recognition (人臉辨識) :
  1. 擁有 K 個人物的Database
  2. 給予 Input image
  3. 輸出 ID, if (image 為 K 個人物中的其中一個)
  4. 無法辨識此人, if (image 不為K個人物中任何一個)
  5. 視為 1:K matching problem

e.g. 使用的人臉辨識的員工通行閘門

Concept

在人臉辨識 (Face Recognition) 的應用中經常要做到只靠一張照片就能辨認一個人,但深度學習(Deep Learning)的演算法在只有一筆訓練資料的情況下效果會很差,所以在人臉辨識中必須解決 One Shot Learning(單樣本學習)的問題

One Shot Learning (單樣本學習)

假定某公司內的 Database 共有4位人員的照片各一張,當有其中一位人員經過系統前的鏡頭並被捕捉到臉孔後,儘管 Database 只有一張此人的照片,系統依然能辨認出此臉孔為公司裡的員工,相反的,若不為公司內人員則無法辨識此人

Similarity Function (相似度函數)

為了達到 One Shot Learning (單樣本學習)這樣的目標,我們希望讓NN(Neural Network)去學習一個函數 d

d(img1, img2):給予兩張照片,輸出這兩張照片的相異程度

  • 如果兩張照片是同一個人,則輸出一個較小的數字
  • 如果兩張照片是不同人,則輸出一個較大的數字
    此外,需定義一個 Hyperparameter(超參數)「τ」
  • 如果d(img1,img2)≤τ→ 相同
  • 如果d(img1,img2)>τ→ 不同

如此一來就解決了人臉驗證的 1:1 matching problem,而在人臉辨識的 1:K matching problem 同樣也可使用此函數來解決 One-Shot Learning (單樣本學習)的問題

找出距離小於τ的人像,並辨識出此人
比對資料庫內人像的距離都大於τ,無法辨識此人

Siamese network (孿生網路)

使用《DeepFace: Closing the gap to human-level performance in face verification》(2014) [1]提出的 Siamese network 架構來達成上述 Similarity Function的效果,其實就是使用兩個常見的 ConvNet 的網路架構,這個兩個網路擁有相同的參數與權重,一樣經由 Convolution(卷積)、Pooling(池化)、Fully connected layers(全連接層)最後得到一個帶有128個數字的特徵向量(feature vector),而這個過程稱為 encoding(編碼)

Siamese network (孿生網路)
  • 將兩張圖片(這裡稱x(1)與x(2))放入這兩個 ConvNet 後得出編碼的兩個特徵向量(feature vector)
  • 為了算出兩張圖片相似度,方式為將這兩個經由編碼所獲得的128維特徵向量f(x1)、f(x2)相減並取2範數(2-Norm)的平方,這樣我們就透過Siamese network 學習出我們所想要的 Similarity Function(相似度函數)
Similarity Function(相似度函數)

Note:2範數(2-Norm)又稱為為歐基里德範數(Euclidean norm),是以歐式距離的方式作為基礎,計算出向量的長度或大小(線性代數的內積空間經常用到)

2範數(2-Norm)
  • 總結來說,在 Siamese network 的架構我們希望能學出一種 encoding(編碼)方式,更準確來說是希望學習出參數使得我們能達成以下的目標

在上述的目標中,改變 ConvNet 每一層的參數就會得到不同的編碼,所以我們可以利用反向傳播(Backpropagation)來更改這些參數以達到上列的目標

Triplet Loss (三元組損失)

在NN(Neural Network)的訓練中,都需要一個損失函數(Loss function)作為最小化(minimize)目標,而在Face recognition的應用中為了能夠學習參數來得到良好的編碼(encoding),《FaceNet: A Unified Embedding for Face Recognition and Clustering》(2015) [2]這篇論文提出一種有效的損失函數稱為 Triplet Loss (三元組損失)

  • 在 Triplet Loss 中會有 AnchorPositiveNegative 這三種照片
  • Positive 為與 Anchor同個人的照片
  • Negative 則為不同人的照片
  • 我們需要比較 Anchor 分別與 Positive 和 Negative 一組的兩對的照片
  • 目標是希望 Anchor 與 Positive 的距離(編碼)較近,與 Negative 的距離(編碼)較遠

也就是說,我們希望神經網路的參數所造成的編碼能夠使 Anchor 與 Positive的距離小於等於 Anchor 與 Negative 的距離這樣的性質

Triplet Loss

在上圖中,Anchor、Positive、Negative分別簡寫為A、P、N

  • 如果 f 變成零函數會將每個向量的輸出都變成零,就是所謂的trivial solutions,則0 – 0 ≤ 0 這樣就很容易滿足這個不等式,會讓NN學不到我們的目標
  • 為了不讓 NN 將編碼學習成零函數,我們希望兩對的照片的差距不只小於等於零,還要比零還小一些,因而引進一個超參數(Hyperparameter)α,這個 α 稱為 邊距 (margin),我們讓 ≤ 這個符號左邊的式子小於負α,習慣上會將 α 移到式子左邊
  • 而邊距(margin) 用意即是拉開 d(A,P) 與 d(A,N) 這兩對的差距,就是把這兩對推開,盡量的遠離彼此
    e.g. 假設 margin = 0.2 ,表示若 d(A,P)=0.5 則 d(A,N) 至少0.7才符合上述的不等式,若 d(A,N) 為0.6就不符合,因為兩組的差距不夠大
  • Triplet Loss 的實現如下

Loss Function (損失函數)

Triplet Loss 定義在3張一組的圖片A、P、N上,則損失函數可以定義成:

Loss Function

這個 max 函數的用意在於,若括號的左邊項 ≤ 0則損失就為零,若左邊項 > 0則損失變成大於零;而我們是希望損失越小越好,所以只要左邊項 ≤ 0不管負多少,就能把損失推向零

Cost function (成本函數)

將訓練資料裡一組三張圖片的損失加總起來作為整體 NN 的總成本(Total cost),並利用 Gradient descent (梯度下降法)來去訓練 NN 最小化成本

Cost function

Note: 假定有10000張訓練圖片,分別來自1000個不同的人(每人約10張圖片)才能構成我們的資料集,若每個人只有一張照片這樣就無法順利挑出Anchor 與 Positive,但是當 NN 訓練完成後就可以將系統用在 One-shot Learning 的問題,對於你想辨識的人,你可能只有他的一張照片也能順利辨識出此人。

Choosing the triplets A, P, N

  • 在訓練資料中,Triplets(三元組)樣本的選擇會是一個問題,因為在上述學習目標 d(A,P) + α ≤ d(A,N) 中,若只按照要求隨機的選擇同一個人的照片A與P 和不同人照片A與N,則這個不等式很容易就被滿足,因為隨機挑兩個人的照片有很大的機率使得 A 與 N 差異遠大於 A 與 P,這會使得 NN無法學習有效的參數
  • 因此,要建立訓練集的話必須挑選那種很難訓練的 A, P和 N,因為目標是讓所有 Triplets(三元組)滿足 d(A,P) + α ≤ d(A,N) 這個不等式,而很難訓練的 Triplets(三元組)的意思就是你所挑選的 A,P和N會讓 d(A,P)≈ d(A,N) ,如此一來NN在學習的時候就必須花更大的力氣嘗試讓d(A,N)往上推或讓 d(A,P)往下掉 ,推開彼此以達到相隔α的邊距,這樣的效果會讓你的學習演算法更效率;反之,若隨便選會導致很多的 Triplets(三元組)都解起來很簡單,Gradient descent(梯度下降法)就不會再做任何事,因為你的NN早已把問題都做對了,這部分在《FaceNet: A Unified Embedding for Face Recognition and Clustering》(2015) [2]這篇論文有更詳細的說明

Face detection (人臉偵測)

在人臉偵測的部分使用 OpenCV 的 Haar Cascade 分類器,選擇的為人臉分類器haarcascade_frontalface_default.xml

Usage

完整的程式在我的github

  • On Windows
eg: With Tensorflow as backend
> python facenet.py

Result

  • 利用 OpenCV 的 Haar Cascade 分類器進行人臉偵測(Face detection)
人臉偵測(Face detection)
  • 偵測出人臉後使用預訓練的 FaceNet 來進行 encoding 並計算距離,辨識從 Webcam 讀取的影像是否為資料庫中的人物

- 若距離小於0.7則回傳資料庫內對應的人名與印出字串並發出語音”Welcome (someone), have a nice day!”

- 若不是則繼續偵測人臉並計算當下影像的編碼與距離

Output distance

--

--

Jack Lin
Coding like coffee

Sharing the subject of data science and deep learning