機器學習原來如此有趣:用深度學習識別人臉

本系列文章目前已經更新兩期,分別是:  機器學習原來如此有趣!全世界最簡單的機器學習入門指南、  機器學習原來如此有趣:如何故意欺騙神經網絡

 

你是否有注意到Facebook最近開發了一個非同尋常的功能:將你照片中的好友識別出來。過去,Facebook 讓你手動點擊照片上的好友,輸入他們的名字,而後加上標籤。如今只要你上傳一張照片,Facebook就會像變魔術同樣爲你自動標記出全部人:html

 

這項技術就叫作人臉識別。在你的朋友的臉被標記了幾回以後,Facebook的算法就能夠識別他了。這是一個讓人驚豔的技術--Facebook識別人臉的正確率高達98%!這與人類的表現差很少了。python

 

下面就讓咱們來學習一下人臉識別技術是如何實現的!可是隻是識別你的朋友的臉就太簡單了。 咱們能夠最大化擴展這項技術,來解決一個更具挑戰性的問題——區分威爾·法瑞爾(Will Ferrell,著名演員)和查德·史密斯(Chad Smith,著名搖滾音樂家)!git

 

 

如何使用機器學習來解決複雜的問題

 

人臉識別由一個系列的相關問題組成:github

 

1.首先:查看一張照片並找出上面全部的臉算法

2.將注意力放在每一張臉上面,即便這張臉被轉到奇怪的方向或者是光線很差的狀況下也依舊是同一我的。docker

3. 從這張臉上挑出一些特徵用於和其餘人區分來,好比像眼睛有多大,臉有多長等。數據庫

4.最後,將這張臉的特徵和其餘其餘臉做比較,以最後肯定這我的的名字。bash

 

做爲一我的類,你的大腦會自動作這些事情。實際上,人類太擅長於識別人臉了,以致於他們在平常物品上面也會試圖去尋找臉(好像是這樣哦,人們老是喜歡去物品上找出練得形狀,而且以爲這樣很萌)。網絡

 

計算機目前並不具有這種高水平的能力。。。因此咱們須要一步步的教他們。app

 

咱們須要構建一個流水線(pipeline):咱們將分別解決人臉識別的每一步,並將當前步驟的結果傳入下一個步驟。換句話說,咱們須要將幾個機器學習算法鏈(chain)起來。

 

人臉識別-一步一步來

 

咱們一步一步地解決這個問題。在每個步驟中,咱們都將學習到不一樣的機器學習算法。我不會對算法的每一步都進行解釋,可是你能夠學習到每個算法的主體思想,以及如何在 Python 中使用 OpenFace 和 dlib 來構建一個你本身的面部識別系統。

 

第一步:尋找全部的臉

 

在咱們的流水線中的第一步是人臉檢測。很明顯在咱們區分人臉以前須要在圖片中將臉標記出來。

 

若是你有在最近十年裏面用過相機的話,你可能已經見過正在運行中的人臉檢測了:

 

面部識別是相機的一個偉大的功能。當相機能夠自動挑出面部的時候,這將確保在拍照片的瞬間全部的臉都對準焦點了。不過咱們使用它是爲了別的目的--尋找咱們想在下一步要傳遞的照片區域。

 

2000年年初的時候,當Paul Viola和Michael Jones發明了一種能夠在廉價相機上面快速運行的面部檢測技術後,人臉檢測成爲了主流。然而如今更可靠的解決方案出現了。咱們如今用的是2005年發明的一個叫作方向梯度直方圖,簡稱爲HOG

 

爲了識別出圖片中的臉,首先咱們須要將圖片轉換爲黑白色,由於在識別面部的時候咱們不須要顏色數據。

 

而後咱們須要依次遍歷圖片中的每一個像素。對於單個像素,咱們也須要看直接包圍它的其餘元素:

 

 

咱們的目標是比較這個像素與周圍像素的深度。而後咱們要畫一個箭頭來表明圖像變暗的方向:

 

 

若是你對這個圖像中的每一個像素都重複這個過程,最後每一個像素,最終每一個像素會被一個箭頭取代。這些箭頭被稱爲梯度(gradients),它們能顯示出圖像上從明亮到黑暗的流動過程:

 

 

這看起來沒有明確的目的,但其實這頗有必要。若是咱們直接分析像素,同一我的明暗不一樣的兩張照片將具備徹底不一樣的像素值。可是若是隻考慮亮度變化方向(direction)的話,明暗圖像將會有一樣的結果。這使得問題變得更容易解決!

 

可是保存每一個像素的梯度太過細節化了,咱們最終頗有可能撿了芝麻丟了西瓜。若是能從更高的角度上觀察基本的明暗流動,咱們就能夠看出圖像的基本規律,這會比以前更好。

 

爲了作到這一點,咱們將圖像分割成一些 16×16 像素的小方塊。在每一個小方塊中,咱們將計算出每一個主方向上有多少個梯度(有多少指向上,指向右上,指向右等)。而後咱們將用指向性最強那個方向的箭頭來代替原來的那個小方塊。

 

最終的結果是,咱們把原始圖像轉換成了一個很是簡單的表達形式,這種表達形式能夠用一種簡單的方式來捕獲面部的基本結構:

 

原始圖像被表示成了 HOG 形式,以捕獲圖像的主要特徵,不管圖像明暗度如何。

 

爲了在這個 HOG 圖像中找到臉部,咱們要所須要作的,就是找到咱們的圖像中,與已知的一些 HOG 圖案中,看起來最類似的部分。這些 HOG 圖案都是從其餘面部訓練數據中提取出來的:

 

使用這種技術,咱們如今能夠輕鬆地在任何圖片中找到臉部:

 

 

 

若是你想用 Python 和 dlib 親手試試看,這些代碼顯示瞭如何生成和查看 HOG 圖像。

 

第二步:臉部的不一樣姿式和方位

 

噹噹噹,咱們把圖片中的臉部分離出來了。 但如今,咱們要處理的問題就是,對於電腦來講,面朝不一樣方向的同一張臉是兩我的:

人類能夠很輕鬆地識別出到兩個圖片都是同一我的,但電腦會認爲這兩張圖片是兩個徹底不一樣的人。

 

爲了解決這一點,咱們將試圖扭曲每一個圖片,使得眼睛和嘴脣老是在圖像中的樣本位置(sample place)。 這將使咱們在接下來的步驟中,更容易比較臉部之間的不一樣。

 

爲此,咱們將使用一種稱爲面部特徵點估計(face landmark estimation)的算法。 不少方法均可以作到這一點,但此次咱們會使用由 瓦希德·卡奇米(Vahid Kazemi)和約瑟菲娜·沙利文(Josephine Sullivan)在 2014 年發明的方法

 

基本思路是找到 68 我的臉上廣泛存在的特徵點( landmarks)——包括下巴的頂部、每隻眼睛的外部輪廓、每條眉毛的內部輪廓等。接下來咱們訓練一個機器學習算法,讓它可以在任何臉部找到這 68 個特定的點:

 

 

咱們將在每一張臉上定位的 68 個特徵點。這張圖片的做者是在OpenFace工做的卡內基梅隆大學 Ph.D. 布蘭東·阿莫斯(Brandon Amos)。

 

這是在測試圖片上定位 68 個特徵點的結果:

 

你也可使用這一技術來實現本身的 Snapchat 實時 3D 臉部過濾器!

 

如今,咱們知道了眼睛和嘴巴在哪兒,咱們將圖像進行旋轉、縮放和錯切,使得眼睛和嘴巴儘量靠近中心。咱們不會作任何花哨的三維扭曲,由於這會讓圖像失真。咱們只會使用那些可以保持圖片相對平行的基本圖像變換,例如旋轉和縮放(稱爲仿射變換):

 

如今不管人臉朝向哪邊,咱們都能將眼睛和嘴巴向中間挪動到大體相同的位置。這將使咱們的下一步更加準確。

 

若是你想用 Python 和 dlib 親手試試看這一步的話,這裏有一些代碼幫你尋找臉部特徵點並用這些特徵點完成圖像變形

 

第三步:給臉部編碼

 

如今咱們要面臨最核心的問題了——準確識別不一樣的人臉。這纔是這件事的有趣之處!

 

最簡單的人臉識別方法,是把咱們在第二步中發現的未知人臉,與咱們已經標註了的人臉圖片做比較。當咱們發現未知的面孔與一個之前標註過的面孔看起來及其類似的時候,它確定是同一我的。這個想看起來很完美,對吧?

 

實際上這種方法有一個巨大的問題。像 Facebook 這種擁有數十億用戶和數萬億張照片的網站,是不可能去循環比較每張先前標記的臉的,這太浪費時間了。他們須要在毫秒內識別人臉,而不是幾個小時。

 

咱們須要的方法是從每張人臉上提取一些基本的測量數值。而後,咱們能夠用一樣的方式測量未知的面孔,並找到最接近測量數值的那張已知的臉。例如,咱們能夠測量每一個耳朵的大小、眼距、鼻子的長度等。若是你曾經看過像《犯罪現場調查》這樣的電視劇,你就知道我在說什麼了。

 

 

測量面部的最可靠方法

 

好的,因此爲了創建咱們的已知臉部數據庫呢,咱們應該測量面部的哪些數值?耳朵的大小?鼻子的長度?眼睛的顏色?還有什麼?

 

事實證實,對於咱們人類來講一些顯而易見的測量值(好比眼睛顏色),對計算機來講沒什麼意義。研究人員發現,最準確的方法是讓計算機本身找出它要收集的測量值。深度學習在尋找哪些部分的測量值比較重要方面表現的比人類更好。

 

因此,解決方案是訓練一個深度卷積神經網絡。可是,並非讓它去識別圖片中的物體,這一次咱們的訓練是要讓它爲臉部生成 128 個測量值。

 

每次訓練要觀察三個不一樣的臉部圖像:

 

1. 加載一張已知的人的面部訓練圖像

 

2. 加載同一我的的另外一張照片

 

3. 加載另一我的的照片

 

而後,算法查看它本身爲這三個圖片生成的測量值。再而後,稍微調整神經網絡,以確保第一張和第二張生成的測量值接近,而第二張和第三張生成的測量值略有不一樣。

 

 

在爲幾千我的的數百萬圖像重複該步驟幾百萬次以後,神經網絡學習瞭如何可靠地爲每一個人生成 128 個測量值。對於同一我的的任何十張不一樣的照片,它都應該給出大體相同的測量值。

 

機器學習專業人士把每張臉的 128 個測量值稱爲一個嵌入(embedding)。將複雜的原始數據(如圖片)縮減爲可由計算機生成的一個數列的方法,在機器學習(特別是語言翻譯)中出現了不少次。咱們正在使用的這種臉部提取方法是由 Google 的研究人員在 2015 年發明的,但也有許多相似方法存在。

 

給咱們的臉部圖像編碼

 

這個經過訓練卷積神經網絡來輸出臉部嵌入的過程,須要大量的數據和強大的計算能力。即便使用昂貴的 Nvidia Telsa 顯卡,你也須要大約 24 小時的連續訓練,才能得到良好的準確性。

 

但一旦網絡訓練完成,它就能夠爲每一張臉生成測量值,即便以前它從未見過這張臉!因此這種訓練只需一次便可。幸運的是,OpenFace 上面的大牛已經作完了這些,而且他們發佈了幾個訓練過能夠直接使用的網絡。謝謝Brandon Amos他的團隊!

 

因此咱們須要作的,就是經過他們預訓練的網絡來處理咱們的臉部圖像,以得到 128 個測量值。這是咱們測試圖像的一些測量值:

 

 

那麼,這 128 個數字到底測量了臉部的哪些部分?咱們固然不知道,可是這對咱們並不重要。咱們關心的是,當看到同一我的兩張不一樣的圖片時,咱們的網絡能獲得幾乎相同的數值。

 

若是你想本身嘗試這個步驟,OpenFace 提供了一個 lua 腳本,它能夠生成一個文件夾中全部圖像的嵌入,並將它們寫入 csv 文件。點此查看如何運行

 

第四步:從編碼中找出人的名字

 

最後這一步其實是整個過程當中最簡單的一步。咱們要作的就是找到數據庫中,與咱們的測試圖像的測量值最接近的那我的。

 

你能夠經過任何基本的機器學習分類算法來達成這一目標。咱們並不須要太花哨的深度學習技巧。咱們將使用一個簡單的線性 SVM 分類器,但實際上還有不少其餘的分類算法可使用。

 

咱們須要作的是訓練一個分類器,它能夠從一個新的測試圖像中獲取測量結果,並找出最匹配的那我的。分類器運行一次只須要幾毫秒,分類器的結果就是人的名字!

 

因此讓咱們試一下咱們的系統。首先,我使用Will Ferrell, Chad Smith and Jimmy Falon三人每人 20 張照片的嵌入來訓練分類器:

 

嗯……就是這些訓練數據!

 

接下來,我在這個分類器上運行了威爾·法瑞爾和查德·史密斯在吉米·法倫的節目上互相模仿的那個視頻的每一幀:

 

https://cdn-images-1.medium.com/max/800/1*_GNyjR3JlPoS9grtIVmKFQ.gif

 

結果成功了!不一樣角度的臉部,甚至是側臉,它都能捕捉到!

 

本身動手作一遍

 

讓咱們回顧一下咱們的步驟:

 

1. 使用 HOG 算法給圖片編碼,以建立圖片的簡化版本。使用這個簡化的圖像,找到其中看起來最像通用 HOG 面部編碼的部分。

 

2. 經過找到臉上的主要特徵點,找出臉部的姿式。一旦咱們找到這些特徵點,就利用它們把圖像扭曲,使眼睛和嘴巴居中。

 

3. 把上一步獲得的面部圖像放入神經網絡中,神經網絡知道如何找到 128 個特徵測量值。保存這 128 個測量值。

 

4. 看看咱們過去已經測量過的全部臉部,找出哪一個人的測量值和咱們要測量的面部最接近。這就是你要找的人!

 

如今你知道這一切都是如何運行的了,這裏是如何使用 OpenFace 在你本身的電腦上運行整我的臉識別系統的說明:

 

開始以前

 

確保你已經安裝了 python、OpenFace 和 dlib。你也能夠在這裏手動安裝,或者使用一個已經設定好的 docker image:

 

docker pull
bamos/openface
docker run -p 9000:9000
-p 8000:8000 -t -i bamos/openface /bin/bash
cd /root/openface

 

友情提示:若是你正在 OSX 上使用 Docker,你能夠這樣使你的 OSX /Users/

文件夾在 docker image 中可見:

 

docker run -v /Users:/host/Users -p 9000:9000 -p
8000:8000 -t -i bamos/openface /bin/bash
cd /root/openface

 

而後你就能訪問你在 docker image 中 /host/Users/...的 OSX 文件

 

ls /host/Users/

 

第一步

在 openface 文件中創建一個名爲 ./training-images/ 的文件夾。

 

mkdir training-images

 

第二步

爲你想識別的每一個人創建一個子文件夾。例如:

 

mkdir ./training-images/will-ferrell/
mkdir ./training-images/chad-smith/
mkdir ./training-images/jimmy-fallon/

 

第三步

將每一個人的全部圖像複製進對應的子文件夾。確保每張圖像上只出現一張臉。不須要裁剪臉部周圍的區域。OpenFace 會本身裁剪。

第四步

從 openface 的根目錄中運行這個openface 腳本。

首先,進行姿式檢測和校準:


./util/align-dlib.py
./training-images/ align outerEyesAndNose ./aligned-images/ --size 96

 

這將建立一個名爲./aligned-images/的子文件夾,裏面是每個測試圖像裁剪過、而且對齊的版本。

其次,從對齊的圖像中生成特徵文件:


./batch-represent/main.lua
-outDir ./generated-embeddings/ -data ./aligned-images/

運行完後,這個./generated-embeddings/子文件夾會包含一個帶有每張圖像嵌入的 csv 文件。

第三,訓練你的面部檢測模型:

./demos/classifier.py
train ./generated-embeddings/

 

這將生成一個名爲 ./generated-embeddings/classifier.pkl的新文件,其中包含了你用來識別新面孔的 SVM 模型。

到這一步爲止,你應該有了一個可用的人臉識別器!

 

第五步:識別面孔!

 

獲取一個未知臉孔的新照片,而後像這樣把它傳遞入分類器腳本中:

 

./demos/classifier.py
infer ./generated-embeddings/classifier.pkl your_test_image.jpg

你應該會獲得像這樣的一個預測:

 

===/test-images/will-ferrel-1.jpg ===
Predict will-ferrell with 0.73 confidence.

 

至此,你已經完成了一個預測了。你也能夠修改./demos/classifier.py 這個 python 腳本,來讓它匹配其餘人的臉。

重要提示:

 

  • 若是你獲得的結果不夠理想,試着在第三步爲每一個人添加更多照片(特別是不一樣姿式的照片)。
  • 即便徹底不知道這個面孔是誰,如今這個腳本仍然會給出預測。在真實應用中,低可信度(low confidence)的預測可能會被直接捨棄,由於頗有可能它們就是錯的。
 
via medium.com
相關文章
相關標籤/搜索