1. 導讀前端
做爲DAU過億的國民出行服務平臺,高德地圖天天爲用戶提供海量的檢索、定位和導航服務,實現這些服務須要有精準的道路信息,好比電子眼位置、路況信息、交通標識位置信息等。讀者是否會好奇,高德是如何感知到現實世界的道路信息,並提供這些數據給用戶呢?算法
事實上,咱們有不少的方法將現實世界的道路要素採集回收,並更新到高德地圖App上。其中一種很是重要的方法是利用計算機視覺的手段,將視覺算法部署到客戶端,經過對圖片的檢測識別,快速將道路的信息回收。後端
爲了低成本,高實時性地實現道路要素回收,咱們藉助MNN引擎(一個輕量級的深度神經網絡推理引擎),將卷積神經網絡模型部署到客戶端,在客戶端進行端側的模型推理,從而完成在計算能力低,內存小的客戶端進行道路要素採集的任務。性能優化
傳統的CNN(卷積神經網絡)計算量很是大,且業務場景須要部署多個模型。如何在低性能的設備上部署多個模型,並在不影響實時性的狀況下保證應用的"小而優"是一個很是大的挑戰。本文將分享利用MNN引擎在低性能設備上部署深度學習應用的實戰經驗。網絡
2. 部署架構
2.1 背景介紹框架
如Figure2.1.1所示,業務背景是將道路要素識別相關的CNN模型部署到客戶端,在端側進行模型推理,並提取道路要素的位置和矢量等信息。性能
因爲該業務場景的須要,目前端上需同時部署10+甚至更多的模型,以知足更多的不一樣道路要素的信息提取須要,對於低性能設備來講是很是大的挑戰。學習
Figure 2.1.1 高德數據採集優化
爲了達到應用的"小而優",MNN引擎部署模型的過程當中遇到了不少問題和挑戰。下面就這些問題和挑戰分享一些經驗和解決辦法。
2.2 MNN部署
2.2.1 內存佔用
應用運行內存對於開發者來講是始終繞不開的話題,而模型推理產生的內存在應用運行內存中佔有很大的比例。所以,爲了使模型推理內存儘量小,在模型部署的過程當中,做爲開發者必須清楚模型運行產生內存的主要來源。根據咱們的部署經驗,部署單模型的過程當中,內存主要來源於如下四個方面:
Figure 2.2.1 單模型部署內存佔用
ModelBuffer: 模型反序列化的buffer,主要存儲模型文件中的參數和模型信息,其大小和模型文件大小接近。
FeatureMaps: Featuremaps的內存,主要存儲模型推理過程當中,每一層的輸入和輸出。
ModelParams: 模型參數的內存,主要存儲模型推理所需的Weights, Bias, Op等內存。其中Weights佔用了該部分的大部份內存。
Heap/Stack: 應用運行中產生的堆棧內存。
2.2.2 內存優化
知曉模型運行內存佔用後,就能方便理解模型運行時的內存變化。通過多個模型部署實踐, 爲了下降部署模型的內存峯值,咱們採起的措施以下:
Figure 2.2.2.1 MNN模型部署內存複用方案
通過內存複用,以部署1個2.4M的視覺模型爲例,模型運行時從加載到釋放,中間各階段所佔用內存變化能夠用如下曲線表示:
Figure 2.2.2.2 單模型應用內存曲線(Android memoryinfo統計)
通過屢次模型部署的實踐,下面總結了部署單模型到端的內存峯值預估公式:
MemoryPeak:單模型運行時內存峯值。
StaticMemory:靜態內存,包括模型Weights, Bias, Op所佔內存。
DynamicMemory:動態內存,包括Feature-maps所佔內存。
ModelSize:模型文件大小。模型反序列化所佔內存。
MemoryHS:運行時堆棧內存(經驗取值0.5M-2M之間)。
2.2.3 模型推理原理
本章節分享模型推理原理,以便於開發者遇到相關問題時,快速定位和解決問題。
模型推理前模型的調度: MNN引擎推理保持了高度的靈活度。便可以指定模型不一樣的運行路徑,也能夠對不一樣的運行路徑指定不一樣的後端,以提升異構系統的並行性。此過程主要是調度或者任務分發的過程。
對於分支網絡,能夠指定當前運行分支,也能夠調度分支執行不一樣後端,提升模型部署的性能。圖Figure2.2.3.1所示爲一個多分支模型, 兩個分支分別輸出檢測結果和分割結果。
Figure 2.2.3.1 多分支網絡
部署時可作以下優化 :
模型推理前的預處理: 本階段會根據上一步的模型調度信息進行預處理,本質是利用模型信息和用戶輸入配置信息,進行Session(持有模型推理數據)的建立。
Figure 2.2.3.2 根據Schedule建立Session
本階段根據模型反序列化的模型信息和用戶調度配置信息來進行運算調度。用於建立運行的Piplines和對應的計算後端。如Figure2.2.3.3所示。
Figure 2.2.3.3 Session建立
模型的推理: 模型推理本質是根據上一步建立的Session,依次執行算子的過程。運算會根據預處理指定的模型路徑和指定後端進行模型每層的運算。值得一提的是,算子在指定的後端不支持時,會默認恢復到備用後端執行計算。
Figure 2.2.3.4 模型推理計算圖
2.2.4 模型部署時間
本部分統計了單模型部署過程各階段耗時,方便開發者瞭解各階段的耗時,以便更好的設計代碼架構。(不一樣設備有性能差別,耗時數據僅供參考)
Figure 2.2.4.1 模型推理計算圖
模型反序列化和Session建立相對耗時較長,進行多張圖的推理時,儘可能執行一次。
2.2.5 模型偏差分析
模型部署時,開發者不免會遇到部署端和X86端(Pytorch, Caffe, Tensorflow)訓練模型輸出結果有誤差的狀況。下面分享偏差緣由, 定位思路以及解決辦法。
模型Inference示意圖如Figure 2.2.5.1所示:
Figure 2.2.5.1 模型Inference示意圖
模型偏差的肯定: 查看是否有模型偏差最直觀的方法是,固定部署端模型和X86端模型的輸入值,分別推理,對比部署端模型和X86端模型輸出值,可確認是否有偏差。
模型偏差的定位: 當肯定有模型偏差時,先排除因模型輸入偏差致使的模型輸出偏差。由於X86端和部分Arm設備浮點的表示精度不一致,輸入偏差在某些模型中會被累積,最終形成較大的輸出偏差。用什麼方法來排除是輸入偏差致使的問題呢?咱們提供一種方法是將模型輸入設置爲0.46875(緣由是該值在X86設備和部分Arm設備表示一致,本質是1通過移位得到的浮點數在兩種端上表示均一致)。而後觀察輸出是否一致便可。
模型偏差的定位思路: 在排除模型輸入偏差致使模型輸出偏差(即模型輸入一致時,模型輸出不一致)的狀況下,極可能是模型某些算子致使的偏差了。如何定位模型哪一個OP致使的偏差呢?經過下述的步驟能夠定位模型內部引發偏差的緣由:
1)經過runSessionWithCallBack來回調模型每一個OP的中間計算結果。目的是定位模型從哪一個Op開始出現偏差。
2)定位到該層以後,便可定位到產生偏差的算子。
3)定位到算子後,經過指定的後端信息便可定位到對應的算子執行代碼。
4)定位到對應的執行代碼後,調試定位產生偏差的代碼行,從而定位到產生模型偏差的根本緣由。
3. 總結
MNN引擎是一個很是好的端側推理引擎,做爲開發者來講,模型的端上部署和性能優化在關注業務邏輯優化的同時,也需關注對引擎計算過程,框架設計和模型加速的思想,反過來能夠更好的優化業務代碼,作出真正"小而優"的應用。
4.將來規劃
隨着設備性能的廣泛提高,後續的業務會搭載到性能更高的設備,咱們會利用更豐富的計算後端作模型的加速,好比OpenCL, OpenGL等, 從而加速模型的推理。
將來設備會搭載更多的模型到客戶端,用於實現更多品類道路要素信息的回收,咱們也會利用MNN引擎,探究更高效,更高實時性的代碼部署框架,以更好的服務於地圖採集業務。
咱們是高德地圖數據研發團隊,團隊中有大量HC,歡迎對Java後端、平臺架構、算法端上工程化(C++)、前端開發感興趣的小夥伴加入,請發送您的簡歷到 gdtech@alibaba-inc.com ,郵件標題格式: 姓名-技術方向-來自高德技術。咱們求賢若渴,期待您的加入。