深刻淺出人臉識別技術

在深度學習出現後,人臉識別技術才真正有了可用性。這是由於以前的機器學習技術中,難以從圖片中取出合適的特徵值。輪廓?顏色?眼睛?如此多的面孔,且隨着年紀、光線、拍攝角度、氣色、表情、化妝、佩飾掛件等等的不一樣,同一我的的面孔照片在照片象素層面上差異很大,憑藉專家們的經驗與試錯難以取出準確率較高的特徵值,天然也無法對這些特徵值進一步分類。深度學習的最大優點在於由訓練算法自行調整參數權重,構造出一個準確率較高的f(x)函數,給定一張照片則能夠獲取到特徵值,進而再歸類。本文中筆者試圖用通俗的語言探討人臉識別技術,首先概述人臉識別技術,接着探討深度學習有效的緣由以及梯度降低爲何能夠訓練出合適的權重參數,最後描述基於CNN卷積神經網絡的人臉識別。html

1、人臉識別技術概述python

人臉識別技術大體由人臉檢測和人臉識別兩個環節組成。git

之因此要有人臉檢測,不光是爲了檢測出照片上是否有人臉,更重要的是把照片中人臉無關的部分刪掉,不然整張照片的像素都傳給f(x)識別函數確定就不可用了。人臉檢測不必定會使用深度學習技術,由於這裏的技術要求相對低一些,只須要知道有沒有人臉以及人臉在照片中的大體位置便可。通常咱們考慮使用opencv、dlib等開源庫的人臉檢測功能(基於專家經驗的傳統特徵值方法計算量少從而速度更快),也可使用基於深度學習實現的技術如mtcnn(在神經網絡較深較寬時運算量大從而慢一些)。github

在人臉檢測環節中,咱們主要關注檢測率、漏檢率、誤檢率三個指標,其中:算法

檢測率:存在人臉而且被檢測出的圖像在全部存在人臉圖像中的比例;瀏覽器

漏檢率:存在人臉可是沒有檢測出的圖像在全部存在人臉圖像中的比例;
網絡

誤檢率:不存在人臉可是檢測出存在人臉的圖像在全部不存在人臉圖像中的比例。架構

固然,檢測速度也很重要。本文不對人臉檢測作進一步描述。機器學習

在人臉識別環節,其應用場景通常分爲1:1和1:Nide

1:1就是判斷兩張照片是否爲同一我的,一般應用在人證匹配上,例如身份證與實時抓拍照是否爲同一我的,常見於各類營業廳以及後面介紹的1:N場景中的註冊環節。而1:N應用場景,則是首先執行註冊環節,給定N個輸入包括人臉照片以及其ID標識,再執行識別環節,給定人臉照片做爲輸入,輸出則是註冊環節中的某個ID標識或者不在註冊照片中。可見,從機率角度上來看,前者相對簡單許多,且因爲證件照一般與當下照片年代間隔時間不定,因此一般咱們設定的類似度閾值都是比較低的,以此得到比較好的經過率,容忍稍高的誤識別率。

然後者1:N,隨着N的變大誤識別率會升高,識別時間也會增加,因此類似度閾值一般都設定得較高,經過率會降低。這裏簡單解釋下上面的幾個名詞:誤識別率就是照片實際上是A的卻識別爲B的比率;經過率就是照片確實是A的,但可能每5張A的照片才能識別出4張是A其經過率就爲80%;類似度閾值是由於對特徵值進行分類是機率行爲,除非輸入的兩張照片實際上是同一個文件,不然任何兩張照片之間都有一個類似度,設定好類似度閾值後惟有兩張照片的類似度超過閾值,才認爲是同一我的。因此,單純的評價某我的臉識別算法的準確率沒有意義,咱們最須要弄清楚的是誤識別率小於某個值時(例如0.1%)的經過率。無論1:1仍是1:N,其底層技術是相同的,只是難度不一樣而已。

取出人臉特徵值是最難的,那麼深度學習是如何取特徵值的?

假定咱們給出的人臉照片是100*100像素大小,因爲每一個像素有RGB三個通道,每一個像素通道由0-255範圍的字節表示,則共有3個100*100的矩陣計3萬個字節做爲輸入數據。深度學習實際上就是生成一個近似函數,把上面的輸入值轉化爲能夠用做特徵分類的特徵值。那麼,特徵值能夠是一個數字嗎?固然不行,一個數字(或者叫標量)是沒法有效表示出特徵的。一般咱們用多個數值組成的向量表示特徵值,向量的維度即其中的數值個數。特徵向量的維度並不是越大越好,google的facenet項目(參見https://arxiv.org/abs/1503.03832論文)作過的測試結果顯示,128個數值組成的特徵向量結果最好,以下圖所示:

那麼,如今問題就轉化爲怎麼把3*100*100的矩陣轉化爲128維的向量,且這個向量可以準確的區分出不一樣的人臉?

假定照片爲x,特徵值爲y,也就是說存在一個函數f(x)=y能夠完美的找出照片的人臉特徵值。如今咱們有一個f*(x)近似函數,其中它有參數w(或者叫權重w)能夠設置,例如寫成f*(x;w),如有訓練集x及其id標識y,設初始參數p1後,那麼每次f*(x;w)獲得的y`與實際標識y相比,若正確則經過,若錯誤則適當調整參數w,若是可以正確的調整好參數w,f*(x;w)就會與理想中的f(x)函數足夠接近,咱們就得到了機率上足夠高準確率的f*(x;w)函數。這一過程叫作監督學習下的訓練。而計算f*(x;w)值的過程由於是正常的函數運算,咱們稱爲前向運算,而訓練過程當中比較y`與實際標識id值y結果後,調整參數p的過程則是反過來的,稱爲反向傳播

因爲咱們傳遞的x入參畢竟是一張照片,照片既有對焦、光線、角度等致使的不太容易衡量的質量問題,也有自己的像素數多少問題。若是x自己含有的數據太少,即圖片很是不清晰,例如28*28像素的照片,那麼誰也沒法準確的分辨出是哪一個人。能夠想見,必然像素數越多識別也越準,但像素數越多致使的計算、傳輸、存儲消耗也越大,咱們須要有根據的找到合適的閾值。下圖是facenet論文的結果,雖然只是一家之言,但google的嚴謹態度使得數據也頗有參考價值。

從圖中可見排除照片其餘質量外象素數至少也要有100*100(純人臉部分)才能保證比較高的識別率。

2、深度學習技術的原理

由清晰的人臉照轉化出的象素值矩陣,應當設計出什麼樣的函數f(x)轉化爲特徵值呢?這個問題的答案依賴於分類問題。即,先不談特徵值,首先如何把照片集合按人正確的分類?這裏就要先談談機器學習。機器學習認爲能夠從有限的訓練集樣本中把算法很好的泛化。因此,咱們先找到有限的訓練集,設計好初始函數f(x;w),並已經量化好了訓練集中x->y。若是數據x是低維的、簡單的,例如只有二維,那麼分類很簡單,以下圖所示:

上圖中的二維數據x只有方形和圓形兩個類別y,很好分,咱們須要學習的分類函數用最簡單的f(x,y)=ax+by+c就能表示出分類直線。例如f(x,y)大於0時表示圓形,小於0時表示方形。

給定隨機數做爲a,c,b的初始值,咱們經過訓練數據不斷的優化參數a,b,c,把不合適的L一、L3等分類函數逐漸訓練成L2,這樣的L2去面對泛化的測試數據就可能得到更好的效果。然而若是有多個類別,就須要多條分類直線才能分出,以下圖所示:

這其實至關於多條分類函數執行與&&、或||操做後的結果。這個時候還可能用f1>0 && f2<0 && f3>0這樣的分類函數,但若是更復雜的話,例如自己的特徵不明顯也沒有匯聚在一塊兒,這種找特徵的方式就玩不轉了,以下圖所示,不一樣的顏色表示不一樣的分類,此時的訓練數據徹底是非線性可分的狀態:

這個時候,咱們能夠經過多層函數嵌套的方法來解決,例如f(x)=f1(f2(x)),這樣f2函數能夠是數條直線,而f1函數能夠經過不一樣的權重w以及激勵函數完成與&&、或||等等操做。這裏只有兩層函數,若是函數嵌套層數越多,它越能表達出複雜的分類方法,這對高維數據頗有幫助。例如咱們的照片毫無疑問就是這樣的輸入。所謂激勵函數就是把函數f計算出的很是大的值域轉化爲[0,1]這樣較小的值域,這容許多層函數不斷的前向運算、分類。

前向運算只是把輸入交給f1(x,w1)函數,計算出的值再交給f2(y1,w2)函數,依次類推,很簡單就能夠獲得最終的分類值。可是,由於初始的w權重其實沒有多大意義,它得出的分類值f*(x)確定是錯的,在訓練集上咱們知道正確的值y,那麼事實上咱們實際上是但願y-f*(x)的值最小,這樣分類就越準。這其實變成了求最小值的問題。固然,y-f*(x)只是示意,事實上咱們獲得的f*(x)只是落到各個分類上的機率,把這個機率與真實的分類相比較獲得最小值的過程,咱們稱爲損失函數,其值爲loss,咱們的目標是把損失函數的值loss最小化。在人臉識別場景中,softmax是一個效果比較好的損失函數,咱們簡單看下它是如何使用的。

好比咱們有訓練數據集照片對應着cat、dog、ship三個類別,某個輸入照片通過函數f(x)=x*W+b,前向運算獲得該照片屬於這3個分類的得分值。此時,這個函數被稱爲得分函數,以下圖所示,假設左邊關於貓的input image是一個4維向量[56,231,24,2],而W權重是一個4*3的矩陣,那麼相乘後再加上向量[1.1,3.2,-1.2]可獲得在cat、 dog、ship三個類別上的得分:

從上圖示例可見,雖然輸入照片是貓,但得分上屬於狗的得分值437.9最高,但究竟比貓和船高多少呢?很難衡量!若是咱們把得分值轉化爲0-100的百分比機率,這就方便度量了。這裏咱們可使用sigmoid函數,以下圖所示:

從上圖公式及圖形可知,sigmoid能夠把任意實數轉換爲0-1之間的某個數做爲機率。但sigmoid機率不具備歸一性,也就是說咱們須要保證輸入照片在全部類別的機率之和爲1,這樣咱們還須要對得分值按softmax方式作如下處理:

這樣給定x後能夠獲得x在各個類別下的機率。假定三個類別的得分值分別爲三、一、-3,則按照上面的公式運算後可得機率分別爲[0.8八、0.十二、0],計算過程以下圖所示:

然而實際上x對應的機率實際上是第一類,好比[1,0,0],如今拿到的機率(或者可稱爲似然)是[0.8八、0.十二、0]。那麼它們之間究竟有多大的差距呢?這個差距就是損失值loss。如何獲取到損失值呢?在softmax裏咱們用互熵損失函數計算量最小(方便求導),以下所示:

其中i就是正確的分類,例如上面的例子中其loss值就是-ln0.88。這樣咱們有了損失函數f(x)後,怎麼調整x纔可以使得函數的loss值最小呢?這涉及到微分導數。

3、梯度降低

梯度降低就是爲了快速的調整權重w,使得損失函數f(x;w)的值最小。由於損失函數的值loss最小,就表示上面所說的在訓練集上的得分結果與正確的分類值最接近!

導數求的是函數在某一點上的變化率。例如從A點開車到B點,經過距離和時間能夠算出平均速度,但在其中C點的瞬時速度是多少呢?若是用x表示時間,f(x)表示車子從A點駛出的距離,那麼在x0的瞬時速度能夠轉化爲:從x0時再開一個很小的時間,例如1秒,那麼這一秒的平均速度就是這一秒開出的距離除以1秒,即(f(1+x0)-f(x0))/1。若是咱們用的不是1秒而是1微秒,那麼這個1微秒內的平均速度必然更接近x0時的瞬時速度。因而,到該時間段t趨向於0時,咱們就獲得了x0時的瞬時速度。這個瞬時速度就是函數f在x0上的變化率,全部x上的變化率就構成了函數f(x)的導數,稱爲f`(x)。即:

從幾何意義上看,變化率就變成了斜率,這更容易理解怎樣求函數的最小值。例以下圖中有函數y=f(x)用粗體黑線表示,其在P0點的變化率就是切線紅線的斜率:

能夠形象的看出,當斜率的值爲正數時,把x向左移動變小一些,f(x)的值就會小一些;當斜率的值爲負數時,把x向右移動變大一些,f(x)的值也會小一些,以下圖所示:

這樣,斜率爲0時咱們其實就獲得了函數f在該點能夠獲得最小值。那麼,把x向左或者向右移一點,到底移多少呢?若是移多了,可能移過了,若是移得不多,則可能要移好久才能找到最小點。還有一個問題,若是f(x)操做函數有多個局部最小點、全局最小點時,若是x移的很是小,則可能致使經過導數只能找到某個並不足夠小的局部最小點。以下圖所示:

藍色的爲局部最小點,紅色是全局最小點。因此x移動多少是個問題,x每次的移動步長過大或者太小均可能致使找不到全局最小點。這個步長除了跟導數斜率有關外,咱們還須要有一個超參數來控制它的移動速度,這個超參數稱爲學習率,因爲它很難優化,因此通常須要手動設置而不能自動調整。考慮到訓練時間也是成本,咱們一般在初始訓練階段把學習率設的大一些,越日後學習率設的越小。

那麼每次移動的步長與導數的值有關嗎?這是天然的,導數的正負值決定了移動的方向,而導數的絕對值大小則決定了斜率是否陡峭。越陡峭則移動的步長應當越大。因此,步長由學習率和導數共同決定。就像下面這個函數,?λ是學習率,而?F(ωj) /ωj是在ωj點的導數。

ωj=?ωj -?λF(ωj) /ωj

根據導數判斷損失函數f在x0點上應當如何移動,才能使得f最快到達最小值的方法,咱們稱爲梯度降低。梯度也就是導數,沿着負梯度的方向,按照梯度值控制移動步長,就能快速到達最小值。固然,實際上咱們未必能找到最小點,特別是自己存在多個最小點時,但若是這個值自己也足夠小,咱們也是能夠接受的,以下圖所示:

以上咱們是以一維數據來看梯度降低,但咱們的照片是多維數據,此時如何求導數?又如何梯度降低呢?此時咱們須要用到偏導數的概念。其實它與導數很類似,由於x是多維向量,那麼咱們假定計算Xi的導數時,x上的其餘數值不變,這就是Xi的偏導數。此時應用梯度降低法就以下圖所示,θ是二維的,咱們分別求θ0和θ1的導數,就能夠同時從θ0和θ1兩個方向移動相應的步長,尋找最低點,以下圖所示:

前文說過,根據有限的訓練集,去適應無限的測試集,固然訓練集容量越大效果就越好。可是,訓練集若是很大,那麼每次都根據所有數據執行梯度降低計算量就太大了。此時,咱們選擇每次只取所有訓練集中的一小部分(究竟多少,通常根據內存和計算量而定),執行梯度降低,不斷的迭代,根據經驗同樣能夠快速的把梯度降下來。這就是隨機梯度降低

上面的梯度降低法只能對f函數的w權重進行調整,而上文中咱們說過實際是多層函數套在一塊兒,例如f1(f2(x;w2);w1),那麼怎麼求對每一層函數輸入的導數呢?這也是所謂的反向傳播怎樣繼續反向傳遞下去呢?這就要提到鏈式法則。其實質爲,原本y對x的求導,能夠經過引入中間變量z來實現,以下圖所示:

這樣,y對x的導數等價於y對z的導數乘以z對x的偏導。當輸入爲多維時則有下面的公式:

如此,咱們能夠獲得每一層函數的導數,這樣能夠獲得每層函數的w權重應當調整的步長,優化權重參數。

因爲函數的導數不少,例如resnet等網絡已經達到100多層函數,因此爲區別傳統的機器學習,咱們稱其爲深度學習

深度學習只是受到神經科學的啓發,因此稱爲神經網絡,但實質上就是上面提到的多層函數前向運算獲得分類值,訓練時根據實際標籤分類取損失函數最小化後,根據隨機梯度降低法來優化各層函數的權重參數。人臉識別也是這麼一個流程。以上咱們初步過完多層函數的參數調整,但函數自己應當如何設計呢?

4、基於CNN卷積神經網絡進行人臉識別

咱們先從全鏈接網絡談起。google的tensorflow遊樂場裏能夠直觀的體驗全鏈接神經網絡的威力,這是遊樂場的網址:http://playground.tensorflow.org/,瀏覽器裏就能夠作神經網絡訓練,且過程與結果可視化。以下圖所示:

這個神經網絡遊樂場共有1000個訓練點和1000個測試點,用於對4種不一樣圖案劃分出藍色點與黃色點。DATA處可選擇4種不一樣圖案。

整個網絡的輸入層是FEATURES(待解決問題的特徵),例如x1和x2表示垂直或者水平切分來劃分藍色與黃色點,這是最容易理解的2種劃分點的方法。其他5種其實不太容易想到,這也是傳統的專家系統才須要的,實際上,這個遊樂場就是爲了演示,一、好的神經網絡只用最基本的x1,x2這樣的輸入層FEATURES就能夠完美的實現;二、即便有不少種輸入特徵,咱們其實並不清楚誰的權重最高,但好的神經網絡會解決掉這個問題。

隱層HIDDEN LAYERS能夠隨意設置層數,每一個隱層能夠設置神經元數。實際上神經網絡並非在計算力足夠的狀況下,層數越多越好或者每層神經元越多越好。好的神經網絡架構模型是很難找到的。本文後面咱們會重點講幾個CNN經典網絡模型。然而,在這個例子中,多一些隱層和神經元能夠更好的劃分。

epoch是訓練的輪數。紅色框出的loss值是衡量訓練結果的最重要指標,若是loss值一直是在降低,好比能夠低到0.01這樣,就說明這個網絡訓練的結果好。loss也可能降低一會又忽然上升,這就是很差的網絡,你們能夠嘗試下。learning rate初始都會設得高些,訓練到後面都會調低些。Activation是激勵函數,目前CNN都在使用Relu函數。

瞭解了神經網絡後,如今咱們回到人臉識別中來。每一層神經元就是一個f函數,上面的四層網絡就是f1(f2(f3(f4(x))))。然而,就像上文所說,照片的象素太多了,全鏈接網絡中任意兩層之間每倆個神經元都須要有一次計算。特別以前提到的,複雜的分類依賴於許多層函數共同運算才能達到目的。當前的許多網絡都是多達100層以上,若是每層都有3*100*100個神經元,可想而知計算量有多大!因而CNN卷積神經網絡應運而生,它能夠在大幅下降運算量的同時保留全鏈接網絡的威力。

CNN認爲能夠只對整張圖片的一個矩形窗口作全鏈接運算(可稱爲卷積核),滑動這個窗口以相同的權重參數w遍歷整張圖片後,能夠獲得下一層的輸入,以下圖所示:

CNN中認爲同一層中的權重參數能夠共享,由於同一張圖片的各個不一樣區域具備必定的類似性。這樣本來的全鏈接計算量過大問題就解決了,以下圖所示:

結合着以前的函數前向運算與矩陣,咱們以一個動態圖片直觀的看一下前向運算過程:

這裏卷積核大小與移動的步長stride、輸出深度決定了下一層網絡的大小。同時,核大小與stride步長在致使上一層矩陣不夠大時,須要用padding來補0(如上圖灰色的0)。以上就叫作卷積運算,這樣的一層神經元稱爲卷積層。上圖中W0和W1表示深度爲2。

CNN卷積網絡一般在每一層卷積層後加一個激勵層,激勵層就是一個函數,它把卷積層輸出的數值以非線性的方式轉換爲另外一個值,在保持大小關係的同時約束住值範圍,使得整個網絡可以訓練下去。在人臉識別中,一般都使用Relu函數做爲激勵層,relu函數就是max(0,x),以下所示:

可見 relu的計算量其實很是小!

CNN中還有一個池化層,當某一層輸出的數據量過大時,經過池化層能夠對數據降維,在保持住特徵的狀況下減小數據量,例以下面的4*4矩陣經過取最大值降維到2*2矩陣:

上圖中經過對每一個顏色塊篩選出最大數字進行池化,以減少計算數據量。

一般網絡的最後一層爲全鏈接層,這樣通常的CNN網絡結構以下所示:

CONV就是卷積層,每一個CONV後會攜帶RELU層。這只是一個示意圖,實際的網絡要複雜許多。目前開源的google facenet是採用resnet v1網絡進行人臉識別的,關於resnet網絡請參考論文https://arxiv.org/abs/1602.07261,其完整的網絡較爲複雜,這裏再也不列出,也能夠查看基於tensorflow實現的python代碼https://github.com/davidsandberg/facenet/blob/master/src/models/inception_resnet_v1.py,雅思官網報名注意slim.conv2d含有relu激勵層。

以上只是通用的CNN網絡,因爲人臉識別應用中不是直接分類,而是有一個註冊階段,須要把照片的特徵值取出來。若是直接拿softmax分類前的數據做爲特徵值效果很很差,例以下圖是直接將全鏈接層的輸出轉化爲二維向量,在二維平面上經過顏色表示分類的可視化表示:

可見效果並很差,中間的樣本距離太近了。經過centor loss方法處理後,能夠把特徵值間的距離擴大,以下圖所示:

這樣取出的特徵值效果就會好不少。

實際訓練resnetv1網絡時,首先須要關注訓練集照片的質量,且要把不一樣尺寸的人臉照片resize到resnet1網絡首層接收的尺寸大小。另外除了上面提到的學習率和隨機梯度降低中每一批batchsize圖片的數量外,還須要正確的設置epochsize,由於每一輪epoch應當完整的遍歷完訓練集,而batchsize受限於硬件條件通常不變,但訓練集可能一直在變大,這樣應保持epochsize*batchsize接近所有訓練集。訓練過程當中須要密切關注loss值是否在收斂,可適當調節學習率。

最後說一句,目前人臉識別效果的評價惟一通行的標準是LFW(即Labeled Faces in the Wild,參見http://vis-www.cs.umass.edu/lfw/),它包含大約6000個不一樣的人的12000張照片,許多算法都依據它來評價準確率。但它有兩個問題,一是數據集不夠大,二是數據集場景每每與真實應用場景並不匹配。因此若是某個算法稱其在LFW上的準確率達到多麼的高,並不能反應其真實可用性。

筆者水平有限,若有錯誤歡迎你們指出。

相關文章
相關標籤/搜索