用Python和深度學習實現iPhone X的Face ID

景略集智發表於2019-02-26

去年蘋果的最新產品 iPhone X 最受熱議的莫過於全新的解鎖功能——取代了 TouchID 的FaceID。

Apple 已經制造出了全面屏手機(雖然是備受吐槽和跟風的“劉海屏”),因此也得開發出與之對應能簡單迅速地解鎖手機的方法。

用Python和深度學習實現iPhone X的Face ID

正當 Apple 的競爭者們還在調整指紋感測器的位置時,Apple 革新了手機解鎖方式——你只需要看著手機就可以了。通過一個小巧先進的前置深度攝像頭,iPhone X 可以建立一張使用者臉部的 3D 影象。此外,紅外攝像頭也會拍攝一張使用者臉部的照片以適應不同環境下光線和顏色的變化。通過深度學習,手機可以學習使用者的臉部,並在每次使用者舉起手機時辨識出來。令人驚訝的是,Apple 宣稱這項技術比 TouchID 更加安全,其錯誤率僅有百萬分之一。

用Python和深度學習實現iPhone X的Face ID

隨著蘋果手機推出的這項革命性技術,市面上也出現了越來越多的採用人臉解鎖技術的手機,面部解鎖儼然成為新的技術潮流。

用Python和深度學習實現iPhone X的Face ID

那麼 iPhone X 的 FaceID 背後都有哪些祕密?作為普通的開發者,我們自己能實現它嗎?羅馬大學人工智慧專業的一位叫 Norman Di Palo 的小夥最近就不斷琢磨了這個問題,最後經過一番探索後,藉助深度學習技術和 Python 程式設計,逆向破解了這項技術。下面我們聽他嘮嘮怎麼做到的。


我(作者Norman Di Palo——譯者注)對 Apple 實現 FaceID 的技術十分感興趣——一切都是在裝置上執行的,被使用者臉部稍微訓練一下就能在每次手機被舉起時順利地執行了。

我的關注點在於,怎樣利用深度學習實現這個過程以及如何優化每個步驟。在本文,我將展示如何使用 Keras 實現類似 FaceID 的演算法。我會詳細解釋我作出的各種架構決策並展示最終的實驗結果。我使用了 Kinect,一個很流行的 RGB 和深度攝像頭,它輸出的結果和 iPhone X 上的前置攝像頭很相似,只是裝置體積要大一些。倒杯茶坐下來歇會兒,下面我們一起逆向破解 Apple 改變行業趨勢的這項新功能。

用Python和深度學習實現iPhone X的Face ID

理解FaceID

用Python和深度學習實現iPhone X的Face ID

第一步是分析 FaceID 是怎樣在 iPhone X 上工作的。iPhone X 的白皮書可以幫助我們理解 FaceID 的基本工作原理。使用 TouchID 的時候,使用者需要先數次觸碰感測器以記錄指紋。 15 到 20 次觸碰後,TouchID 就設定完成了。FaceID 也類似,使用者需要先錄入面部資料。過程很簡單:使用者只需和平時一樣正向看著手機,之後緩慢轉動頭部以完成全方位採集。

就這麼簡單,FaceID 已經設定好,可以用來解鎖手機了。錄入過程的驚人速度可以告訴我們很多關於其背後演算法的資訊。比如,驅動 FaceID 的神經網路並不是只是在進行分類,我接下來會進一步解釋。

用Python和深度學習實現iPhone X的Face ID

對一個神經網路來說,分類意味著學習預測它看到的臉是否是使用者的。因此,簡單來說,它需要利用訓練資料預測“是”或“否”。但和其他很多深度學習用例不同,這個方法在這裡行不通。首先,神經網路需要用從使用者面部新獲得的資料從頭開始訓練模型,這需要大量的時間、計算資源和不同的人臉作為訓練資料以獲得反例(在遷移學習和對一個已經訓練好的網路進行微調的情況下,變化是很小的)。

不僅如此,這種方法使 Apple 無法“離線”訓練一個更為複雜的網路,比如先在實驗室裡訓練網路,再把訓練好的、可以直接使用的網路放到手機裡。因此,我認為 FaceID 是利用了一個被 Apple“離線”訓練好的類似孿生網路的卷積神經網路,將人臉對映到低維的潛在空間,再利用對比損失將不同人臉的距離最大化。這樣,你就得到了一個可以進行一次性學習的架構,Apple 的 Keynote 裡簡要提到了這一點。我知道,可能有些看官會對很多名詞感到陌生;別急,繼續讀下去,我會一步步解釋的。

用Python和深度學習實現iPhone X的Face ID

神經網路:從人臉到數字

孿生神經網路是由兩個相同的神經網路組成的,這兩個網路的權重也完全一樣。這個架構可以計算特定的資料型別之間的距離,比如影象。你讓資料通過孿生網路(或者分兩步讓資料通過同一個網路),網路就會將其對映到一個低維的特徵空間,比如一個n維的陣列,你再訓練網路,使對映能夠讓不同類別的資料離得越遠越好,相同類別的資料離得越近越好。長期來看,神經網路會學著提取最有意義的特徵,將其壓縮成一個陣列,並建立一個有意義的對映。為了能更直觀的理解,想象你需要用一個很小的向量來描述狗的品種,這樣相似的狗的向量會更相近。你也許會用一個值表示狗的皮毛顏色,一個值表示狗的體型大小,另一個值表示毛髮長度,等等。這樣,相似的狗就會有相似的向量。很聰明,不是嗎?孿生神經網路就可以替你做這件事,就像一個自編碼器。

用Python和深度學習實現iPhone X的Face ID

上面這幅圖出自 Yann LeCun 參與發表的一篇論文,神經網路可以學習數字之間的相似性,並以 2 維為它們自動分類。這樣的技術也可以應用到人臉資料上。

利用這個技術,我們可以利用大量的人臉訓練出一個可以識別相似人臉的架構。只要有足夠的預算和算力(就像 Apple 這樣),神經網路的魯棒性可以變得越來越強,可以處理雙胞胎、對抗攻擊等更困難的樣本。這個方法的最後一個優點是什麼呢?就是你有了一個即插即用的模型,它不需要進一步訓練,只要在一開始錄入時拍幾張照片,計算出使用者的臉在隱對映中的位置,就可以識別不同使用者。(想象一下,像剛才說的那樣,為一隻新的狗建立代表它品種的向量,再把它儲存到什麼地方)此外,FaceID 可以在使用者這一方適應眼鏡、帽子、化妝等突然變化和麵部毛髮這樣的緩慢變化——只需要在對映中新增參考的面部向量,再根據新的外貌進行計算。

用Python和深度學習實現iPhone X的Face ID

用 Keras 實現 FaceID

對於所有的機器學習專案來說,首先需要的就是資料。建立我們自己的資料集需要時間和很多人的合作,是比較有挑戰的。因此,我在網上找到了一個看起來很合適的 RGB-D 人臉資料集。這個資料集由一系列人們面朝不同方向,做出不同表情的 RGB-D 圖片組成,就像 iPhone X 的用例一樣。

如果想看到最後的實現,可以去我的 Github 庫,裡面有一個Jupyter Notebook

另外,我在Colab Notebook也實驗過,你可以試試看。

我基於 SqueezeNet 建立了一個卷積神經網路,輸入是 RGB-D 人臉影象,即 4 通道影象,輸出是兩個巢狀之間的距離。神經網路是根據對比損失函式訓練的,以減小同一個人的影象之間的距離,加大不同人的影象之間的距離。

用Python和深度學習實現iPhone X的Face ID

圖為損失對比函式。

經過一些訓練,神經網路能夠把人臉對映為 128 維的陣列,這樣同一個人的影象會組在一起,並遠離其他人的影象。這意味著,解鎖的時候,神經網路只需要計算解鎖時拍下的照片和錄入時儲存下來的照片的距離。如果這個距離低於某個閾值(閾值越小越安全),裝置就解鎖。

我利用 T-分佈隨機近鄰嵌入將 128 維的巢狀空間在 2 維空間視覺化。每個顏色代表了一個人:如你所見,神經網路學會了把這些照片緊密的組在一起。(在使用 T-分佈隨機近鄰嵌入的情況下,叢集之間的距離是無意義的)使用 PCA 降維演算法時也會出現很有意思的影象。

用Python和深度學習實現iPhone X的Face ID

圖為用t-SNE建立的巢狀空間中的人臉照片群集。

用Python和深度學習實現iPhone X的Face ID

圖為用PCA建立的巢狀空間中的人臉照片群集。

實驗!啟動!

我們現在可以模擬一個 FaceID 的迴圈,來看看這個模型執行得怎麼樣了:首先,錄入使用者的臉;之後是解鎖,使用者的臉應當可以成功解鎖裝置而其他人的臉則不行。如前所述,區別在於神經網路計算出來的試圖解鎖裝置的臉和錄入時的臉的距離是否小於某一個閾值。

我們先從錄入開始:我從資料庫中提取了一系列同一個人的照片並模擬了設定面部識別的過程。裝置會計算每個姿態的巢狀,並儲存在本地。

用Python和深度學習實現iPhone X的Face ID

圖為模擬FaceID錄入人臉資料。

用Python和深度學習實現iPhone X的Face ID

圖為深度攝像頭看到的人臉資料錄入過程。

當同一個使用者試圖解鎖裝置時,同一個使用者的不同姿態和表情的距離較低,平均大概在 0.3 左右。

用Python和深度學習實現iPhone X的Face ID

圖為巢狀空間中同一人物的臉部距離

而不同人的 RGB-D 影象的距離則平均有 1.1。

用Python和深度學習實現iPhone X的Face ID

圖為巢狀空間中不同人物的臉部距離

因此,將閾值設定在 0.4 左右就可以防止陌生人解鎖你的裝置了。

結語

在這篇博文中,我基於人臉巢狀和孿生卷積神經網路,藉助 Keras 和 Python 實現了 FaceID 人臉解鎖的概念驗證。希望本文對你有所幫助和啟發,相關的 Python 程式碼你也都可以在這裡找到。

對於本文所用的 Keras 工具及其提供有哪些深度神經網路模組,可以看看我站的簡明教程

相關文章