天天看點

人臉識别會議系統性能優化

簡介

姓名:徐新宇

細分場景:物聯網行業下移動app+人臉識别在工業安卓平闆的應用

(注:公司項目資訊脫敏,相關圖檔替換為網絡圖檔,本人無意侵犯版權,已表明相關出處)

一.項目背景

公司是一家物聯網公司,意向自研一款人臉會議考勤簽到面闆機,為了提高産品競争力,主打成本效益+定制化差異(硬體便宜好用,軟體頁面炫酷叼炸天);軟體研發部需要支撐配套的人臉會議考勤安卓平闆應用。主要業務功能有:人臉識别功能(人臉采集、對比識别、人臉庫管理),會議子產品,考勤簽到功能,定制化互動子產品。

人臉識别會議系統性能優化

人臉識别互動示意圖(圖檔來源谷歌圖檔)

(原頁面實作由識别定位框+骨骼輪廓圖+資訊卡片+動畫構成)

與硬體産品經理的溝通後,提供一套樣機和一套産品清單來支撐軟體研發的開發和測試。

主機闆是RK3288四核 1.8GHZ.2g記憶體。8G存儲的闆子,安卓5.1的作業系統。螢幕是15.6英寸 1920*1080分辨率 10點式電容觸摸屏。

人臉識别會議系統性能優化

 RK3288主機闆示意圖(圖檔來源谷歌圖檔)

人臉識别會議系統性能優化

RK3288主機闆核心參數

架構選型是使用的ReactNative+tracker.js

,考慮控制成本,沒有內建市面上的Android人臉識别SDK。通過經驗使用tracker.js替代opencv實作端的人臉識别捕捉,服務端實作人臉對比(這裡為後續的錯誤埋下了伏筆),經過一段時間加班加點,開發了人臉會議考勤系統V0.1-Alpha版。

采購流程是比較慢的,等到開發闆到了開始一輪真機測試運作,搞了一輪以後組員說束手無策,别的機子都好好的,就這個不行,懷疑硬體問題。

排除硬體原因後,我整體的牽頭開始對于系統進行性能優化。

1.人臉識别不流暢,人畫不同步,明顯延遲,人員高頻次出入鏡頭框會伴随頓挫感。

2.POE供電,長時間運作軟體運作發熱發燙。

3.機率偶發性閃退現象,捕捉不到有價值的異常日志。

1.沒有使用純安卓開發(組員基本不會安卓原生開發)+人臉識别安卓SDK(控制成本的訴求)。限制了性能的上限。

2.硬體性能低。RK3288處理器,搭載的Mali-T764GPU,在14年當年算是神U,被譽為國産最強ARM處理器,但是已經6、7年過去了,我們采用的也是基礎版。安卓闆人臉機還需要内置一些其他相關軟體,對性能和穩定性的要求還是比較高的。

3.機率性存在ANR/閃退崩潰問題,報錯模糊,定位不到問題。

4.組員整體為前端開發人員,對于app的優化和調試經驗不足。

二.解決問題的步驟

忠告,先不要盯着問題本身。尤其是對于性能問題,這是大忌。這是對于很多開發人員都容易犯的錯誤,甚者用精妙的技巧去掩蓋系統設計上的缺陷。(産品設計,架構設計,原型設計,互動設計,UI設計等等)

如果系統運作或者測試中出現了遠高于門檻值的問題,第一步一定是先回過頭來看系統的看設計。(一定是)

沒有經驗的程式員會一頭紮入bug中,富有經驗的程式員會利用自有的思維方式了解問題,定位問題,分析問題,解決問題,驗證問題。而作為一個合格的架構師,或者技術團隊的leader。一定要學會“揪頭發”思維。

很多系統需要優化的問題,往往并不僅僅是一個技術問題,根源上可能是一個不合理的産品設計,備援的架構,反人類的互動,層次過深的UI導緻的。而由于系統的複雜度和團隊的溝通成本以及後期需求變動與場景的細化,往往在項目初期有些問題是很難暴露的。是以對于軟體系統的性能優化,第一步要複盤之前的設計與行為是否合理。

而事實上,所謂的差異化設計,在通過梳理精簡,剔除掉不合理因素後,對于一個工業平闆app它的動畫和互動還是太複雜了。

本項目人臉檢測驗收标準:

包大小:~ 100M

最小人臉檢測大小:50px * 50px

可識别人臉角度:yaw ≤ ±30°, pitch ≤ ±30°

檢測速度:100ms 720p*

追蹤速度:50ms 720p*

人臉檢測耗時:< 200ms

人臉庫檢索速度:< 100ms

檢測+識别全流程耗時 < 500ms(app其他性能名額不做過多叙述)

工程化的一個要素就是用設定的标準去衡量離散型資料。如果優化沒有可量化的渲染性能評判标準,就是開發者\leader拍腦門決定了,是以不僅僅是測試人員需要了解這些名額,開發者也要學會使用測試工具去定位問題、驗證資料。

ok開始行動, Androidadb

網絡連接配接安卓主機闆測試,安裝apk。

打開安卓開發者模式,檢查

GPU 渲染速度和過度繪制,篩選出渲染壓力過大的頁面,

人臉識别會議系統性能優化

 GPU 渲染模式分析示意圖(圖檔來源百度)

人臉識别會議系統性能優化

渲染顔色說明

過度繪制:實際上對于過度繪制相關的優化,要考慮投入産出比,過于精細的優化整體産出是不高的,該項目中隻對于過度繪制紅色區域(過度繪制4次及以上區域)進行優化。

由于軟體伴有運作發熱發燙的現象,那麼一定要分析耗電情況。

耗電統計是系統元件,也就是說系統運作他就一直在統計。是以擷取統計報告的時候需要将統計重置。

1.先斷開adb服務,然後開啟adb服務

    殺死adb服務:執行adb kill-server 防止沖突和髒資料。

    重新開機adb: 執行adb devices或者adb start-server

2 .重置電池資料收集

adb shell dumpsys batterystats--enable full-wake-history

adb shell dumpsys batterystats--reset

正常情況下,我們應該斷開充電器并斷開usb連接配接(連接配接時充電),這樣會大大影響統計有效性。但是由于我們是poe供電,具體情況具體分析,使用資料輔助查找異常點。因為我們是5.1系統,是以使用adb指令:

人臉識别會議系統性能優化

由于txt報告實在是比較大,10幾個m肉眼看不太現實,一般都配合BatteryHistorian

這個工具來使用。

(注意:Battery Historian是android 5.0(api 21)及以上使用,如果有幸還在使用安卓4.4工業面闆的可以略過此條了。)

人臉識别會議系統性能優化

Battery Historian示例圖(圖檔來源百度)

線程活動與CPU分析 工具有很多,但是Android Studio自帶的他不香嗎?(Rn安卓打包還是用Android Studio,使用vscode打包坑太多了。)

針對異常點進行分析。

人臉識别會議系統性能優化

Android Studio ​​CPU 分析器​​  示例圖

(圖檔來源https://developer.android.com/)

資料顯示CPU的負擔過重,tracking導緻程序有阻塞現象。

實際上大家一直認為是完全由于渲染壓力大導緻的頁面卡頓,(渲染是RN 整個架構的瓶頸),報表資料顯示的恰恰相反,對于人臉識别,GPU并沒跑滿,圖形界面的渲染工作隻有部分由GPU進行的,當tracking阻塞後會暫時等待發生卡頓,再逐個完成canvas 關鍵點渲染定位,調用接口,取得傳回資料後渲染資訊卡片和執行動畫時導緻第二次輕微卡頓(RN渲染卡頓),然後性能反應正弦函數波動,同時卡頓和不流暢現象消失。

導緻“拍腦袋”定位問題就是因為前端同僚對于日志和資料分析工具的使用是普遍不夠的。

定位問題的方法有多種,像大家常用的二分查找法(二分注釋、二分復原)。或者     斷點調試、分析日志。都可以有效的幫助我們快速定位問題。

那麼通過資料的分析以及工具提供的關鍵類,我們也是比較清晰的找出了問題:資訊卡片動畫+canvas特效+人臉識别相關函數。

​原有的實作方式:引入全部的相關js,new多個tracking.objectTracker來檢測人臉、眼睛、嘴的區域。在通過canvas實作人臉關鍵點的展示效果,

人臉識别會議系統性能優化

Tracking.js檔案目錄示意圖

而對人臉進行采集。Tracking.js

是使用 CPU 進行計算的,在圖像的矩陣運算效率上,相對 GPU 要慢一些。

此時,有了資料的支撐,決定替換人臉識别架構層配合RN進行嘗試性優化,采用face-api.js

face-api.js

基于 TensorFlow.js 核心,實作了三種卷積神經網絡架構,用于完成人臉檢測、識别和特征點檢測任務;其内部實作了一個非常輕巧,快速,準确的 68 點面部标志探測器。支援多種 tf 模型,微小模型僅為 80kb。另外,它還支援 GPU 加速,相關操作可以使用 WebGL 運作。

核心原理是針對人臉檢測工作實作了一個 SSD(Single Shot Multibox Detector)算法,它本質上是一個基于 MobileNetV1 的卷積神經網絡(CNN),在網絡的頂層加入了一些人臉邊框預測層。

人臉識别會議系統性能優化

face-api面部标志探測器(圖檔來源官方文檔)

确認替換後,針對于React Native線程排程做一下調優,為了友善了解,我簡單繪制了一個示意圖,講解下流程:

JS Thread:React 等 JavaScript 代碼都在這個線程執行。

Bridge:連接配接橋,具有異步,序列化,批處理的特點

Shadow Thread:進行布局計算和構造 UI 界面的線程。

Native modules提供 Native 功能(比如相冊、藍牙)

UI Thread:Android/iOS(或其它平台)應用中的主線程。

人臉識别會議系統性能優化

ReactNative線程示意圖

​比如我們繪制一個UI,JS thread會先對其序列化,形成一條UIManager.createView 消息,然後通過Bridge發到Shadow Thread。Shadow Tread接收到這條資訊後,先反序列化,形成Shadow tree,再轉換原生布局資訊,傳給UIthread。

而UI thread 拿到消息後,同樣先反序列化,然後根據所給布局資訊,進行繪制。

而這一系列都強依賴于

bridge,像高度計算、UI更新每次的操作都通過

bridge傳遞,任務一多,就會生成任務隊列,異步操作批量處理,一些前端的更新很難及時反應到

UI 上,特别是類似于更新頻率較高的動畫操作,任務較多,很難保證每一幀及時渲染。

那麼,優化的方向:

1.減少 JS Thread 和 UI Thread 之間的異步通信,或者減少較少JSON的大小

2.盡量減少 JS Thread 側的計算

整體解決方案是face-api替代tracker;React Native做一下調優。下面主要分三步講下React Native調優。

1.開啟動畫原生驅動

useNativeDrive:true

JS Thread 和 UI Thread 之間是通過 JSON 字元串傳遞消息的。對于一些非布局的屬性、直接事件,(useNativeDriver

這個屬性隻能使用到隻有非布局相關的動畫屬性上,例如 transform 和 opacity。布局相關的屬性,比如說 height 和 position 相關的屬性,開啟後會報錯。)比如人臉識别成功,人員資訊卡片動畫,我們可以使用 useNativeDrive: true 開啟原生動畫驅動。

Animated.timing(this.state.animatedValue, { toValue: 1, duration: 500, useNativeDriver: true, // <-- Add this }).start();  

通過啟用原生驅動,我們在啟動動畫前就把其所有配置資訊都發送到原生端,利用原生代碼在 UI 線程執行動畫,而不用每一幀都在兩端間來回溝通。如此一來,動畫一開始就完全脫離了 JS

線程,是以此時即便 JS 線程被卡住,也不會影響到動畫了。

2.使用互動管理器 InteractionManager

使用InteractionManager将部分需要優化的任務在互動操作和動畫完成之後再執行,比如:會場分布的跳轉動畫。目的是平衡複雜任務和互動動畫之間的執行時機。

const handle = InteractionManager.createInteractionHandle();// 執行動畫... (`runAfterInteractions`中的任務現在開始排隊等候)// 在動畫完成之後開始清除句柄:InteractionManager.clearInteractionHandle(handle);// 在所有句柄都清除之後,現在開始依序執行隊列中的任務  

根據官方解釋的解釋:runAfterInteractions接受一個回調函數,或是一個PromiseTask對象,該對象傳回一個Promise。如果提供的參數是一個PromiseTask, 那麼即便是異步的它也會阻塞任務隊列,直到它執行完畢後,才會執行下一個任務。這樣就可以按需優化動畫流暢度。

3.重新渲染

首先,RN與React中,當父元件中觸發setState, 未修改任何state中的值也會引起所有子元件的重新渲染, 或者當父元件傳給子元件的props發生改變, 不管該props是否被子元件用到, 也都會去重新渲染子元件。

那麼,針對重新渲染問題,使用PureComponent和shouldComponentUpdate對于普通函數進行優化;對于hook元件使用memo優化;

至驗證後整體得到改善,互動較為流暢,達到基本性能名額。現在主要是針對于機率性問題是否複現。尋求測試同僚的幫助。

首先為什麼要使用性能監控平台:1.處理重複資訊,避免一些問題在多個APP上重複處理,或者在一個APP上反複處理;2持續捕捉重要可疑資訊,提升效率,降低人力成本。

其次什麼時候、什麼場景下使用性能監控平台:除了測試、運維需要使用性能監控平台,開發者也要學會利用性能監控平台去輔助定位解決問題,這裡推薦兩個方案:

Android vitals是Google為提高Android裝置穩定性和性能而推出的一項計劃, Google Play 的Android vitals控制台可以突出顯示崩潰率、ANR 發生率、喚醒次數過多以及喚醒鎖定被卡住等名額。包含了開發者常用功能,關鍵是不侵入代碼,應用比較友善。

而Firebase除此之外還可以擷取詳細的自定義崩潰報告資料,以了解應用中出現的崩潰情況。該工具會按相似堆棧軌迹将崩潰分門别類,并根據崩潰對使用者所産生影響的嚴重程度進行分級。除了接收自動生成的報告外,還可以通過記錄自定義事件來獲知導緻應用崩潰的操作。

人臉識别會議系統性能優化
人臉識别會議系統性能優化

Vitals + Firebase功能對比圖(圖檔來源官網)

​是以一般情況下使用AndroidVitals可處理大部分簡單問題,并可搭配Firebase靈活處理自定義事件。

不太友善的是Google國内限制,需要公司申請專線跨境聯網,并且網絡波動時,經常需要身份驗證(這點比較煩人)。

費用上:AndroidVitals

使用免費,但是需要25$注冊開發者賬号;Firebase有免費版和付費版。适合外企、跨國公司或者有相關資質的公司研發使用。

 由于Google國内限制,很多企業沒有網絡報備不能連接配接外網,那麼友盟+ 的U-APM也可以完美滿足以上需求。針對于我的項目,我這裡是選擇接入友盟+SDK協助問題檢測。

友盟的推送和統計在業界做的是比較好的,而比較熟悉友盟的朋友應該了解U-APP的穩定性功能,那麼U-APM就是友盟+在U-APP穩定性功能的基礎上更新推出的一款面向開發者監控應用的穩定性資料産品。

人臉識别會議系統性能優化

U-APM核心技術與優勢(圖檔來源友盟官網)

為什麼選擇​​​友盟+U-APM 應用性能監控平台

​​​:

該産品不僅通過發現線上問題-快速定位問題-高效解決問題打造體系化線上品質監控平台。而且擁有支援實時監控線上App崩潰趨勢,7*24小時監控告警與修複驗證,複現使用者崩潰現場,關鍵環節的重點監控,修複測試等特點。

重點還在于有阿裡技術的加持,可以提供長期穩定的産品疊代和項目服務及專家咨詢能力。貼心啊,企業工程化需要的就是長期穩定!小廠的産品可能用着用着就找不到人了。

人臉識别會議系統性能優化

U-APM與競品功能對比(圖檔來源友盟官網)

如果之前有使用過U-APP的,可以直接檢視官網的更新說明按體驗U-APM;那麼沒有使用過友盟産品的需要到 ​​【友盟+】官網 注​​冊并且添加新應用,獲得AppKey。

注:請一定認真閱讀U-APM合規指南,滿足工信部相關合規要求。避免因隐私政策風險導緻APP下架。

maven自動內建:

maven自動內建是比較簡單快速的

首先在工程build.gradle配置腳本中buildscript和allprojects段中添加【友盟+】sdk 新maven倉庫位址。如下圖。

人臉識别會議系統性能優化

然後在工程App 對應build.gradle配置腳本dependencies段中添加SDK庫依賴,是不是很簡單呢。

1. dependencies {  

2.     implementation fileTree(include:['*.jar'], dir:'libs')  

3.   

4. // 下面各SDK根據宿主App是否使用相關業務按需引入。  

5.     implementation  'com.umeng.umsdk:common:9.4.4'// 必選  

6.     implementation  'com.umeng.umsdk:asms:1.4.1'// 必選  

7.     implementation 'com.umeng.umsdk:apm:1.4.2' // 必選  

8. }  

  手動Android Studio內建:

那麼我這裡是采用的手動內建

1.首先在選擇U-APMSDK

元件并下載下傳,解壓.zip檔案得到相應元件包

人臉識别會議系統性能優化

得到如下檔案:

人臉識别會議系統性能優化

umeng-common-9.4.4.jar // 統計SDK 必選

umeng-asms-armeabi-v1.4.1.aar//

必選

以及apm目錄下的

umeng-apm-armeabi-v1.4.2.aar//U-APMSDK

可如有UTDID需求,內建thirdparties下

utdid4all-1.5.2.1-proguard.jarUTDID

服務的補充包

如需要ABTest子產品,可內建common下

umeng-abtest-v1.0.0.aarABTest

子產品

2.在Android Studio的項目工程libs目錄中拷入以上jar包。

右鍵Android Studio的項目工程 —> 選擇Open Module Settings —> 在 Project Structure彈出框中 —> 選擇 Dependencies頁籤 —> 點選左下“+” —> 選擇元件包類型 —> 引入相應的元件包。

3在app的build.gradle檔案中引入相應的元件包。參考示例如下:

1. repositories{  

2.     flatDir{  

3.         dirs 'libs'  

4. }  

5. }  

6. dependencies {  

7.     implementation fileTree(include:['*.jar'], dir:'libs')  

8.     implementation (name:'umeng-asms-armeabi-v1.4.1', ext:'aar')   

9.     implementation (name:'umeng-apm-armeabi-v1.4.2', ext:'aar')  

10.      

}  

注意:如果需要适配armeabi 以外的平台,或者遇到了多CPU架構so庫加載失敗問題[SA10070],除了需要引入相應的包,還要分别下載下傳并考入對應的.so檔案。

按照官網教程授予如下權限:

人臉識别會議系統性能優化

1. <manifest ……>  

2. <uses-sdkandroid:minSdkVersion="8"></uses-sdk>  

3. <uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE"/>  

4. <uses-permissionandroid:name="android.permission.ACCESS_WIFI_STATE"/>  

5. <uses-permissionandroid:name="android.permission.READ_PHONE_STATE"/>  

6. <uses-permissionandroid:name="android.permission.INTERNET"/>  

7. <application ……>  

如果APP中使用了代碼混淆,需要增加如下配置

1. -keep class com.umeng.** { *; }  

2.   

3. -keep class com.uc.** { *; }  

4.   

5. -keep class com.efs.** { *; }  

6.   

7. -keepclassmembers class *{  

8.      public<init>(org.json.JSONObject);  

9. }  

-keepclassmembers enum *{  

11.      

      publicstatic**[] values();  

12.      

      publicstatic** valueOf(java.lang.String);  

13.      

2.6初始化sdk

在rn的安卓原生的application.onCreate函數中調用基礎元件包提供的初始化函數:

1. /** 

2. * 注意: 即使您已經在AndroidManifest.xml中配置過appkey和channel值,也需要在App代碼中調 

3. * 用初始化接口(如需要使用AndroidManifest.xml中配置好的appkey和channel值, 

4. * UMConfigure.init調用中appkey和channel參數請置為null)。 

5. */  

6. UMConfigure.init(Context context,String appkey,String channel,int deviceType,String pushSecret);  

或者調用此預初始化函數

1. public static void preInit(Context context,String appkey,String channel)  

然後打開日志開關

2. *設定元件化的Log開關 

3. *參數: boolean 預設為false,如需檢視LOG設定為true 

4. */  

5. UMConfigure.setLogEnabled(true);  

至此即可使用卡頓分析功能、Java、Native崩潰分析、ANR分析功能等等基礎功能了。因為其原理通過主線程的響應時間,将有卡頓體驗的裝置資訊、卡頓日志進行上報。那麼等待裝置上報後我們可以在web控制台看到上傳的Error(列印SDK內建或運作時錯誤資訊),Warn(列印SDK警告資訊),Info(列印SDK提示資訊),Debug(列印SDK調試資訊)。以及報表。

人臉識别會議系統性能優化

U-APM崩潰資訊日志示例圖

但是從封包直接看錯誤堆棧非常麻煩, U-APM利用聚合算法提供了卡頓子產品的功能,篩選影響使用者量大的200個堆棧從棧頂到棧底雙向聚合,展示出現頻率前10的子產品,子樹深度最多支援50層,幫助下挖詳細的卡頓子產品資訊。

人臉識别會議系統性能優化

U-APM卡頓子產品示例圖

除此之外,U-APM中還提供了啟動分析、記憶體分析、網絡分析,使用者細查子產品等進階功能。除了記憶體分析外是其他功能需要進行配置才能使用的。大家可以去體驗一下。

那麼最終通過U-APM也是順利的驗證問題、解決問題。完成了整個研發閉環。感興趣的話,可以免費體驗​U-APM。

三.項目總結 

1.不要盯着問題看。對于app的性能優化也好,系統優化也好。問題的表象可能是由于本質的副作用帶來的。例如,本項目中局部現象是卡頓、不流暢,隻盯着現象,我們很可能陷入優化困境,去優化渲染、減少canvas繪圖,甚至精簡業務。而最終突破我們的性能瓶頸是通過修改實作方式達成的,更适合業務場景、更能發揮機器性能。而這一切,需要資料去支撐。

2. 用資料說話。不要憑感覺,去檢測性能問題、評估性能優化的效果,要有可量化的渲染性能評判标準,以及可量化、可視化的優化工具。利用經驗去感覺、猜測對于團隊是沒有沉澱的,而資料和工具是可以傳承的。例如:對于優化性能如果沒有标準,對于結果沒有資料展現。那麼整體的工作是沒有意義的,成功與否全靠leader拍腦門決定。

3.使用低配置的裝置:同樣的程式,在低端配置的裝置中,相同的問題會暴露得更為明顯。例如:在前期安卓開發真機上并沒有卡頓現象,放在工業真機上才暴露出卡頓等問題。而對于高低端裝置都能帶來很好的使用者體驗,一直是一個很重要的問題。

4.權衡利弊:在能夠保證産品穩定、按時完成需求的前提下去做優化,投入産出比過高時,應采取其他方案,切勿過度優化。永遠不要忘記,優化性能的目的是提高使用者體驗,而不是炫技。

5.抛棄沉沒成本:對于研發中已經付出且不可收回的成本,不要影響未來的決策,例如:對于已經使用track開發的人臉識别子產品,資料證明選型影響到了性能。投入産出比在可接受範圍内,越早替換預期收益越高。