愛鋒貝

 找回密碼
 立即注冊

只需一步,快速開始

扫一扫,极速登录

查看: 447|回復(fù): 2
打印 上一主題 下一主題
收起左側(cè)

含代碼 | 支付寶如何優(yōu)化移動端深度學(xué)習(xí)引擎?

[復(fù)制鏈接]

1385

主題

1427

帖子

5714

積分

Rank: 8Rank: 8

跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2022-1-16 02:43:31 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式

一鍵注冊,加入手機(jī)圈

您需要 登錄 才可以下載或查看,沒有帳號?立即注冊   

x
阿里妹導(dǎo)讀:移動端深度學(xué)習(xí)在增強(qiáng)體驗實時性、降低云端計算負(fù)載、保護(hù)用戶隱私等方面具有天然的優(yōu)勢,在圖像、語音、安全等領(lǐng)域具有越來越廣泛的業(yè)務(wù)場景??紤]到移動端資源的限制,深度學(xué)習(xí)引擎的落地面臨著性能、機(jī)型覆蓋、SDK尺寸、內(nèi)存使用、模型尺寸等多個方面的嚴(yán)峻挑戰(zhàn)。

本文介紹如何從模型壓縮和引擎實現(xiàn)兩個方面的聯(lián)合優(yōu)化,應(yīng)對上述挑戰(zhàn),最終實現(xiàn)技術(shù)落地,希望對大家有所啟發(fā)。
1.背景

由于移動端資源的限制,大部分深度學(xué)習(xí)引擎都部署在云端,移動設(shè)備獲取到輸入數(shù)據(jù),經(jīng)過簡單的加工,發(fā)送給云端,云端服務(wù)器經(jīng)過深度神經(jīng)網(wǎng)絡(luò)推斷運算,得到結(jié)果并反饋給移動端,完成整個過程。
顯而易見,這種交互方式有很多弊端,比如依賴網(wǎng)絡(luò),流量過大,延遲太長,更重要的是,云端服務(wù)器必須有足夠大的數(shù)據(jù)吞吐能力,如果移動端請求量太大,超過負(fù)荷,容易導(dǎo)致服務(wù)器宕機(jī),從而使所有移動端任務(wù)都失效。其實,現(xiàn)有的移動設(shè)備已經(jīng)逐漸從以前的單核32位到多核64位過渡,計算能力和存儲能力有了很大的提升,將深度學(xué)習(xí)引擎部署到移動端已經(jīng)成為一個必然趨勢。
然而,成功將DL引擎部署到移動端并非易事。運行速度,包大小,內(nèi)存占用,機(jī)型覆蓋,甚至功耗都是必須逾越的障礙。支付寶移動端深度學(xué)習(xí)引擎xNN是這方面的佼佼者,本文將回顧xNN移動端DL優(yōu)化的方法和技術(shù)。


2.運行速度

大部分移動端處理器都是基于ARM架構(gòu),移動端完成深度神經(jīng)網(wǎng)絡(luò)推斷的任務(wù),基于CPU的方案是最基礎(chǔ)的,也是最可靠的;基于GPU的方案存在兼容性/數(shù)據(jù)同步/overhead過高/接口不滿足等問題;DSP的方案也會存在兼容性的問題; 最近,很多手機(jī)芯片廠商開始構(gòu)建AI協(xié)處理器(各種TPU/APU/NPU),但離應(yīng)用還需要一定的時間。下面我們重點介紹一下在ARM平臺的優(yōu)化技術(shù)。做優(yōu)化有三部曲,如下:
第一部:充分評估的優(yōu)化目標(biāo)。如果算法原型太復(fù)雜了,花再多精力優(yōu)化也是徒勞。針對DL業(yè)務(wù),務(wù)必讓模型充分精簡,直到你覺得差不多了才開始下手,不然的話,嘿嘿。
第二部:確認(rèn)運算熱點。這離不開一些timing profile工具,如XCODE instrument, GPROF, ATRace, DS-5等,熟練地運用工具,可以事半功倍。
第三部:貼身肉搏。下面有利器若干。
2.1.基于C/C++的基本優(yōu)化
編譯器很牛逼,GCC/CLANG都有運行速度的優(yōu)化選項,打開這些選項大部分情況下都會幫你的程序速度提升不少,雖然這還遠(yuǎn)遠(yuǎn)不夠,但聊勝于無。
書寫高效的C代碼。循環(huán)展開,內(nèi)聯(lián),分支優(yōu)先,避免除法,查表等等優(yōu)化小技巧一定要滾瓜爛熟,信手拈來。本文將不再贅述這些基本技巧。
必須學(xué)會看得懂匯編,即便你不寫,也要知道編譯器編譯出來的匯編代碼的效率如何。這樣你可以通過調(diào)整C/C++代碼,讓編譯器生成你需要的代碼。否則,一切浮于表面。
2.2.緩存友好
基于CPU內(nèi)存子系統(tǒng)的優(yōu)化工作很大部分都是在想如何高效地利用緩存(cache),尤其是圖像視頻處理這種大量數(shù)據(jù)交換的場景。幾十年前,我們的老前輩就發(fā)明了主存,多級緩存, 寄存器用來彌補(bǔ)存儲器與計算單元的性能差異,直到今天這個問題還沒有解決(或許一直都不會解決,存儲器和計算單元的設(shè)計思路是不一樣的,高速ram的成本肯定是高的)。存儲層次如下圖,原理很簡單,你想跑得快,只能背得少,你想跑得快,還想裝的多,那就要多掏錢買個車。


CPU-內(nèi)存 子系統(tǒng)工作起來后,如果寄存器沒數(shù)了,通過指令從L1 cache拿,L1沒數(shù)了(Cachemiss),從L2拿,Cache都沒有數(shù)據(jù)了,從主存拿,從主存拿的話, 也要分時間和位置,主存(dram/DDR)不同時刻不同位置訪問的效率都是不同的。這里分享幾個準(zhǔn)則:

少用內(nèi)存
盡量復(fù)用內(nèi)存,不要隨便地申請一大塊內(nèi)存。訪問一大塊內(nèi)存意味著cache miss、TLB miss、dram切bank的概率都會增大,效率自然就降低。小塊的內(nèi)存反復(fù)使用,可以讓CPU更加持久地運作,CPU運作占比越高,程序效率越高。要知道,一次cache miss導(dǎo)致的訪問主存,在復(fù)雜應(yīng)用下,可能有幾十甚至上百個cycle的stall.

連續(xù)訪問
數(shù)據(jù)訪問一般都遵循局部性原理,位置相近的內(nèi)存被重復(fù)使用的概率更高, cache的替換規(guī)則也大多給基于這個原理來設(shè)計,跳躍的訪問內(nèi)存會打破這個規(guī)則,造成訪問效率的低下。

對齊訪問
主存和緩存的最小數(shù)據(jù)交換單元是cache line, 所以訪問內(nèi)存的地址最好是按照cache line的大小進(jìn)行,這樣可以保證最高效的數(shù)據(jù)訪問。比如某臺機(jī)器cache line大小為64Bytes,申請一個128Byte的內(nèi)存區(qū)域,將它的開始地址放在非64Byte對齊的位置,如0x80000020,那么訪問這128Byte需要3條cacheline的訪問, 若放在0x80000040, 則只需要2條cache line, 一般通過多申請一點點內(nèi)存,來避免這種不對齊,比如用posix_mem_align() 函數(shù);更近一步,為了對齊訪問,有時需要對圖像的邊界做一些padding的,比如 224x224的圖片,我們可能會存儲在256x224的內(nèi)存地址中,保證在隨機(jī)訪問某一行時,地址處于對齊的位置。如:


合并訪問
如果反復(fù)的讀寫一段內(nèi)存進(jìn)行運算,效率上肯定不如“一次讀取-多次運算-一次寫入”來的更高效。比如,DL模型中,一般CONV層后面跟著RELU,BIAS層,本著內(nèi)存訪問能省則省的原則,通過提前分析網(wǎng)絡(luò)的結(jié)構(gòu),可以將CONV層和bias合并,甚至將CONV+BIAS+RELU合并在一起進(jìn)行運算,可以獲得很好的gain. 比如:


經(jīng)過合并后,原來對memory的三讀三寫,變成了三讀一寫,速度杠杠的。
顯式對齊數(shù)據(jù)加載
在ARM匯編中,可以顯式的通知CPU,加載的地址是一個對齊得較好的地址。比如      


其中,“:128” 即是通知CPU, R1存放的地址是一個128bit對齊的地址,此時,CPU在向內(nèi)存發(fā)出數(shù)據(jù)請求時,可以發(fā)出更高效的信號。如果R1不是128bit對齊的,執(zhí)行這樣的指令會得到一個地址異常,也就是LINUX中常見的 bus error。怎么保證R1是128bit對齊? 程序員必須知道R1對應(yīng)的數(shù)據(jù)結(jié)構(gòu),需要事先設(shè)計好地址偏移,保證該指令被正確執(zhí)行。并不是所有case都可以滿足這個要求。

緩存預(yù)取
請設(shè)想,如果CPU正熱火朝天的做計算,這時我們在后臺偷偷搬些后面會使用的數(shù)據(jù)到緩存,下次使用時CPU就不用再去等數(shù)據(jù)了,效率不是就變高了嗎?是的。緩存預(yù)取可以做這個事情,如:preload [R1, #256],  可以讓CPU在繼續(xù)執(zhí)行后面的指令,并開始在后臺加載 $R1+256byte位置的數(shù)據(jù)到緩存中。
但是,preload是一條指令,當(dāng)你發(fā)出這樣的指令時,需要知道,至少一個cycle浪費掉了,然后再考慮你預(yù)加載進(jìn)cache的數(shù)據(jù),是不是馬上就可以接著被CPU 采納。不幸的是,在手機(jī)實時操作系統(tǒng)中,可能多達(dá)幾十甚至上百個線程嗷嗷待哺,完全無法保證預(yù)取的這些數(shù)據(jù)會被馬上用上,系統(tǒng)中有大把事件是會讓你的線程找地方歇息的,這種情況下,你預(yù)取的數(shù)據(jù)非但不能用,還可能被其他線程從cache中踢出去,白白浪費了一次主存訪問。但是夢想總是要有的,萬一實現(xiàn)了呢,總要試試才知道效果吧!

類似的方法可能還能舉出一些來,但宗旨只有一個,在做同樣的事情的前提下,別讓你的CPU經(jīng)常停下來等數(shù)據(jù)。
2.3.多線程
手機(jī)核備競賽前幾年搞得如火如荼,最近慢慢冷下來了,但也說明多核在運算上還有很大的優(yōu)勢。當(dāng)然,多核的使用,會導(dǎo)致CPU占比和功耗直線上升,但在可接受的條件下,多線程優(yōu)化帶來的性能提升是最可觀的。多線程的實現(xiàn)方法推薦使用OPENMP,接口豐富,編程簡潔,用起來并不難,但需要注意一些細(xì)節(jié)。
線程開銷
OPENMP會自動為循環(huán)分配線程,但并非所有循環(huán)都適合做多線程優(yōu)化,如果每次循環(huán)只做了非常少的事情,那么使用多線程會得不嘗失。線程的創(chuàng)建和切換會消耗一定的系統(tǒng)資源,線程調(diào)度有一定的規(guī)律,操作系統(tǒng)在沒有高優(yōu)先事件觸發(fā)的情況下(中斷,異常,信號量), 調(diào)度周期都在毫秒級別,如果每次線程執(zhí)行時間沒有達(dá)到一定的量,多線程的效果就會大打折扣。實際運用中,可以通過 #pragma omp parallel for if (cond) 語句來判斷runtime過程中是否要啟用多線程。
動態(tài)調(diào)度
默認(rèn)情況,OPENMP采用靜態(tài)調(diào)度機(jī)制,即將循環(huán)的次數(shù)平均分配給各個線程,不關(guān)心各個線程的執(zhí)行快慢。如果某次循環(huán)運行比較慢或者循環(huán)次數(shù)不能平均分配時,容易出現(xiàn)負(fù)載不均衡的情況,這時就必須有動態(tài)調(diào)度的機(jī)制,動態(tài)調(diào)度可以根據(jù)線程的運行快慢,決定是否“互相幫助”。 OPENMP可以采用schedule(dynamic)來達(dá)到動態(tài)調(diào)度的效果。


同時需要說明的是,某些機(jī)型對于OPENMP的支持并不好,或者說線程的開銷過大,這時,可能需要手動調(diào)整線程的負(fù)載和并行的方式。這些細(xì)節(jié)需要通過反復(fù)的實驗來微調(diào)。
2.4.稀疏化
深度神經(jīng)網(wǎng)絡(luò)是個超級黑盒,人們把神經(jīng)突觸的權(quán)重找出來了,讓整個網(wǎng)絡(luò)可以完成特定的任務(wù),但卻不知道每根突觸的作用是啥。實際上,其決定作用的很可能就只是那“幾根筋”。我們的實驗結(jié)果也是如此,大量的權(quán)重數(shù)據(jù)都可以是0,而整個輸出精度相差無幾。當(dāng)發(fā)現(xiàn)網(wǎng)絡(luò)中有50%甚至80%的數(shù)據(jù)為0時,那么針對稀疏的卷積和矩陣優(yōu)化就顯得非常重要了。
稀疏優(yōu)化的重點是設(shè)計合適的索引方案和數(shù)據(jù)存放方式,如下圖。


稀疏方案的應(yīng)用,依賴不同的運算結(jié)構(gòu),如針對1x1卷積的優(yōu)化,數(shù)據(jù)組織方法和3x3卷積就可能存在不同,不同的稀疏程度,得到的提升效果也是不同,需要不斷地嘗試各種方案和參數(shù)。
2.5.定點化     
大部分深度神經(jīng)網(wǎng)絡(luò)推斷引擎,都需要用浮點精度來得到更精確的結(jié)果,這樣paper上的數(shù)據(jù)才好看。但實際上,有些DL應(yīng)用并不需要這么高的精度,即便是單精度浮點,也存在很大的冗余運算。以Tensor的1x1的卷積為例子,實際就是一個乘累加的過程,若使用單精度浮點存放數(shù)據(jù),每個元素需要4個字節(jié),而如果將數(shù)據(jù)量化到8bit, 只需要1個字節(jié),節(jié)省3/4的內(nèi)存訪問量,這意味著在帶寬緊張的狀態(tài)下,性能提升會更加明顯。下圖體現(xiàn)了不同場景下定點化的性能提升收益(倍數(shù))。


2.6.neoN及匯編
NEON 是針對高級媒體和信號處理應(yīng)用程序以及嵌入式處理器的 64/128 位混合 SIMD 技術(shù)。它是作為 ARM內(nèi)核的一部分實現(xiàn)的,但有自己的執(zhí)行管道和寄存器組,該寄存器組不同于ARM 核心寄存器組。NEON 支持整數(shù)、定點和單精度浮點 SIMD 運算。經(jīng)過良好設(shè)計的NEON代碼,理論上可以比普通C語言版本快2-8倍。
NEON指令集分為ARMV7版本和ARMV8版本,寄存器個數(shù)和格式略有不同。寫NEON指令有兩種方式,一種是NEON Intrinsic, 一種是NEON Inline Assembly(內(nèi)聯(lián)匯編)。
本文主要是分享一些用Neon/匯編優(yōu)化的經(jīng)驗,學(xué)習(xí)具體neon/匯編寫法可以參考:
https://community.arm.com/android-community/b/android/posts/arm-neon-programming-quick-reference

2.6.1.NEON Intrinsic vs Neon 內(nèi)聯(lián)匯編
大部分情況下采用NEON Intrinsic編程就夠用了,NEON Intrinsic的好處也是非常明顯的,首先,在armv7,armv8平臺都可以跑,其次,代碼簡潔容易理解和維護(hù),另外,編譯器還會根據(jù)不同平臺做代碼重排;但是NEON intrinsic也有一些缺點,比如沒有預(yù)取指令,分解Neon寄存器很麻煩,寄存器分配可能不高效,無法做顯式的對齊加載,編譯器可能會引進(jìn)一些奇怪的指令,造成性能低下。


如果對某個模塊的性能要求很高,編譯器的輸出不滿足要求,這時候,就需要使用內(nèi)聯(lián)匯編;對于xNN中的核心模塊卷積運算,都是通過內(nèi)聯(lián)匯編實現(xiàn),性能比NEON Intrinsic提升10%左右。以下是ARM官方例子:


當(dāng)然還有一種方式是采用純匯編寫程序,這不是所有人都能接受的。付出得多,收獲也多,真正的高效的程序都是純匯編的。相對編譯器產(chǎn)生的代碼,手工純匯編的好處還是非常明顯的,比如精簡的棧內(nèi)存,高效的寄存器利用,充分的流水線優(yōu)化等等,有一種一切盡在掌握的快感。
但是,大部分情況下,用純匯編寫程序花去的精力,完全有機(jī)會在其它地方去彌補(bǔ)。所以這種方式適合追求極致的同學(xué)。
2.6.2.會寫NEON/匯編很重要,構(gòu)思好的實現(xiàn)方案更重要
NEON指令比較豐富,實現(xiàn)同一個功能有多種指令組合,除了理解指令的本身的作用之后,需要合理組織數(shù)據(jù),使用更高效的指令來實現(xiàn)既定功能。
舉個例子,實用實現(xiàn)單精度浮點矩陣乘法 sgemm中的 C = A * B + Bias,為了簡單起見,假設(shè)矩陣的維度是2的冪。如 Dims(C) = 512x512, Dims(B) =512x512, Dims(B) = 512x512, Dims(Bias) = 512x512;  
代碼1  :  C語言的寫法是:


運行時間是: 1654689us  (小米5 snapdragon 820,下同).   
為了構(gòu)造SIMD,我們將4個C的元素同時輸出,如:


從而產(chǎn)生代碼2,這是初步的NEON寫法:


運行時間:633551us
考慮到數(shù)據(jù)的重復(fù)加載,可以多取四行,一次輸出4x4的block, 這樣可以省下接近3/4的數(shù)據(jù)讀取,如


從而得到代碼3:


運行時間:367165us
進(jìn)一步,我們發(fā)現(xiàn)矩陣B的取數(shù)不連續(xù),每次只取4個float, 遠(yuǎn)不到cache line (64Byte),相當(dāng)于cache miss有3/4是有可能被優(yōu)化掉的,存在很大的浪費,所以對B的數(shù)據(jù)做轉(zhuǎn)置,轉(zhuǎn)置的過程可以和實際代碼結(jié)合,減少額外內(nèi)存拷貝;同時,我們將Bias的作為sum的初始化值, 減少一次寫操作。于是得到代碼4:


運行時間是:60060us
最后,按4x4的block進(jìn)行循環(huán)構(gòu)造,然后用OPENMP進(jìn)行多線程化,得到代碼5:


運行時間25178us
上面四種NEON寫法的運行速度增益分別是:


代碼5肯定還不是優(yōu)化的終點,通過數(shù)據(jù)重排,4x4的轉(zhuǎn)置部分還可以省掉;cache的優(yōu)化還可以更加細(xì)致;4x4的塊是否是最優(yōu)也有待論證;最后,還可以祭出匯編大殺器,性能還能再上一個臺階。
sgemm的優(yōu)化版本還可以參考nnpack/eigen等開源庫。實際代碼中,需要處理各種維度的情況,代碼遠(yuǎn)比上述要復(fù)雜。
3.包大小

移動端的資源緊張,不僅僅是指運算資源,app大小也是商用DL引擎一個重要指標(biāo),更小的包大小意味著更快的下載速度,更少的app下載流量。app大小的壓縮包括很多方面,這里我們只針對庫文件的大小精簡,做一些經(jīng)驗分享。
3.1.編譯優(yōu)化
編譯器有針對大小的編譯選項,比如GCC的-Os, 相當(dāng)于可以同時打開-O2的優(yōu)化效果,同時精簡生成目標(biāo)文件的尺寸,生成目標(biāo)代碼后,鏈接成動態(tài)庫的時候,可以通過strip命令,去掉多余的調(diào)試代碼。這些是最基本的優(yōu)化。針對IOS, 可以通過XCODE下面方法做精簡:

  • BuildSettings->Optimization Level,XCODE默認(rèn)設(shè)置為“Fastest     ,Smallest”,保持默認(rèn)即可
  • Build Settings->Linking->Dead Code Stripping 設(shè)置成 YES
  • Deployment Postprocessing 設(shè)置成YES
  • Strip Linked Product 設(shè)置成YES
  • 工程的Enable C++ Exceptions和Enable     Objective-C Exceptions選項都設(shè)置為NO。
  • symbols hidden by default選項設(shè)置為YES。
  • 所有沒有使用C++動態(tài)特性的lib庫(搜索工程沒有使用dynamic_cast關(guān)鍵字) Enable C++ Runtime     Types 選項設(shè)置為NO。
上述配置,在IOS設(shè)置輸出目標(biāo)為release時,XCODE會幫你自動打開一部分配置。同樣的,在Android NDK編譯,在Application.mk中配置OPTIMIZE=release,NDK會幫你做絕大部分的優(yōu)化工作。
針對資源緊張的嵌入式設(shè)備,ARM提供了thumb/thumb2精簡指令集, 相當(dāng)于,同樣的指令,同時有 16bit 和32bit 兩套指令,使用 -MThumb選項可以讓編譯器優(yōu)先編譯出16bit的指令,在執(zhí)行時通過內(nèi)置的譯碼器,將指令轉(zhuǎn)換成32bit的指令,這樣既可以精簡代碼,還可以保持原來32bit指令的性能。
針對動態(tài)庫的發(fā)布,還可以通過Invisible Symbol的方式,將不需要的符號隱藏起來,省下目標(biāo)庫文件中符號表的表項,如果你的代碼有大量的函數(shù),這會是不小的提升,試試看,說不定有驚喜。具體寫法是:


這樣就ok了,簡直是物美價廉!
3.2.代碼精簡
以上都是一些常規(guī)的縮小庫大小的方法,實際上,針對DL模型的特性還可以進(jìn)一步精簡庫大小,比如包括:

  • 庫依賴簡化- 大部分開源引擎都會依賴C++ STL庫,如Caffe/Tensorflow, 如果要做到極致的精簡,需要將復(fù)雜的C++屬性去掉,這樣可以依賴更加緊湊的stl庫,甚至不依賴stl.
  • 功能裁剪 - 刪除不常用的layer,刪除不常用的代碼分支,或者Layer組件化,用時加載,都可以減少基本庫大?。?br />
3.3.模型壓縮
深度學(xué)習(xí)模型的size,小到幾M,大到幾百M,如果不做壓縮,根本是不可想象的。模型中的大部分?jǐn)?shù)據(jù)是神經(jīng)網(wǎng)絡(luò)的突觸權(quán)重,存在有巨大的壓縮空間。比如, 支付寶xNN團(tuán)隊提供的xqueeze工具,可以讓深度學(xué)習(xí)模型壓縮比例達(dá)到幾十甚至一百倍。壓縮技術(shù)包括神經(jīng)元剪枝 (neuron pruning)、突觸剪枝(synapse pruning)、量化 (quantization)、網(wǎng)絡(luò)結(jié)構(gòu)變換 (network transform)、自適應(yīng)Huffman編碼(adaptive Huffman)等等。具體實現(xiàn)可以參考一些主流的Paper。
4.內(nèi)存精簡

內(nèi)存使用也需要精簡,低端機(jī)型有可能只有1G甚至512M的內(nèi)存空間,再復(fù)雜的應(yīng)用場景下,經(jīng)常會不夠用。精簡內(nèi)存,可以一定程度上緩解內(nèi)存不足引起的閃退;另一方面,使用更少的內(nèi)存也有利于推斷速度的提升;
具體到DL推斷過程運行時存在很大的內(nèi)存冗余,比如:


實際上,推斷過程中,大部分輸入層在做完運算后,可以被馬上釋放,所以完全存在復(fù)用內(nèi)存的可能性。
支付寶xNN 設(shè)計了一種稱為MPool的內(nèi)存管理機(jī)制,結(jié)合深度學(xué)習(xí)推斷的過程,MPool 通過分析網(wǎng)絡(luò)結(jié)構(gòu),在內(nèi)存充分復(fù)用的前提下,計算出最小的內(nèi)存使用量,在開始推斷前提前申請足夠的內(nèi)存。


MPool有如下幾個優(yōu)點:

  • 避免推斷過程中反復(fù)申請釋放內(nèi)存;
  • 內(nèi)存申請全部集中到初始化過程,避免推斷過程中出現(xiàn)內(nèi)存不足導(dǎo)致的推斷失敗,從而改善用戶體驗;
  • 充分的復(fù)用可以提高的內(nèi)存訪問效率,對性能提升也有一定的幫助;
采用MPool結(jié)構(gòu)的DL引擎,運行主流模型,內(nèi)存占用降低達(dá)到75%以上。
5.兼容性與可靠性

商用軟件,兼容性和可靠性是很重要的指標(biāo)。舉個例子,支付寶xNN在春節(jié)掃五?;顒又?,機(jī)型覆蓋率達(dá)到98%以上,基本上只要是ARM based的手機(jī),電池不要隨便爆炸,就可以支持。然而兼容性和可靠性的提升,不比開發(fā)過程順利多少,需要解決很多工程上的問題。
舉幾個例子:
為了在支付寶app中部署xNN,需要兼容app中的stl版本;
為了兼容舊版本的Android, 必須使用較舊一點的NDK版本和API, 否則會出現(xiàn)一些數(shù)學(xué)庫的兼容性問題;
為了保證連續(xù)多次運行內(nèi)存不泄漏,需要在不同android/ios版本的上做疲勞測試;
為了多任務(wù)并發(fā),需要做互斥;
為了兼容受損的模型文件,需要做多層次的模型校驗和兼容。
……
這樣的例子還有很多??偨Y(jié)一句:出來混的,遲早要還的;代碼中的任何瑕疵,最后總會被爆出來。
6.更多

基于CPU的實現(xiàn)方案,面對復(fù)雜場景/強(qiáng)實時性應(yīng)用,還是力不從心的,畢竟CPU資源是有限的,永遠(yuǎn)都無法預(yù)測用戶部署的模型的復(fù)雜度,也無法預(yù)測手機(jī)后臺運行了多少程序;異構(gòu)化也是重要的優(yōu)化方向,采用DSP/GPU來做推斷可以大大降低功耗,同時還可以提升推斷速度,DSP/GPU方案面臨的問題是兼容性比較差,每一個款手機(jī)都有可能不同,所以需要做大量的適配工作。
最后,模型安全也是需要考慮的方向,模型文件包含了用戶的知識產(chǎn)權(quán),對模型文件適當(dāng)加密和隔離運行,可以有效地阻止模型被破解和盜取的風(fēng)險。

-----------------------------
精選高品質(zhì)二手iPhone,上愛鋒貝APP

0

主題

56

帖子

20

積分

Rank: 1

沙發(fā)
發(fā)表于 2022-1-16 04:10:56 | 只看該作者
還有比支付寶優(yōu)化更差的程序嗎?
精選高品質(zhì)二手iPhone,上愛鋒貝APP

0

主題

30

帖子

3

積分

Rank: 1

板凳
發(fā)表于 2022-1-16 06:04:30 | 只看該作者
多了去了,阿里系的MNN已經(jīng)開源了,優(yōu)化相當(dāng)給力
精選高品質(zhì)二手iPhone,上愛鋒貝APP
您需要登錄后才可以回帖 登錄 | 立即注冊   

本版積分規(guī)則

QQ|Archiver|手機(jī)版|小黑屋|愛鋒貝 ( 粵ICP備16041312號-5 )

GMT+8, 2025-1-13 06:32

Powered by Discuz! X3.4

© 2001-2013 Discuz Team. 技術(shù)支持 by 巔峰設(shè)計.

快速回復(fù) 返回頂部 返回列表