QNNPACK高性能前向内核库全面剖析——引言篇
前言
前段時間因為項目需求,搞了一段時間的前向優化,主要參考了Facebook 18年開源的神經網絡加速庫QNNPACK。
QNNPACK針對INT8的量化網絡,對神經網絡的各個算子都提供了非常高效的優化方案,傳言其卓越的性能幾乎擊敗了全部已公開的加速算法,不管真假,就優化方案而已個人覺得還是比較新穎,值得好好研究的。到目前為止,QNNPACK已經開源一年多了,除了不多的官方資料之外,民間資料也是最近幾個月才陸陸續續出現一些(文章后面會貼出鏈接),覺得有必要對QNN做一個細致的記錄,這里寫個QNN專欄方便大家參考交流。
本篇僅作為開篇引言,主要說一些宏觀的東西,內容基本都會在官方文檔上面找到,短期內會補上對QNN的詳細介紹。文章內容會偏重于對QNN源碼的分析以及工程的實現,當然在介紹的過程中會結合算法對方案的優勢進行說明。詳細的宏觀算法設計可參考知乎大神的文章神經網絡加速庫 QNNPACK 實現揭秘;facebook官方文檔也可參考,就是比較粗略;前不久QNN的作者也發表文章介紹了qnn加速的核心思想(ps:作者Marat Dukhan從facebook跑路google了,文章署名也是現任公司google...., QNN估計是要停更了)。
?
QNNPACK初識
為了讓這篇文章不會顯得毫無價值,接下來會對QNN的優化方案做一個宏觀的介紹,讓各位心里有個數。QNN的數據流通為UINT8類型,圖像內存分布為NHWC模式,內核庫包含常見的Conv/Depthwise Conv、Deconv、各種Pooling、Eltwise Sum等網絡算子。本文默認讀者了解神經網絡量化原理,不清楚的也不影響看懂,想了解的話看這篇文章。
每個算子從代碼邏輯上可以分為三個階段:
第一:卷積的數據準備,這一步可以說是精華所在,整個算法實現的基礎了。這一階段涉及輸入相關的間接內存緩沖區(Indirext Buffer)的計算以及對權重數據的分塊重排;
以卷積為例,QNNPACK 實現了 4×8 的和 8×8 兩種計算核(micro kernel),分別用于支持 armv7 和 arm64 指令集的處理器。這兩種計算核在原理上區別不大,后者主要利用了更多的寄存器和雙發射(Dual Issue)以提高計算的并行度。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖一:間接緩沖區
QNN的一大亮點就是使用了Inter Buffer。常用的Im2col優化算法存在兩個問題,第一是占用大量的額外內存,第二是需要對輸入進行額外的數據拷貝。這兩點如何才能解決呢?間接卷積算法給出的答案是間接緩沖區(Indirect Buffer),如圖一右半所示。
Im2col 優化算法首先將輸入拷貝到一個矩陣中,如圖一中 Input 的相關箭頭,然后執行矩陣乘操作。間接卷積優化算法使用的間接緩沖區中存儲的其實是指向輸入的指針(這也是間接卷積優化算法要求輸入內存地址固定的原因)。在代碼實現時,第一階段就需分配好每一層輸入的內存空間將Indirect Buffer要指向的區域固定,在第二階段運行的時候將每一層的輸入都放到第一階段分配的指定內存塊中,之后就可以利用Inter Buffer(便于介紹,后文將用二級指針替換Inter Buffer的說法)來對輸入數據進行操作了。
第二:運行,在NHWC數據模式的加持下,qnnpack的解決方案使得cache的利用率空前提高,NEON并行原語及NEON匯編也得以大放光彩。
第三:內存清理,就不說了。
?
文章有關QNNPACK原理的內容部分會參考神經網絡加速庫 QNNPACK 實現揭秘以及通用矩陣乘(GEMM)優化與卷積計算,感謝兩位大佬。文章畢竟是從源碼逆向推理,如果存在分析錯漏還請各位小伙伴幫忙指正。
總結
以上是生活随笔為你收集整理的QNNPACK高性能前向内核库全面剖析——引言篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 优图yolo-v2 loss解析(ten
- 下一篇: smooth l1(huber)+bin