當前位置:
首頁 > 最新 > 使用卷積神經網路做人臉識別

使用卷積神經網路做人臉識別

上回書說到了對人臉的檢測,這回就開始正式進入人臉識別的階段。

關於人臉識別,目前有很多經典的演算法,當我大學時代,我的老師給我推薦的第一個演算法是特徵臉法,原理是先將圖像灰度化,然後將圖像每行首尾相接拉成一個列向量,接下來為了降低運算量要用PCA降維, 最後進分類器分類,可以使用KNN、SVM、神經網路等等,甚至可以用最簡單的歐氏距離來度量每個列向量之間的相似度。OpenCV中也提供了相應的EigenFaceRecognizer庫來實現該演算法,除此之外還有FisherFaceRecognizer、LBPHFaceRecognizer以及最近幾年興起的卷積神經網路等。

卷積神經網路(CNN)的前級包含了卷積和池化操作,可以實現圖片的特徵提取和降維,最近幾年由於計算機算力的提升,很多人都開始轉向這個方向,所以我這次打算使用它來試試效果。

老規矩,先配置下編程的環境:

系統:windows / linux

解釋器:python 3.6

依賴庫:numpy、opencv-python 3、tensorflow、keras、scikit-learn

如果手中有一塊支持Cuda加速的GPU建議安裝GPU版本:

上次文章有位讀者評論說:

所以,為了照顧初學者,這裡簡單介紹下Anaconda的安裝方法,Anaconda是一個開源的Python發行版本,其包含了Conda、Python等180多個科學包及其依賴項。因為包含了大量的科學包,Anaconda 的下載文件比較大,所以有python包安裝基礎的人還是建議通過pip來安裝所需的依賴。

首先進入Anaconda下載頁(https://www.anaconda.com/download/):

這裡根據自己的電腦系統來選擇相應的系統選項,至於是64位還是32位要根據自己電腦的內存大小和系統位數來選擇,python版本選擇3.6。

下載完成安裝,打開程序,切換左側菜單到Environment,選擇all,輸入想要安裝的模塊並搜索,選中後點擊右下角的Apply就開始安裝了。

基本思路:

我的設計思路是這樣的,先用上節講到的人臉檢測方法來檢測出人臉位置,然後根據返回的坐標、尺寸把臉用數組切片的方法截取下來,然後把截取的小圖片送進訓練好的卷積神經網路模型,得出人臉的分類結果,最後在原圖片上打上包圍框並且把結果寫在包圍框的上端:

原諒我拙劣的繪畫技巧

當然了,實現這一步驟的前提就是要有一個訓練好的可以做人臉識別的模型,所以本文的主要內容都會放在訓練上面。

深度學習框架的選擇:

卷積神經網路是深度學習在圖像方面的應用,所以最高效的方法就是選擇合適的深度學習框架來實現它,現在市面上有很多深度學習框架可供選擇, 比如基於 C++ 的Caffe 、基於 Python 的TensorFlow、Pytorch、Theano、CNTK以及前兩天一個好友提到的她正在用來做推薦演算法的MXNET。

這些都是搭建深度學習框架不錯的選擇,不過搭建的步驟會比較繁瑣,會讓很多初學者瞬間放棄,還好世界上出現了Keras,它可以使用TensorFlow、Theano、CNTK作為後端運算引擎,提供了高層的,更易於使用的函數,可以讓不太了解深度學習原理的人也能快速上手,用通俗的話說就是:「 Keras是為人類而不是天頂星人設計的API 」。

本文所使用後端運算引擎為TensorFlow,簡稱 TF (掏糞)。

人臉收集:

我的目的是希望在很多人中可以識別出自己的臉,所以對這個系統的要求是:

不能把別人識別成我

要能在我出現的時候識別出我

於是我需要自己的一些圖照片,來教會神經網路,這個就是我,以及一堆其他人的照片來告訴它,這些不是我,或者說這些人分別是誰。

現在需要去採集一些其他人的圖片,這些數據集可以自己用相機照、或者寫個爬蟲腳本去網上爬,不過由於人臉識別早在幾十年前就一直有前輩在研究,很多大學和研究機構都採集並公布了一些人臉數據集專門用作圖像識別演算法的研究和驗證用,像耶魯大學的Yale人臉庫,劍橋大學的ORL人臉庫以及美國國防部的FERET人臉庫等,我在這裡用了耶魯大學的Yale人臉庫,裡面包含15個人,每人11張照片,主要包括光照條件的變化,表情的變化,接下來我會把自己的幾張照片混進去,看看訓練過後能不能被神經網路良好的識別。

頭像提取:

提取自己照片使用的是上篇文章提到的方法:

獲取文件夾下所有圖片文件 -> 檢測人臉位置 -> 根據人臉位置及尺寸剪裁出人臉 -> 保存。

這是我的目錄結構:

代碼:

得到了還蠻不錯的效果:

尺寸變換:

現在有了所有的圖片,可以開始訓練了,不過Yale人臉庫裡面所有照片都是100*100的尺寸,所以將要構建的卷積神經網路的輸入就是100*100,而我新生成的圖片樣本形狀都是不規則的,為了使它可以順利進入卷積層,第一步就要對圖片做尺寸變換,當然不能暴力的resize成100*100,否則會引起圖片的變形,所以這裡採用了一種數字圖像處理中常用的手段,就是將較短的一側塗黑,使它變成和目標圖像相同的比例,然後再resize,這樣既可以保留原圖的人臉信息,又可以防止圖像形變:

調用了該函數出現了下面的效果:

下面是讀取照片的函數,可以傳入尺寸,默認尺寸是100*100,返回了兩個列表,第一個列表中每一個元素都是一張圖片,第二個列表中則對應存儲了圖片的標籤,這裡用1、2、3.......來指代,因為我根本不知道這些人的名字是什麼:

訓練:

接下來就是最重要的一步了,訓練卷積神經網路,訓練的好壞會直接影響識別的準確度。

引進卷積和池化層,卷積類似於圖像處理中的特徵提取操作,池化則很類似於降維,常用的有最大池化和平均池化:

引入全連接層、Dropout、Flatten。

全連接層就是經典的神經網路全連接。

Dropout用來在訓練時按一定概率隨機丟棄一些神經元,以獲得更高的訓練速度以及防止過擬合。

Flatten用於卷積層與全連接層之間,把卷積輸出的多維數據拍扁成一維數據送進全連接層(類似shape方法):

引入SGD(梯度下降優化器)來使損失函數最小化,常用的優化器還有Adam:

讀入所有圖像及標籤:

神經網路需要數值進行計算,需要對字元型類別標籤進行編碼,最容易想到的就是把他們編碼成1、2、3.......這種,但是這樣也就出現了強行給它們定義了大小的問題,因為如果一個類別是2,一個是4,他們之間就會有兩倍的關係,但是實際上他們之間並沒有直接的倍數關係,所以這裡使用one-hot編碼規則,做到所有標籤的平等化。on-hot編碼:

在所有讀入的圖像和標籤中,需要劃分一部分用來訓練,一部分用來測試,這裡使用了sklearn中的train_test_split方法,不僅可以分割數據,還可以把數據打亂,訓練集 :測試集 = 7 : 3 :

數據歸一化,圖像數據只需要每個像素除以255就可以:

構建卷積神經網路的每一層:

添加卷積層,32個卷積核,每個卷積核是3 * 3,邊緣不補充,卷積步長向右、向下都為1, 後端運算使用 tf , 圖片輸入尺寸是(100,100, 3),使用relu作為激活函數,也可以用sigmoid函數等,relu收斂速度比較快:

池化層,過濾器尺寸是2 * 2:

Dropout層:

Flatten層,處於卷積層與Dense(全連層)之間,將圖片的卷積輸出壓扁成一個一維向量:

全連接層, 經典的神經網路結構,512個神經元:

輸出層,神經元數是標籤種類數,使用sigmoid激活函數,輸出最終結果:

有點不放心,把神經網路結構列印出來看一下:

看起來沒什麼問題。

使用SGD作為反向傳播的優化器,來使損失函數最小化,學習率(learning_rate)是0.01,學習率衰減因子(decay)用來隨著迭代次數不斷減小學習率,防止出現震蕩。引入衝量(momentum),不僅可以在學習率較小的時候加速學習,又可以在學習率較大的時候減速,使用nesterov:

編譯模型,損失函數使用交叉熵,交叉熵函數隨著輸出和期望的差距越來越大,輸出曲線會越來越陡峭,對權值的懲罰力度也會增大,如果其他的損失函數,如均方差可以可以的,各有優劣:

開始訓練,訓練100次(epochs),每次訓練分幾個批次,每批(batch_size)20個,shuffle用來打亂樣本順序:

現在離開座位,找一個西瓜,慢慢吃,一定要慢,因為訓練的時間著實太長,配上薯片會更好。

訓練完成後在測試集上評估結果並保存模型供以後載入使用:

識別:

要開始寫在識別時正式運行的程序了:

載入級聯分類器模型:

載入卷積神經網路模型:

打開攝像頭,獲取圖片並灰度化:

人臉檢測:

根據檢測到的坐標及尺寸裁剪、無形變resize、並送入模型運算,得到結果後在人臉上打上矩形框並在矩形框上方寫上識別結果:

看效果:

當然了,識別的效果還是取決於訓練好的模型的質量,我差不多用了吃2/3個西瓜的時間來訓練,還是有一些誤識別的情況出現:

總結了下這次的人臉識別系統,感覺人臉檢測效果還需要改進,識別準確度也有待提升,之後要多收集各個角度的照片樣本和改進網路參數。

這是我的微信公眾號二維碼:

歡迎關注!

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 kangChi的小課堂 的精彩文章:

TAG:kangChi的小課堂 |