海量人臉特徵檢索解決方案演進之路

1. 概述

clipboard.png

  人臉識別技術在最近幾年獲得了長足進步,目前在人臉識別領域業界領先的廠家識別準確率均達到了99%以上,所以大量人臉相關的應用場景開始逐步落地,例如人臉支付、人員布控、尋找失蹤人口等,此外,結合人臉的追蹤技術,也開始出現了分析人流走向、分析景點旅客行走規律、人員行爲偏好分析等。這些應用雖然表現形式多樣,但最終都是基於人臉特徵檢索這一技術實現的。算法

clipboard.png

  首先介紹一下人臉特徵是什麼。目前圖像識別算法可以在一張照片中發現人臉,並可以對人臉中的輪廓進行識別和標記,算法使用這些標記點構造出表示該張人臉的特徵的矩陣,這個過程稱爲人臉特徵提取,獲得的矩陣稱爲人臉特徵矩陣,在工程上,特徵矩陣通常以一維矩陣表示,以二進制數組的方式進行存儲。後端

clipboard.png

  當須要確認兩張人臉照片是否同一我的時,能夠經過上述公式計算這兩張人臉的特徵矩陣之間的類似度,以此做爲兩我的臉的類似度,當類似度超過必定閾值時,就認爲是同一我的,該閾值是經驗值,不一樣廠家的特徵提取算法不一樣,獲得的經驗值也會不一樣。提升閾值,會提升準確率(認爲是同一我的的狀況下判斷正確的佔比),但會下降查全率(能匹配到的人臉在人臉庫中所有匹配人臉的佔比)。所以在不一樣的應用場景下,因爲準確率和查全率的權重不一樣,致使了閾值也會不一樣。如在尋找失蹤人口的場景,是寧肯找錯也不該放過的,閾值就會相應調低,讓更多類似的人臉能被看到;在人臉支付場景,準確率是最重要的,那麼閾值相應就會較高,固然也會致使匹配失敗的次數增多。數組

  把大量人臉特徵集中存儲可造成特徵庫,若要判斷一我的在不在這個特徵庫中,只須要拿這我的的人臉照片對應的人臉特徵,跟特徵庫裏每一個特徵計算類似度,把類似度超過閾值的特徵對應的照片找出便可。經過一個特徵來比對一個特徵庫的場景,每每稱爲人臉1:N比對,與之對應的兩個特徵庫之間的比對,每每稱爲人臉M:N比對。緩存

  算法場景一般會提供以下的M:N比對接口:安全

clipboard.png

  接口實現兩個特徵庫之間的比對,如上圖中4個特徵的庫和3個特徵的庫的比對,可獲得12個類似度。當要實現1:N時,只需讓其中一個特徵庫只包含一個特徵便可。此前基於E5-2640V3 CPU(16物理核)實測1:N,每秒可實現1.5億對特徵比對。通常經過C++調用該接口完成比對。性能優化

2. 性能指標要求

clipboard.png

clipboard.png

  在今年某地市的項目中,系統從一萬多人臉攝像機中採集人臉抓拍圖片進行特徵提取後造成特徵庫,業務層須要實現人臉檢索功能。其中數據規模爲:天天約2000萬張人臉抓拍圖,圖片平均約30KB,人臉特徵約600字節,即每個月6億個特徵,每個月特徵庫單副本約佔用350GB空間,數據須要存儲1年,人臉檢索要求1:1億在3秒內響應,須要支持10個併發,須要支持根據時間、攝像機編號、類似度閾值來過濾人臉。服務器

  固然這是在最近才提出的性能指標要求,兩年前,在人臉相關項目尚未大面積落地時,對人臉檢索的性能指標要求還在千萬級如下的人臉比對,並且只需支持1-3個併發,但也因爲當時沒有可參考的案例,業務場景處於摸索階段,所以在人臉檢索上須要支持更豐富的檢索條件,如除了時間和攝像機編號外,還須要支持根據性別、年齡段、是否戴帽子、是否戴眼鏡等條件過濾數據。網絡

  下面將從最簡單的方案講起,逐步推動到支持千萬級、億級人臉比對的方案,讓你們對方案的演進有個總體的瞭解。併發

3. 解決方案演進

3.1 人臉動態庫方案

clipboard.png

  在內部驗證階段,使用單機存儲固定特徵個數(多是一千萬個)的特徵庫,每一個特徵對應記錄ID、時間戳、攝像機編號等信息。天天新增的特徵造成一個單獨的小特徵庫,天天定時把小特徵庫合併到大特徵庫,並把大特徵庫中最舊的同量特徵刪除,保持特徵庫的大小。在檢索時先對全庫進行1:N,根據閾值過濾出部分記錄後,再抽取對應記錄的額外信息,與頁面檢索條件進行匹配,返回結果。負載均衡

優勢:因爲是單機系統,方案實現和維護都比較簡單
缺點:單機支持的特徵數量有限,沒法橫向擴展,檢索併發度低,過濾條件沒法靈活變化

3.2 ES分佈式人臉檢索方案

  因爲業務之初並不清楚實際應用場景中哪些檢索條件是用戶離不開的,只有在不斷的實踐迭代中摸索真正能落地的使用方式,所以豐富、靈活的檢索條件在當時是相對重要的。考慮現已用戶的檢索條件過濾數據後造成特徵庫,再用待搜索的人臉跟特徵庫作1:N。所以第一步須要使用可以支持靈活搜索,而且搜索性能極佳的引擎,基於公司技術棧和業界經常使用的搜索引擎考慮,最終敲定爲ElasticSearch搜索引擎。

  ES沒有提供查詢後在服務端對結果進行二次處理的接口,而且其源碼中寫死了最多隻可返回5000條記錄,若根據搜索條件過濾出來的人臉在百萬級,按照源生接口,就算改大了返回記錄數的限制,也只能是先匯聚到客戶端,而後由客戶端在本地作1:N。這會致使ES和客戶端之間的帶寬佔用太高,而且單單是網絡傳輸也要耗費很多時間。

  固然,客戶端能夠跟ES Node部署在一塊兒,由客戶端提供人臉檢索服務,應用端請求時,客戶端直接對本機的ES Node發起請求,彙總的人臉在本機內部拷貝,可避免網絡傳輸的問題。可是依舊存在以下問題:
  1)ES對檢索結果是組裝爲List對象再處理後返回到客戶端的,對內存消耗較大;
  2)客戶端獲取檢索結果仍是經過網卡,雖然服務器內部傳輸避免了帶寬損耗,但內存拷貝是免不了的;
  3)ES端檢索時須要彙總所有匹配的結果到查詢節點,這部分的帶寬是免不了的;
  4)檢索性能受限於單機性能,沒法橫向擴展。

clipboard.png

  爲了不上面的問題,最好就能在每一個ES Node內部檢索到特徵數據後,把造成List的過程變爲直接寫到事先分配好的堆外內存ByteBuffer中,緊接着經過JNI的方式調用本機的C++接口,傳入ByteBuffer內存塊地址,直接在本機完成1:N比對,而後才把比對結果包裝爲ES Node響應對象返回到ES查詢節點,在查詢節點內部完成類似度的排序和取TopN操做,最終返回給客戶端。這個過程如上圖所示,其中爲了使線看起來沒那麼多,C++ 1:N的結果返回到ES Node的箭頭只在一臺服務器上畫了,實際上其餘服務器一樣有這樣的箭頭。

優勢:
1)不須要造成List對象,直接在本機造成內存塊,節省了內存,也減小了內存拷貝;
2)1:N是每一個節點並行作的,僅返回類似度超過閾值的記錄到查詢節點,帶寬消耗極小,查詢節點處理幾乎不耗時間,所以可橫向擴展;
3)ES自身提供了副本和查詢負載均衡機制,大大節省了運維和接口開發工做量;
4)能支持幾乎所有的ES檢索功能,查詢條件靈活,頁面可隨時修改檢索條件而不須要修改後端實現代碼。
缺點:
1)須要爲ES增長一種查詢類型,實如今Node中檢索後直接寫ByteBuffer和調用C++接口作1:N的邏輯,須要深度修改ES源碼;
2)因爲是經過JNI調用C++接口,若C++程序異常了,會直接致使ES Node的JVM掛掉。

  可是也應注意到該方案並不能避免從ES的Share拷貝記錄到ByteBuffer。因爲進行人臉比對所需讀取的記錄數每每在百萬級以上,若這些記錄不在系統緩存中,就會致使須要到磁盤隨機讀取數據,IO消耗嚴重。實測單機使用7200轉普通硬盤而且沒有系統緩存的狀況下,要在ES中隨機加載100萬條記錄,須要約60s-80s,而實際應用場景中,須要比對的人臉數據每每大多不在緩存中,所以須要優化從Share拷貝記錄到ByteBuffer的過程。

clipboard.png

  當時採用了以下方案(簡稱內存ES方案):
  單機上啓動2個ES進程,一個ES進程的數據目錄設置在硬盤中,另一個ES進程的數據目錄設置在使用tmpfs在內存中模擬的內存文件系統中,N臺服務器共2*N個ES進程組成集羣。關閉ES的自動分配和自動平分片功能,按月建立人臉Index,每一個Index設置3個副本,3個副本中其中一個分配到使用內存文件系統的ES進程中,另外兩個副本分配到其餘服務器上使用磁盤存儲的ES進程中,建立Index的操做專門開發工具實現。對於人臉比對檢索請求,修改客戶端選擇分片的邏輯爲優先檢索使用內存存儲的ES分片(經過節點名稱約定實現),只有當內存存儲的ES分片異常時才選用磁盤存儲的分片。具體實施如上圖所示。

  在內存文件系統中的分片在檢索時,從Share拷貝記錄到ByteBuffer就變成了從內存拷貝到內存,避免了磁盤IO,大大提升了性能。可是內存拷貝雖然快,但也只是針對大塊數據而言的,從Share中讀取數據是隨機讀取,通過實際測試發現,單機從存儲在內存文件系統的Share中讀取記錄的速度上限約爲250萬條/秒。也就是說,若是要求單併發對1千萬人臉作比對在1秒內響應,不算其餘步驟耗時的狀況下,至少也要4臺服務器才能支撐。

  因爲該集羣專門用來作人臉檢索,所以Index中只包含檢索條件字段和特徵字段,與另外的一個包含完整字段的集羣(簡稱全量ES集羣)進行數據同步,數據採集網關把數據同時發往這兩個ES集羣中。在發生宕機狀況時,內存中的數據會所有丟失,所以須要在啓動服務器以後,經過專門的運維工具把本來在該服務器上的分片建立出來,並等待其餘節點中的磁盤分片自動同步數據。

缺點:
1)運維很是麻煩,內存ES集羣異常恢復時每每須要讀取大量數據,嚴重拖慢ES性能;
2)由於須要把1/3的分片數放到內存文件系統中,所以須要消耗大量內存,對於128GB內存的服務器,最多隻能劃分40GB內存來存放分片,由於ES自身的正常運行也須要消耗大量內存,這就使得單機可存儲的數據量極少,若是按前面所說的天天2000萬個特徵1個月單單是特徵就要350GB內存,那就須要9臺128GB內存的服務器才能放得下;
3)爲了令人臉比對不影響普通查詢的性能,全量ES集羣和內存ES集羣應部署到不一樣的服務器組上,這樣無形中又須要消耗更多的服務器;
4)單機內存拷貝速度依然較慢,須要大量服務器才能支撐大規模的人臉比對;
5)ES自身在對單個字段進行多值匹配時,耗時呈現指數型增加趨勢,當匹配值個數超過100時,單單是該字段的匹配耗時就在秒級耗時了,而實際場景中用戶每每會選擇大量的攝像機來進行檢索,這樣會嚴重拉低ES檢索性能。

3.3 基於RocksDB的分佈式特徵索引方案

clipboard.png

  隨着應用場景的逐漸清晰和對人臉識別到的其餘特徵準確度的認識,發現實際在使用人臉檢索功能時,其實基本只會使用時間段+攝像機編號+人臉照片這三個條件來檢索人臉,所以靈活的檢索條件這一項變得不那麼重要了。此外,實踐中發現ES方案在作人臉檢索時,其實絕大多數耗時集中在根據條件進行搜索和從Share中拷貝數據造成特徵庫這兩步,真正進行1:N消耗的時間幾乎可忽略不計。

  前面提到,基於高性能CPU能實現1秒完成1:1.5億的比對,假設這樣的場景:用戶須要檢索24小時範圍裏所有攝像機抓拍的人臉裏是否出現了某個性別爲男性的人。按照天天2000萬特徵來算,假設這24小時裏性別爲男性的記錄是1000萬,ES方案中加載1000萬特徵須要4秒,1:1000萬須要0.066秒,不算其餘耗時則總耗時約爲4.066秒;若先不過性別條件,用24小時所有的人臉比對完後,以超過閾值的記錄去判斷是否男性,則1:2000萬須要0.133秒,超過閾值的幾百我的臉再去判斷性別假設須要0.5秒,則總耗時約爲0.633秒。須要檢索的時間範圍越長,則性能差別越大。

  所以,關鍵須要有一個能先根據時間段+攝像機編號初步過濾特徵庫的引擎,先進行人臉比對,而後再作條件匹配。其實這更像是方案一的升級版。具體方案如上圖所示。持久化存儲使用RocksDB,引擎啓動後會在內存中緩存必定時間段的全量特徵庫用於人臉比對,數據以<小時, 攝像機編號>做爲爲索引對特徵數據分塊存儲,相同索引的數據平均分佈在多臺機器上(即數據寫入時對於相同索引的數據集,按照節點數均分,發往所有的節點上),實時寫入時內存庫和RocksDB雙寫。此外還實現了數據副本機制。

  選擇RocksDB的緣由:在本方案中因爲數據寫入是雙寫,引擎的主要壓力在數據寫盤,RocksDB採用LSM樹存儲引擎,數據寫入性能較好,提供了索引機制,而且提供了C++訪問接口,能大大下降開發難度。

  在上圖的數據中,假設檢索時間範圍2018-01-01 06:00:00到2018-01-01 06:30:00,攝像機編號爲4401150002的人臉,則定位到每一個節點的紅色內存塊(以下圖所示),所有節點並行比對人臉,以下圖所示,最終彙總到接收查詢請求的節點。

clipboard.png

  文章開頭所說的人臉檢索要求1:1億在3秒內響應,須要支持10個併發性能指標,換算下來是要達到1:3.333億秒內響應的效果,若按照單機1.5億/秒的比對速度,則至少須要3臺服務器。所以,本方案實際上已經可以知足性能指標要求,後面的3.4和3.5節介紹的方案是後續可能採用的方案,以應對將來可能的更大規模的人臉比對需求。

優勢:
1)支持橫向擴展。任意一個比對請求都會使用所有的服務器的資源進行比對,理論上服務器數量與比對性能成正比關係;
2)能有效利用內存資源,在實際實施時,每每能使用80%的內存用於特徵庫緩存,剩餘內存用於超出緩存時間範圍以外的臨時數據緩存;
3)比對可基於特徵庫緩存直接進行,實現內存零拷貝;
4)引擎是自研的,對於源碼徹底掌控,出了問題更容易解決。
缺點:
1)須要自研整套分佈式框架,實現內存管理和解決數據同步、一致性等問題。

3.4 基於小特徵加速比對的檢索方案

clipboard.png

  一些廠家除了提供前面所說的約600字節的人臉特徵外,還提供了50字節左右的小人臉特徵,使用了更少的特徵點來描述一張人臉。顯然,使用小特徵在判別兩我的臉是否同一我的時,準確率比大特徵低,但小特徵庫能提供更高的比對性能(由於計算量更小)。所以能夠經過小特徵庫來加速大特徵庫比對。

  因爲兩個特徵矩陣的類似度計算主要爲浮點運算,按照類似度計算公式,理論上特徵長度變爲原來的1/N,則單位時間比對次數變爲原來的N倍。也就是說,若600字節大特徵能作到1.5億條/秒的比對速度,則50字節的小特徵理論上能作到18億/秒的比對速度。

  具體方案見上圖。相比於3.3節方案,多出了小特徵內存塊,小特徵內存卡與大特徵內存卡一一對應,使用相同的索引來標識。在檢索人臉時,首先根據查詢條件定位小特徵內存塊,使用更低的類似度閾值進行人臉比對,根據匹配結果從對應的大特徵內存塊中抽取特徵組成大特徵庫(方法能夠是大小特徵塊按ID有序排列,這樣記錄順序是相同的,另外能夠是每一個特徵塊有單獨的ID索引,可快速定位行號),進行第二次人臉比對,第二次比對使用客戶端傳入的閾值。

  在該方案中,第一次比對後從大特徵庫取的數據量較少,但基本爲隨機讀取,所以能夠考慮使用固態硬盤來存儲大特徵塊以節省內存。

3.5 基於GPU優化的檢索方案

clipboard.png

  因爲特徵的比對主要是浮點運算,可考慮使用浮點運算能力更高的GPU來實現。在小特徵50字節狀況下,則8GB顯存約可存儲1.5億個特徵,按一天2000萬特徵計算,則8GB顯存可存儲7.5天數據,4張GPU卡則可存儲一個月數據,若N臺服務器上都插上4張GPU卡,則能夠實現N個月特徵的GPU比對提速效果。使用GPU後,還能帶來一個顯著的好處:更少的服務器,節省了機房空間。

  上圖中在3.4節方案的基礎上,增長了顯存存儲小特徵塊的部分。若是在顯存中存儲最近一個月的熱數據,在內存中存儲更舊日期的小特徵,當檢索條件只落在最近一個月時,只須要GPU就能完成小特徵的比對;若檢索條件涉及最近三個月,可在GPU中比對最近一個月的小特徵,同時在CPU中比對第二三個月的小特徵。在實際應用場景中,用戶絕大多數時間檢索的是最近一個月的數據,該方案能大大提升響應速度。

4 總結

  本文從需求和性能優化的角度,爲你們介紹了海量人臉特徵檢索場景解決方案的演進過程,能夠看到,不一樣的業務需求每每決定了具體的實現方案。能夠預見,當前人臉比對性能逐漸再也不是瓶頸,大量與人臉檢索相關的場景都可以得以實現。現在用戶已經不知足只能實現簡單的人臉檢索功能,他們但願能利用人臉比對的能力,實現諸如人羣聚類、人員歸檔、陌生人行爲分析等業務,這些業務最底層的邏輯是人臉聚類算法,即給出一個未知人員信息的特徵庫,算法根據裏面每一個人的兩兩類似度,把相同的人的照片歸到一類中,實現特徵集合的人員劃分。在公共安全領域,人員聚類將是下一個爆發的應用場景,值得你們關注。

相關文章
相關標籤/搜索