比 TFLite 快 2 倍!FB 開源移動深度學習優化庫 QNNPACK
公眾號/AI前線
策劃編輯|Natalie
作者|MARAT DUKHAN 等
譯者|無明
編輯|Debra
AI 前線導讀:Facebook 正式開源 QNNPACK,一款針對移動 AI 進行優化的高效能核心庫。這個庫加速了多項操作,包括高階神經網路架構所使用的深度卷積。QNNPACK 已經被整合到 Facebook 應用程式中,並被部署到了數十億臺裝置上。在 MobileNetV2 等基準測試中,QNNPACK 在各種手機上的效能表現比之前最好的實現高出 2 倍。
更多幹貨內容請關注微信公眾號“AI 前線”(ID:ai-front)
為了將最新的計算機視覺模型引入移動裝置,Facebook 開發了 QNNPACK,一個針對低強度卷積進行優化的函式庫。
QNNPACK 是 Quantized Neural Network PACKage 的簡寫,已經被整合到 Facebook 的一系列應用程式中,並被部署在全球的 10 億臺移動裝置上。有了這個新庫,Facebook 可以執行高階計算機視覺任務,例如在手機上實時執行 Mask R-CNN 和 DensePose,或者在低配置的移動裝置上執行影象分類,所需時間低於 100 毫秒。
Facebook 將 QNNPACK 開源,為量化推理提供全面支援,並作為 PyTorch 1.0 平臺的一部分。QNNPACK 已經可以支援 Caffe2 模型表示,此外,Facebook 也正在開發其他實用程式,以便將模型從 PyTorch 的 Python 前端匯出成圖表示,並在移動平臺以外的其他平臺上對這些操作進行優化。
由於移動裝置的處理能力只有資料中心伺服器的十分之一甚至千分之一,因此,要在移動裝置上執行人工智慧,需要經過多次調整才能充分利用硬體的所有可用效能。QNNPACK 提供了針對量化張量的卷積、反捲積和完全連線操作,具備很高的效能。在 QNNPACK 之前,並不存在針對幾種常見神經網路原語(分組卷積、擴張卷積)的高效開源實現,因此,ResNeXt、CondenseNet 和 ShuffleNet 等研究模型未能得到充分利用。
實現矩陣乘法
不直接從事科學計算或深度學習的軟體工程師可能不熟悉庫是如何實現矩陣乘法的,因此,在深入研究 QNNPACK 的細節之前,需要先描述一下矩陣乘法。
在下面的示例中,A 是輸入,B 是權重,C 是輸出。 B 推理執行期間保持不變,因此可以在沒有執行時成本的情況下轉換為任意記憶體佈局。
M x K 的矩陣 A 和 K x N 的矩陣 B 之間的乘法將產生 M × N 的矩陣 C。C 中的每個元素可以認為是 A 的相應行和 B 的相應列之間的點積。
Facebook 可以在點積原語之上實現整個矩陣乘法,但是這種實現非常低效。在點積中,他們為每個乘加運算載入兩個元素,而在現代處理器上,這種實現會受到記憶體或快取頻寬的限制,這與乘加單元的計算能力無關。但如果做出略微修改——同時計算 A 的多個行和 B 的多個列的點積——就可以顯著提高效能。
修改後的原語載入 A 的 MR 元素和 B 的 NR 元素,然後執行 MR x NR 乘加運算。雖然 MR 和 NR 的最大值受暫存器數量和處理器體系結構的限制,但在大多數現代系統中,它們提供了足夠大的空間,並且所有的高效能矩陣乘法實現都是建立在這個原語(通常稱為 PDOT 微核心,即面板點積)之上。
QNNPACK 如何提高效率?
QNNPACK 使用與 Android 神經網路 API 相容的線性量化方案。它假定量化值 q[i] 表示為 8 位無符號整數,並與實值表示 r[i] 有如下的關係:
r[i] = scale * (q[i] – zero_point)
其中 scale 是正浮點數,而 zero_point 是無符號 8 位整數,與 q[i] 一樣。
雖然 QNNPACK 利用了 PDOT 微核心,就像其他 BLAS 庫一樣,但它更專注於具有 8 位元素的量化張量,並且移動 AI 用例為效能優化帶來了截然不同的視角。大多數 BLAS 庫針對科學計算用例,其矩陣可以大到包含數千個雙精度浮點元素,但 QNNPACK 的輸入矩陣源於低精度、特定於移動裝置的計算機視覺模型,並且具有非常不同的維度。在 1×1 卷積中,K 是輸入通道的數量,N 是輸出通道的數量,M 是影象中的畫素數量。在實際的移動優化網路中,K 和 N 不大於 1,024,通常在 32-256 之間。
移動架構的限制要求 MR 和 NR 不超過 8。因此,即使是在具有 1,024 個通道的大型模型中,PDOT 微核心讀取的記憶體塊最多為 16KB,即使是超低配置的裝置也能把它塞進 L1 快取。這是 QNNPACK 與其他 GEMM 實現之間的重要區別:其他庫重新打包 A 和 B 矩陣,以便更好地利用快取層次結構,希望在大量計算中分攤打包開銷,而 QNNPACK 針對 A 和 B 可以塞進 L1 快取進行了優化。因此,它移除了對於計算來說不是絕對必要的記憶體轉換。
在量化矩陣乘法中,8 位整數的乘積通常被累加到 32 位中間結果中,然後重新量化以產生 8 位輸出。傳統的實現主要針對大矩陣進行優化,因為 K 可能太大,導致無法將 A 和 B 放入快取。為了有效利用快取層次結構,傳統的 GEMM 實現將 A 和 B 沿著 K 維分割成固定大小的子面板,因此每個面板都可以塞進 L1 快取。這種快取優化要求 PDOT 微核心輸出 32 位中間結果,最終將它們相加並重新量化為 8 位整數。
由於 QNNPACK 針對行動網路進行了優化,A 和 B 面板始終可以塞進 L1 快取,因此可以在一個微核心呼叫中處理 A 和 B 面板。由於無需在微核心之外累積 32 位中間結果,QNNPACK 將 32 位中間結果的重新量化融合到微核心中,並輸出 8 位值,從而節省了記憶體頻寬和快取佔用空間。
因為可以將 A 和 B 的整個面板塞入到快取中,所以可以在 QNNPACK 中進行另一個優化:避免矩陣 A 的重打包。與包含了靜態權重,並且可以一次性轉換為任意記憶體佈局的矩陣 B 不同,矩陣 A 包含了卷積輸入,每次推理都會發生變化。因此,每次重打包矩陣 A 都會產生額外的開銷。傳統的 GEMM 之所以要重打包矩陣 A 主要基於兩個原因:有限的快取關聯性和微核心效率。在沒有重打包的情況下,微核心必須基於可能很大的步幅讀取 A 的行。如果步幅恰好是 2 的次冪,來自 A 不同行的元素可能會落入相同的快取中。如果這種衝突數量超過了快取關聯性,效能就會急劇下降。幸運的是,當面板可以塞入 L1 時,這種情況就不會發生。
打包對微核心效率的影響與 SIMD 向量指令的使用密切相關。這些指令載入、儲存或計算固定大小的元素向量,而不是單個標量。關鍵是要充分利用向量指令來提升矩陣乘法的效能。在傳統的 GEMM 實現中,微核心將重打包的 MR 元素載入到向量暫存器的 MR 通道中。而在 QNNPACK 實現中,MR 元素在記憶體中不連續,微核心必須將它們載入到不同的向量暫存器中。暫存器壓力的增加迫使 QNNPACK 使用更小的 MRxNR,但差異其實很小,而且可以通過消除打包開銷來彌補。例如,在 32 位 ARM 架構上,QNNPACK 使用 4×8 微核心,其中 57%的向量指令是乘加。另一方面,gemmlowp 庫使用稍微高效的 4×12 微核心,其中 60%的向量指令是乘加。
微核心載入 A 的幾個行,乘以 B 的幾個列,然後累加結果,最後執行重新量化並輸出量化的和。A 和 B 的元素被量化為 8 位整數,但乘法結果被累加到 32 位。大多數 ARM 和 ARM64 處理器沒有直接執行這種操作的指令,因此必須將其分解為多個操作。QNNPACK 提供了兩個版本的微核心,它們的區別在於指令序列上,這些指令序列用於 8 位值相乘以及將它們累加到 32 位結果。
QNNPACK 的效能優勢
Facebook 的測試表明,QNNPACK 在端到端基準測試中具備一定的效能優勢。在量化 MobileNet v2 架構中,基於 QNNPACK 的 Caffe2 運算在各種手機上的速度比 TensorFlow Lite 快約 2 倍。Facebook 同時還開源了 Caffe2 量化 MobileNet v2 模型(https://github.com/caffe2/models/tree/master/mobilenet_v2_quantized),與相應的 TensorFlow 模型相比,top-1 準確率提高了 1.3%。
MobileNetV1
MobileNet 架構的第一個版本率先使用深度卷積來讓模型更適用於移動裝置。MobileNetV1 幾乎完全由 1×1 卷積和 3×3 深度卷積組成。Facebook 從 TensorFlow Lite 轉換了量化 MobileNetV1 模型,並在 TensorFlow Lite 和 QNNPACK 的 32 位 ARM 版本上進行了基準測試。兩個執行時都使用了 4 個執行緒,Facebook 發現,QNNPACK 比 TensorFlow Lite 快了 1.8 倍。
MobileNetV2
作為移動視覺任務最先進的架構之一,MobileNetV2 引入了瓶頸構建塊,以及瓶頸之間的快捷連線。Facebook 基於 MobileNetV2 分類模型對 QNNPACK 的 Caffe2 操作進行了基準測試,並與 TensorFlow Lite 實現進行對比。Facebook 釋出了量化 Caffe2 MobileNetV2 模型(https://github.com/caffe2/models/tree/master/mobilenet_v2_quantized),並使用了官方儲存庫中的量化 TensorFlow Lite 模型(https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/lite/g3doc/models.md)。下圖顯示了常用的測試資料集的 top1 準確率:
Facebook 在各種手機上通過 Facebook AI 效能評估平臺進行了基準測試。對於 TensorFlow Lite 的執行緒設定,Facebook 嘗試了一到四個執行緒,並報告了最快的結果。Facebook 發現,在這些手機上使用四個執行緒時,TensorFlow Lite 表現最佳,因此 Facebook 在 TensorFlow Lite 和 QNNPACK 的基準測試中使用了四個執行緒。下圖顯示了結果,在典型的智慧手機和高階手機上,基於 QNNPACK 的操作明顯快於 TensorFlow Lite。
未 來
藉助 QNNPACK,Facebook 的系列應用程式已經將人工智慧部署到全球的移動裝置上。Facebook 正在探索 QNNPACK 的新效能增強,包括 FP16 格式的低精度計算,利用 NEON 點積(VDOT)指令和 16 位累積,讓 AI 在移動裝置上變得更輕量級。Facebook 還期待通過 PyTorch API 公開 QNNPACK 操作支援,並通過擴充套件為移動開發人員提供工具。Facebook 希望 QNNPACK 能夠通過提升模型的移動效能,讓 AI 研究人員和開發人員從中受益。
英文原文:https://code.fb.com/ml-applications/qnnpack/