傳統的基於CNN的人臉識別方法為:
1. 利用CNN的siamese網絡來提取人臉特征
2. 然后利用SVM等方法進行分類
facnet亮點
1. 利用DNN直接學習到從原始圖片到歐氏距離空間的映射,從而使得在歐式空間里的距離的度量直接關聯着人臉相似度;
2. 引入triplet損失函數,使得模型的學習能力更高效。
部分結果展示:
而這篇文章中他們提出了一個方法系統叫作FaceNet,它直接學習圖像到歐式空間上點的映射,其中呢,兩張圖像所對應的特征的歐式空間上的點的距離直接對應着兩個圖像是否相似。
圖1
這是一個簡單的示例,其中圖中的數字表示這圖像特征之間的歐式距離,可以看到,圖像的類內距離明顯的小於類間距離,閾值大約為1.1左右。
實現
這篇文章中,最大的創新點應該是提出不同的損失函數,直接是優化特征本身,用特征空間上的點的距離來表示兩張圖像是否是同一類。網絡結構如下:
圖2
上圖是文章中所采用的網絡結構,上圖步驟可以描述為:
1.前面部分采用一個CNN結構提取特征,
2.CNN之后接一個特征歸一化(使其特征的||f(x)||2=1,這樣子,所有圖像的特征都會被映射到一個超球面上),
3.再接入一個embedding層(嵌入函數),嵌入過程可以表達為一個函數,即把圖像x通過函數f映射到d維歐式空間。
4.此外,作者對嵌入函數f(x)的值,即值閾,做了限制。使得x的映射f(x)在一個超球面上。
5.接着,再去優化這些特征,而文章這里提出了一個新的損失函數,triplet損失函數(優化函數),而這也是文章最大的特點所在。
Triplet Loss(三元組損失函數):
以下是Triplet損失函數的原理(Triplet翻譯為三元組):
思想:
什么是Triplet Loss呢?故名思意,也就是有三張圖片輸入的Loss(之前的都是Double Loss或者是 SingleLoss)。
本文通過LDA思想訓練分類模型,使得類內特征間隔小,類間特征間隔大。為了保證目標圖像 與類內圖片(正樣本)特征距離小,與類間圖片(負樣本)特征距離大。需要Triplet損失函數來實現。
根據上文,可以構建一個約束條件:
把上式寫成損失(優化)函數,通過優化(減小)損失函數的值,來優化模型。損失函數為:
Triplet Selection(generate)
在上面中,如果嚴格的按照上式來進行學習的話,它的T(窮舉所有的圖像3元組)是非常大的。
舉個例子:在一個1000個人,每人有20張圖片的情況下,其T=(1000*20)*19*(20*999)(總圖片數*每個圖片類內組合*每個圖片類間組合),也就是O(T)=N^2 ,所以,窮舉是不大現實的。那么,我們只能從這所有的N^2個中選擇部分來進行訓練。現在問題來了,怎么從這么多的圖像中挑選呢?答案是選擇最難區分的圖像對。
給定一張人臉圖片,我們要挑選:
1.一張hard positive:即在類內的另外19張圖像中,跟它最不相似的圖片。(正樣本里面最差的樣本)
2.一張hard negative:即在類間的另外20*999圖像中,跟它最為相似的圖片。(負樣本里面最差的樣本)
挑選hard positive 和hard negative有兩種方法,offline和online方法,具體的差別只是在訓練上。
問題描述:為了確保模型快速收斂,選擇違反公式1的約束條件的三元組(損失函數的負樣本,與前面的類間圖片表示的“負樣本”不一樣)是至關重要的。這意味着給定,我們需要:
1.選擇一個,使得
2.選擇一個,使得
解決方案:
在整個訓練集上尋找argmax和argmin是困難的。如果找不到,會使訓練變得困難,難以收斂,例如錯誤的打標簽和差勁的反映人臉。因此需要采取兩種顯而易見的方法避免這個問題:
1.離線更新三元組(每隔n步)。采用最近的網絡模型的檢測點 並 計算數據集的子集的argmin和argmax(局部最優)。
2.在線更新三元組。在mini-batch上 選擇不好的正(類內)/負(類間)訓練模型。(一個mini-batch可以訓練出一個子模型)
本文中采用上述第二種方法。本文中,采用以下方法:
1.使用大量 mini-batch,從而得到幾千個不好的訓練模型。
2.計算mini-batch上的argmin和argmax。
總結:以上所有過程博主概括為:為了快速收斂模型-->需要找到訓練的不好的mini-batch上的差模型(負樣本)-->從而找到 不滿足約束條件/使損失增大 的三元組
在本文中,訓練集的每個mini-batch包含:
1. 每個身份的40個人臉
2. 隨機放一些負樣本人臉
實際采用方法:
1.采用在線的方式 (作者說,在線+不在線方法結果不確定)
2.在mini-batch中挑選所有的anchor positive 圖像對 (因為實際操作時,發現這樣訓練更穩定)
3.依然選擇最為困難的anchor negative圖像對 (可以提前發現不好的局部最小值)
特殊情況:
選擇最為困難的負樣本,在實際當中,容易導致在訓練中很快地陷入局部最優,或者說整個學習崩潰f(x)=0 //我在CNN學習的時候也經常會遇到這個問題,不過我的是f(x)=1。為了避免這個問題,在選擇negative的時候,使其滿足式(3):
左邊:Positive pair的歐式距離右邊:negative pair的歐式距離。把這一個約束叫作semi-hard (半序關系)。因為雖然這些negative pair的歐式距離 遠小於 Positive pair的歐式距離,但是 negative pair的歐式距離的平方 接近於Positive pair的歐式距離的平方。
深度網絡結構
最優化算法:
1. SGD+標准BP
2. AdaGrad
起始的學習率:0.05 (之后逐漸遞減,直到模型收斂)
訓練時間:在cpu集群上訓練1000-2000 h,從500 h開始,loss大幅減少。
參數:設置為0.02
網絡結構:(均使用修正的線性單元作為非線性激活函數)
1. 左邊是ZF-Net。原文描述如下:
步長不為1的時候,輸入維數又很大的時候,該怎么計算,經過自己的研究得出公式(池化也是一樣計算):
input_size: 輸入維數大小
filter_size: 卷積核大小
stride: 步長
feature map = [(input_size - filter_size+ stride) /stride] ;;上取整,邊界不丟棄(加上一個stride再除以stride,因為最后1次滑動也算入)
輸入層:224*224像素,3顏色通道
1st隱藏層:卷積。每個顏色通道96個濾波器,大小7*7,x和y方向上的步長均為2。卷積得到110*110的特征圖( 特征圖邊長=(224-7+2)/2)--> 經過 一個修正的線性單元(Relu, 圖中未顯示)-->池化。3*3的最大池化,x和y方向上的步長均為2。池化得到50*50的特征圖( 特征圖邊長=(110-3+2)/2) )
BN層:對比和歸一化這96個特征層
2345層:原理同上
67層:全連接層,把第5層的特征圖轉化成一維向量。
8層:softmax層,把輸出值歸一化( soft(軟化)+max(最大值歸1,其余歸0) )
2.右邊是GooLeNet。層數更多,參數更少。網絡結構如下:
對上圖做如下說明:
1 . 顯然GoogLeNet采用了模塊化的結構,方便增添和修改;
2 . 網絡最后采用了average pooling來代替全連接層,想法來自NIN,事實證明可以將TOP1 accuracy提高0.6%。但是,實際在最后還是加了一個全連接層,主要是為了方便以后大家finetune;
3 . 雖然移除了全連接,但是網絡中依然使用了Dropout ;
4 . 為了避免梯度消失,網絡額外增加了2個輔助的softmax用於向前傳導梯度。文章中說這兩個輔助的分類器的loss應該加一個衰減系數,但看caffe中的model也沒有加任何衰減。此外,實際測試的時候,這兩個額外的softmax會被去掉。
下面是文中實驗用到的一些網絡模型:
NN1:ZF-Net(Zeiler&Fergus),在前幾個卷積層中加入了1*1*d的卷積層,有效的減小了參數的個數。但和GoogleNet相比,參數量還是很大。
NN2:GooleNet。如圖6。與原模型主要區別在於:
1.使用的是L2池化而不是max池化。
2.池化的卷積核大小一般是3*3(除了最后那個平均池化),並且並行於每個輸入模塊里的卷積模塊。
如果在1*1,3*3,5*5池化后有維度下降,那么把它們連接起來作為最后的輸出。
NNS1:剪裁后的GooleNet。為了使得模型可以嵌入到移動設備中,本文中也對模型進行了裁剪。NNS1即只需要26M的參數和220M的浮點運算開銷。
NNS2:剪裁后的GooleNet。NNS2則只有4.3M的參數和20M的浮點運算量。
NN3:GooleNet。與NN2結構一樣,但輸入圖片大小只有160*160。這樣極大幅度的降低了對CPU的需求。
NN4:GooleNet。與NN2結構一樣,但輸入圖片大小只有96*96。這樣極大幅度的降低了對CPU的需求。