PRelu算子調(diào)優(yōu)經(jīng)歷-函數(shù)優(yōu)化策略
上一篇小編和大家分享了在運行客戶的一個模型時遇到了一個PRelu算子,在利用TFLm自帶的PRelu參考實現(xiàn)的代碼,其中PRelu竟然拋出了188ms的天文數(shù)字...因此小編開始準備PRelu算子的優(yōu)化工作。
分析了參考實現(xiàn)后,發(fā)現(xiàn)了兩個優(yōu)化方向,其一是PRelu中alpha參數(shù)的特殊性所帶來的內(nèi)存訪問優(yōu)化;以及量化模型所帶來的反量化問題。
本期小編就和大家一起來看下對于反量化問題的優(yōu)化細節(jié)。在開始前,再來回顧一下小編所特殊定制的模型:
(資料圖片)
這是一個具有5個節(jié)點的小巧的深度神經(jīng)網(wǎng)絡(luò),輸入時128*128*3,模型推理時間(采用KeilIDE,ofast優(yōu)化):
跳過PRelu算子,模型推理時間:
這樣我們就可以得出PRelu算子的執(zhí)行時間為13ms,接下來就將以此為基礎(chǔ)進行算法優(yōu)化,TFLm算法實現(xiàn):
output_value = MultiplyByQuantizedMultiplier( input_value, params.output_multiplier_1, params.output_shift_1);output_value = MultiplyByQuantizedMultiplier( input_value * alpha_value, params.output_multiplier_2, params.output_shift_2);上一篇小編給大家解釋了為何需要進行反量化操作以及其必要性。所謂反量化操作的本質(zhì),就是要用int8類型的中間結(jié)果來準確表達浮點結(jié)果。那么具體來說需要怎么操作呢?下面就是嚴謹?shù)耐乒江h(huán)節(jié),請讀友們不要眨眼:
首先是整數(shù)環(huán)節(jié),我們假設(shè)輸入為input, 輸出為output,參數(shù)alpha;其參數(shù)類型均為int8。而想要將其反量化為浮點數(shù),需要為其設(shè)定對應(yīng)的量化參數(shù),分別為scale以及zero_point。這樣一來,變量的浮點數(shù)表示即為:v_fp=scale* (v_i8+zero_point)
為了分析簡單,我們假設(shè)zero_point為0,那么上式可被簡化為,當然實際計算式,只需要將輸入值提前加上其zero_point再進行操作即可:
v_fp=scale* v_i8接下來我們根據(jù)輸入數(shù)據(jù)的符號進行區(qū)分,當輸入為正時,其輸出結(jié)果為,
scale_o* output=scale_i* v_i8output=scale_i / scale_0* v_i8這樣我們就可以根據(jù)輸入直接獲取int8類型的輸出結(jié)果。
當輸入為負時:
scale_o* output=(scale_a*alpha)*(scale_i* v_i8)output=((scale_a* scale_i)/scale_0)* 〖alpha*v〗_i8)這樣也就獲得了相對應(yīng)的負數(shù)輸入所對應(yīng)的輸出結(jié)果。不過,征程還沒有結(jié)束,TFLm的參考實現(xiàn)會將這兩組浮點數(shù)代表的scale參數(shù)轉(zhuǎn)換為指數(shù)形式,并以mul+shift的形式保存為:正數(shù)output_multipiler_1和output_shift_1, 負數(shù)output_multipiler_2和output_shift_2。
知道了結(jié)果是如何進行反量化操作的,回過頭我們看看TFLm的實現(xiàn):inline std::int16_t SaturatingRoundingDoublingHighMul(std::int16_t a, std::int16_t b) { bool overflow = a == b && a == std::numeric_limits::min(); std::int32_t a_32(a); std::int32_t b_32(b); std::int32_t ab_32 = a_32 * b_32; std::int16_t nudge = ab_32 >= 0 ? (1 << 14) : (1 - (1 << 14)); std::int16_t ab_x2_high16 = static_cast((ab_32 + nudge) / (1 << 15)); return overflow ? std::numeric_limits::max() : ab_x2_high16;}inline int32_t MultiplyByQuantizedMultiplier(int32_t x, int32_t quantized_multiplier, int shift) { using gemmlowp::RoundingDivideByPOT; using gemmlowp::SaturatingRoundingDoublingHighMul; int left_shift = shift > 0 ? shift : 0; int right_shift = shift > 0 ? 0 : -shift; return RoundingDivideByPOT(SaturatingRoundingDoublingHighMul( x * (1 << left_shift), quantized_multiplier), right_shift);} 首先arm的cmsis-nn庫是兼容這種量化方式的,那么他也一定有一個這樣的實現(xiàn),功夫不負有心人,這個函數(shù)叫做arm_nn_requantize,直接替換MultiplyByQuantizedMultiplier函數(shù)讓我們先看一下速度:
嗯,不錯,有效果,44ms->42ms,相當于PRelu算子執(zhí)行速度從13ms->11ms; 還可以,無痛漲點。翻看arm_nn_requantize函數(shù),其中也不乏一些手撕浮點數(shù)的神秘操作。考慮到我們的RT1170本身兼?zhèn)湟粋€FPU單元,為啥不直接用浮點數(shù)計算呢?這次我們不對scale參數(shù)進行指數(shù)化轉(zhuǎn)換,而是直接將其作為浮點數(shù)參與運算,公式就是上面我們推導(dǎo)的:
// init the float mul, shift float real_multiplier_1 = (input->params.scale) / (output->params.scale); float real_multiplier_2 = (input->params.scale) * (alpha->params.scale) / (output->params.scale);計算方式重新定義為:
output_value = MultiplyByQuantizedMultiplierFP32( input_value, multiplier_pos);static inline int32_t MultiplyByQuantizedMultiplierFP32(int32_t x, float mul){ return roundf(x * mul);是不是看著非常清爽?讓我們看下時間:
額。。。有點尷尬,竟然沒有長點,而且和TFLm的原始實現(xiàn)速度一樣。小編才提到的內(nèi)存優(yōu)化不是還沒有上?浮點運算這邊還有小插曲,讓我們繼續(xù)前行:
首先讓我們先看下浮點操作再如何進行優(yōu)化,由于我們的代碼由于采用了Ofast優(yōu)化策略,因此代碼的可閱讀性變得很差。為了進行代碼優(yōu)化,小編需要特殊編寫一組浮點運算代碼以供優(yōu)化參考,因為我們最終實現(xiàn)的是一個int32數(shù)據(jù)與浮點數(shù)相乘:
static inline int32_t MultiplyByQuantizedMultiplierFP32(int32_t x, float mul){ return roundf(x * mul);}編寫代碼如下:
int32_t v1 = (float)SysTick->VAL; float v2 = SysTick->VAL * 0.0001f; int32_t v3 = (v1 * v2); PRINTF("%d", v3);其所生成的匯編代碼為:
int32_t v1 = (float)SysTick->VAL; 800040DCLDR R2, [R0] 800040DE STRD R2, R1, [SP] 800040E2 VLDR D0, [SP] 800040E8 VSUB.F64 D0, D0, D1 800040F0 VCVT.F32.F64 S0, D0 800040F8 VCVT.S32.F32 S0, S0 800040FE VMOV R0, S0 float v2 = SysTick->VAL * 0.0001f; 800040E6 LDR R0, [R0] 800040EC STRD R0, R1, [SP, #16] 800040F4 VLDR D2, [SP, #16] 80004102 VSUB.F64 D0, D2, D1 80004106 VLDR D2, =0x4330000080000000 80004110 VCVT.F32.F64 S0, D0 80004122 VMUL.F32 S0, S0, S4 int32_t v3 = (v1 * v2); 800040FC STR R1, [SP, #12] 8000410A EORR0, R0, #0x80000000 8000410E STR R0, [SP, #8] 80004116 VLDR D1, [SP, #8] 8000411A VSUB.F64 D1, D1, D2 8000411E VLDR S4, =0x38D1B717 80004126 VCVT.F32.F64 S2, D1 8000412A VMUL.F32 S0, S2, S0到這里,小伙伴們可能已經(jīng)看到了端倪,小編也特意為大家標紅了幾條匯編代碼。那小編就先拋出疑問:我們明明定義的浮點型, 咋還用上double類型了呢?相同的代碼用GCC編譯會是什么樣的呢?int32_t v1 = (float)SysTick->VAL;300030f2: mov.w r3, #3758153728 ; 0xe000e000300030f6: vldr s15, [r3, #24]71 float v2 = SysTick->VAL * 0.0001f;300030fa: vldr s14, [r3, #24]300030fe: vcvt.f32.u32 s14, s1430003102: vldr s13, [pc, #92] ; 0x30003160 +148>30003106: vmul.f32 s14, s14, s1372 int32_t v3 = __builtin_roundf(v1 * v2);3000310a: vcvt.f32.s32 s15, s153000310e: vmul.f32 s15, s15, s1430003112: vrinta.f32 s15, s15看似正常,沒有使用double類型寄存器;那問題出在哪呢?難道Keil對于浮點數(shù)的支持不太行?翻閱了一萬件資料之后,小編在編譯時使用一個叫做-ffp-mode = full的參數(shù),這個參數(shù)的意思是:
同時還有兩個參數(shù),是-fp-mode=fast和-fp-mode=std,簡單來講就是full會保證轉(zhuǎn)換精度,因此會出現(xiàn)使用double類型的情況。而fast可能會丟失一點精度,而std介于兩者之間。那么我們定義-fp-mode=std試試?
代碼如下:
int32_t v1 = (float)SysTick->VAL; 800040D4 VLDR S0, [R0] 800040E2 VCVT.F32.U32 S0, S0 float v2 = SysTick->VAL * 0.0001f; 800040D8 VLDR S2, [R0] 800040DC VCVT.F32.U32 S2, S2 800040E6 VMUL.F32 S2, S2, S4 int32_t v3 = (v1 * v2); 800040EA VRINTZ.F32 S0, S0 800040EE VMUL.F32 S0, S2, S0嗯,優(yōu)雅,就是這么簡單。指令條數(shù)減少了很多啊,讓我們再來看看時間:
這樣一來就和arm提供的方式一致了,相比實現(xiàn)就清爽了很多。
接下來小編還有一個殺手锏,內(nèi)存優(yōu)化,不過此處的內(nèi)存優(yōu)化是有個前提,我們知道PRelu的alpha參數(shù)是按通道的,這里要做個特殊的假設(shè),假設(shè)輸入維度為 h w c,而且alpha參數(shù)是按h w共享的,即只有最后一維參數(shù),維度為11 c:
if((alpha_shape.Dims(0) == 1) && (alpha_shape.Dims(1) == 1))這樣我們就可以按c通道進行展開,并進行順序訪問;
其次,輸入數(shù)據(jù)為int8類型,原始實現(xiàn)方式中每次只取一個數(shù)據(jù)進行計算:const int32_t input_value = params.input_offset + input_data[input_index];這樣編譯器會將起編譯為LDRB指令,即每次只獲取一個字節(jié)的數(shù)據(jù)。對此進行優(yōu)化,每次讀取4個字節(jié)的數(shù)據(jù),這樣可以編譯為LDR指令,并放置于寄存器中,減少訪存次數(shù):
uint32_t steps = alpha_shape.Dims(2);uint32_t total_size = input_shape.Dims(0) * input_shape.Dims(1) * input_shape.Dims(2) * input_shape.Dims(3);for(int value_index=0;value_index T *alpha = (T *)alpha_data; // each 4, calc the time_tick uint32_t inner_loop = steps >> 2; int8_t *input_data_ptr = (int8_t*)input_data + value_index; int8_t *output_data_ptr = (int8_t*)output_data + value_index; while(inner_loop --){ int32_t input_data_32 = *((int32_t*)(input_data_ptr)); input_data_ptr += 4; uint32_t count = 4; while(count--){ int8_t input_data_8 = input_data_32 & 0xFF; input_data_32 >>= 8; 。。。。;value_index+=steps){>這樣一來,就可以順序取數(shù)據(jù),并且每次讀取4個字節(jié),看下時間:
Nice!~
PRelu的時間變?yōu)?7ms – 31ms = 6ms。經(jīng)過兩步優(yōu)化,將PRelu的執(zhí)行時間降低了7ms。用客戶的模型測試一下,PRelu算子運行時間從之前的188ms降低到了51ms。Perfect!
不過,小編精益求精,還有一些微小的優(yōu)化空間,后續(xù)將會進一步優(yōu)化。
歡迎朋友們持續(xù)關(guān)注~
關(guān)鍵詞:
相關(guān)文章
新奧股份:上半年歸母凈利潤22.04億再創(chuàng)新高,天然氣直銷業(yè)務(wù)營收貢獻加大
8月24日晚間,滬深300標的新奧股份(600803 SH)披露了2023上半年報告
內(nèi)蒙古自治區(qū)通遼市公安局科爾沁分局:全域防控 數(shù)據(jù)賦能 打造科爾沁特色城市快反體系
通遼市公安局科爾沁分局圍繞答好“市縣主戰(zhàn)、派出所主防”命題,聚焦公
打造消費新地標!北京將啟動環(huán)球度假區(qū)二期建設(shè)
近日,北京對外發(fā)布《關(guān)于進一步推動首都高質(zhì)量發(fā)展取得新突破的行動方
精彩推送
寧海縣自然資源和規(guī)劃局(關(guān)于寧海縣自然資源和規(guī)劃局簡述)
,你們好,今天0471房產(chǎn)來聊聊一篇海縣自然資源和規(guī)劃局,海縣自然資源
交通運輸部:7月網(wǎng)約車訂單環(huán)比提升7.6%
8月21日,交通運輸部發(fā)布7月網(wǎng)約車行業(yè)運行基本情況,數(shù)據(jù)顯示,截至20
「浙江」嘉興市博銳消防設(shè)備有限公司等5家企業(yè)列入經(jīng)營異常名錄公告 嘉市監(jiān)經(jīng)異入告(2023)第28號
中國質(zhì)量新聞網(wǎng)訊2023年8月25日,浙江省嘉興市市場監(jiān)督管理局發(fā)布嘉興
快訊:商洛市今日12時啟動Ⅳ級防汛應(yīng)急響應(yīng)
快訊:商洛市今日12時啟動Ⅳ級防汛應(yīng)急響應(yīng)商洛新聞網(wǎng)訊:今天(8月25
夢幻場景難掩種姓家暴,情節(jié)道具遭受侵權(quán)指責(zé),熱播劇觸痛印社會傷口
“達利特版”灰姑娘的故事印度WION電視臺報道稱,和第一季采取的拍攝手
新奧股份:上半年歸母凈利潤22.04億再創(chuàng)新高,天然氣直銷業(yè)務(wù)營收貢獻加大
8月24日晚間,滬深300標的新奧股份(600803 SH)披露了2023上半年報告
昌吉西部建設(shè)有限責(zé)任公司開展“建證幸福 ‘砼’行‘實’載”主題團建活動
為加強企業(yè)員工高效溝通,舒緩工作壓力,近日,中建西部建設(shè)所屬昌吉西
內(nèi)蒙古電力(集團)有限責(zé)任公司副總經(jīng)理梁景坤接受紀律審查和監(jiān)察調(diào)查
內(nèi)蒙古電力(集團)有限責(zé)任公司副總經(jīng)理梁景坤涉嫌嚴重違紀違法,目前
漲停雷達:贏合科技:上半年經(jīng)營性現(xiàn)金流凈額大增471.14%聚焦全球化發(fā)展 贏合科技觸及漲停
今日走勢:贏合科技(300457)今日觸及漲停板,該股近一年漲停1次。異
《中國好聲音》暫停播出!母公司股價大跌近13%;連續(xù)第7日放量!環(huán)保股繼續(xù)走強
今日早盤,A股繼續(xù)弱勢震蕩,上證指數(shù)開盤即再創(chuàng)年內(nèi)新低,隨后科創(chuàng)50
港股異動 | 康臣藥業(yè)(01681)績后漲超7% 上半年歸母溢利同比增長17.24% 尿毒清顆粒維持市場領(lǐng)先地位
智通財經(jīng)APP獲悉,康臣藥業(yè)(01681)績后漲超7%,截至發(fā)稿,漲6 16%,報5
【喜報】熱烈祝賀副會長單位“勝龍牛業(yè)”獲批“粵港澳大灣區(qū)‘菜籃子’生產(chǎn)基地”
近日,經(jīng)粵港澳大灣區(qū)“菜籃子”生產(chǎn)基地評審委員會公布,我會副會長單
高通收購Autotalks再遇阻:面臨美國聯(lián)邦貿(mào)易委員會深入調(diào)查
8月23日消息,據(jù)外媒報道,當?shù)貢r間周二,兩位知情人士透露,美國聯(lián)邦
中原集團回應(yīng)“深圳中原拖欠員工傭金”:不具墊付能力
中新經(jīng)緯8月25日電25日,中原地產(chǎn)官微發(fā)布對近期深圳中原相關(guān)網(wǎng)絡(luò)報道
實體店無質(zhì)量問題不退合法嗎 手機實體店退貨技巧
你們好,最近0471房產(chǎn)發(fā)現(xiàn)有諸多的對于實體店無質(zhì)量問題不退合法嗎,手
被曝已獲生產(chǎn)資質(zhì) 小米汽車“呼之欲出”
被曝已獲生產(chǎn)資質(zhì)小米汽車“呼之欲出”---中國經(jīng)濟網(wǎng)北京8月24日訊據(jù)路
馬斯克要求Cybertruck的零件精度達到微米級 網(wǎng)友:就這裝配水平?
據(jù)IT之家,當?shù)貢r間周三,馬斯克發(fā)布了一張自己在得州超級工廠試駕量產(chǎn)
市場監(jiān)管總局加大水產(chǎn)品食品安全監(jiān)管及食鹽價格監(jiān)管力度
8月24日,日本政府無視國際社會的強烈質(zhì)疑和反對,單方面強行啟動福島
港股異動 | 康師傅控股(00322)午后漲超6% 上半年歸母溢利同比增長30.66% 兩大業(yè)務(wù)板塊保持增長態(tài)勢
智通財經(jīng)APP獲悉康師傅控股00322午后漲超6截至發(fā)稿漲568報1154港元成交
2023虹口區(qū)第十一批共有產(chǎn)權(quán)保障住房選房結(jié)果一覽
虹口區(qū)第十一批(2023年)共有產(chǎn)權(quán)保障住房選房結(jié)果公告(2023年08月18日)
品味栗鄉(xiāng)韻味 共話產(chǎn)業(yè)發(fā)展 “中國板栗之鄉(xiāng)”遷西迎盛會
2023中國(遷西)板栗暨栗蘑產(chǎn)業(yè)發(fā)展大會現(xiàn)場,多個項目集中簽約。姜文
新一代安耐糖能否打破CGM市場國際品牌的主導(dǎo)態(tài)勢?
根據(jù)觀研報告網(wǎng)發(fā)布的《中國血糖監(jiān)測行業(yè)發(fā)展趨勢分析與投資前景研究報
景津裝備(603279):2023H1業(yè)績持續(xù)高增 多領(lǐng)域需求有望持續(xù)釋放
景津裝備(603279):2023H1業(yè)績持續(xù)高增多領(lǐng)域需求有望持續(xù)釋放
葡萄膜病學(xué)(關(guān)于葡萄膜病學(xué)簡述)
,你們好,今天0471房產(chǎn)來聊聊一篇萄膜病學(xué),萄膜病學(xué)簡述的文章,網(wǎng)友
潔能股份將在新三板掛牌公開轉(zhuǎn)讓 2022年營收3.17億
潔能股份將在新三板掛牌公開轉(zhuǎn)讓2022年營收3 17億2023 8 2219:47:01挖
現(xiàn)代確認:新轎車預(yù)售25.98萬起!10月上市,還看領(lǐng)克03+?
8月25日,現(xiàn)代伊蘭特N開啟預(yù)售,價格為25 98萬元,選裝SportPackage預(yù)
江西省2023年產(chǎn)假最新標準,江西產(chǎn)假新規(guī)多少天
對準媽媽來說,最關(guān)注的一個點就是產(chǎn)假,畢竟產(chǎn)假時間越長,準媽媽可以
