天天看點

YOLOv6量化部署實戰指南

作者:極市平台

作者丨慶源、李亮、奕铎、張勃、王新、祥祥等

來源丨美團基礎研發平台資料科學與平台部和視覺智能部

編輯丨極市平台

1. 背景和難點

YOLOv6 是美團釋出的一款開源的面向工業應用的 2D 目标檢測模型 [1],主要特點是速度快、精度高、部署友好,在美團衆多視覺業務場景中都有着廣泛的應用。通過量化(Quantization)提升推理速度是實際工業應用中的基本操作,但由于 YOLOv6 系列模型采用了大量的重參數化子產品,如何針對 YOLOv6 進行高效和高精度的量化成為一個亟待解決的問題。本文旨在解決 YOLOv6 量化方面的難題,并以 YOLOv6s 模型為例,從訓練後量化(Post-Training Quantization, PTQ)和量化感覺訓練(Quantization-Aware Training, QAT)兩個方面進行分析,探索出了一條切實可行的量化方案。

YOLOv6 采用了多分支的重參數化結構 [2] (如圖 1A 所示),通過在網絡結構層面加入人工先驗可以在訓練階段讓模型更好收斂。在推理階段,多分支可以等價合并為單路,進而提升運作速度。但現有的訓練後量化方法,不能很好應對多分支結構帶來的劇烈變動的數值範圍,導緻量化後産生嚴重的精度損失 [3]。另外,如何針對多分支結構設計量化感覺訓練(QAT)方法也面臨着較大的挑戰。蒸餾常被用來輔助 QAT 提升性能,但如何應用 2D 目标檢測的蒸餾方法來輔助 YOLOv6 模型的量化,也需要設計合理的方案在實際應用中進行檢驗。

YOLOv6量化部署實戰指南

圖1 多分支結構重參數化過程(A)結構變化(B)參數變化 (來源:[2])

2. 量化方案實戰

2.1 重參數化優化器

YOLOv6 網絡中大量使用重參數化結構,在提高模型訓練精度的同時能夠顯著降低模型部署推理延時,但也帶來了模型量化部署方面的難題。對重參數化網絡的直接量化一般會帶來不可接受的精度損失,例如 RepVGG-B1 [2] 網絡在 ImageNet 資料集上的浮點精度為 78.42%,采用 TensorRT 後量化(PTQ)的量化模型精度則降低為 54.55%。

此外,由于重參數化結構在訓練和部署時結構不同,是以無法直接适配現有的量化感覺訓練(QAT)方法,如何使用 QAT 方法來提高 YOLOv6 量化模型的精度,同樣存在着挑戰。近期,一篇重參數化優化器的工作 RepOpt [3] 較好地解決了重參數化結構的量化問題。

2.1.1 RepOpt

RepOpt [3] 對重參數化結構量化困難的問題進行了研究,發現重參數結構的分支融合操作,顯著放大了權重參數分布的标準差。異常的權重分布産生了過大的網絡激活層數值分布,進一步導緻該層量化損失過大,是以模型精度損失嚴重。

鑒于此,我們統計了基于 RepVGG 結構的 YOLOv6 模型(YOLOv6s_repvgg)各層的權重及激活數值分布,分析了 YOLOv6 中的重參數化層的資料分布。下圖 2 以 “Rep_p4.block.0.rbr_reparam” 層為例,給出其特征圖數值分布直方圖,我們發現其數值廣泛分布在 [0, 57] 的區間内。顯然,采用現有的 INT8 量化方法,無論怎樣選擇量化縮放參數 (scale),都會産生較大的量化誤差。

YOLOv6量化部署實戰指南

圖2 YOLOv6 網絡使用 RepVGGBlock 和 RepOptBlock 版本的單層激活值資料分布

為解決這一問題,RepOpt 提出了一種基于優化器的重參數化設計(如下圖 3 所示),通過梯度掩碼(Gradient Mask)的方式在網絡訓練反向傳播的過程中加入先驗,保證了訓練精度可達到 RepVGG 相近的水準,而網絡結構則在訓練和推理階段始終保持普通的 VGG 結構,這種訓練方法請參考 RepOpt [3]。該工作中提出的 RepOpt-B1 網絡模型,在浮點精度與 RepVGG-B1基本一緻的情況下,量化模型精度提升超過 20%,極大地改善了重參數化網絡的量化掉點問題。此外,RepOpt模型的訓練速度快,記憶體占用也比較低。

YOLOv6量化部署實戰指南

圖3 RepVGG 和 RepOpt 結構示意圖

2.1.2 RepOpt 版本的 PTQ

我們實作了 RepOpt 版本的 YOLOv6s網絡(YOLOv6s_repopt),達到了與 YOLOv6s_repvgg 一緻的浮點精度 42.4% (300 epoch),兩個版本的網絡結構在部署階段保持一緻。我們首先分析了 YOLOv6s_repopt 模型的資料分布特征。

如圖 2 所示,給出了“Rep_p4.block.0.rbr_reparam” 層的特征圖數值分布直方圖,可以看到數值緊密分布在 [0, 10] 的區間内,相比 YOLOv6s_repvgg 的數值分布對于量化操作更加友好。進一步采用 TRT 的後量化方法進行模型量化部署,可以看到 YOLOv6s_repvgg 的量化網絡精度降低了 7.4%,在實際工程中基本不可用。而 YOLOv6s_repopt 網絡的量化模型精度為 40.9%,精度損失僅為 1.5%,相比原版模型有了極大的改善。

YOLOv6量化部署實戰指南

表1 使用 RepOpt 在标準分類和檢測任務上的 INT8 精度提升

2.1.3 RepOpt 版本的 QAT

此外,使用 RepOpt 結構解決了原本的 RepVGG 網絡無法直接使用現有量化感覺訓練的問題。對于結構重參數化的 RepVGG 網絡,如何使用 QAT 來恢複量化模型精度,我們一直存有困擾。如下圖 4(左)所示,如果對重參數化操作之前的多分支網絡進行 QAT,對每個分支分别添加僞量化算子進行量化感覺訓練,由于每個分支的量化參數不同,導緻多分支結構無法等效融合進行高性能部署;如果對重參數化操作之後的單分支網絡進行 QAT, 由于網絡中不再有 BN 層,使用 QAT 方法進行微調并不容易恢複到浮點精度。而對于 RepOpt 結構網絡則不存在這一問題,因為 RepOpt 在訓練和部署中網絡結構是保持一緻的。

YOLOv6量化部署實戰指南

圖4 RepVGG 和 RepOpt 結構的 QAT 過程示意圖

如圖 4 (右)所示,對 RepOpt 的卷積等算子加入僞量化節點進行量化感覺訓練,提升量化模型精度,然後直接部署該量化模型,而不需要再進行模型融合的操作。後文,我們将給出具體的 QAT 算法及對模型精度的提升結果。

2.2 基于量化敏感度分析的部分量化

YOLOv6s_repopt 在 PTQ 後的 mAP 達到了 40.9%,雖然比之前的 35.0% 有了很大的改善,但仍然有 1.5% 的精度損失,還無法滿足業務需求。是以,我們采用了部分量化(Partial PTQ),一種使網絡中的部分量化敏感層恢複浮點計算,來快速恢複量化模型精度的方法。首先需要對網絡中的每一層都進行量化敏感度分析。我們在 YOLOv6s-repopt 網絡上對常用的敏感度分析方法均方誤差(MSE)、信噪比(SNR)、餘弦相似度(Cosine Similarity)進行了對比測試。量化校準(calibration)測試使用 4 個 batch 的資料,敏感度計算用 1 個 batch,batch 大小設定為 32。測試時,每次隻對一層進行量化,擷取該層的激活資料後計算敏感度數值,代表了該層的量化敏感度。作為對比,我們可以直接計算網絡在 COCO val 資料集上的 mAP,使用檢測精度作為該層的量化敏感度,即檢測精度越高,該層敏感度越低(下文稱為 mAP 方法)。

YOLOv6量化部署實戰指南

表2 常用的量化敏感度計算方法及含義

測試結果如下圖 5 所示,我們對測試結果進行歸一化後,從不同敏感度分析結果中選擇敏感性最高的 6 層跳過,計算部分量化精度。

YOLOv6量化部署實戰指南

圖5 YOLOv6s_repopt 各層敏感度對比

部分量化精度如下表 3 所示,可以看到:mAP 方法取得了最好的效果,能夠有效代表 YOLOv6 敏感度分析結果。但由于 mAP 方法需要頻繁地計算驗證集精度,耗時太久且容易過拟合驗證集,是以在實際項目中為了追求效率,我們建議使用 MSE 方法。

YOLOv6量化部署實戰指南

表3 使用不同量化敏感名額得到的 Top-6 敏感層及部分量化精度對比

2.3 基于通道蒸餾的量化感覺訓練

至此,我們優化後的 PTQ 的精度達到了 42.0%,進一步提高模型精度需要引入量化感覺訓練(QAT)。量化感覺訓練(Quantization Aware Training, QAT)可以改善 PTQ 量化精度損失,通過在訓練過程中對卷積等算子加入僞量化操作(如圖 4 所示),使得網絡參數能更好地适應量化帶來的資訊損失,進而顯著降低量化後的精度損失。

模型蒸餾作為一種有效的提升小模型精度的方法,在 QAT 過程中被廣泛使用,來提升量化模型的精度。以下,我們将探索針對 YOLOv6 網絡的量化感覺訓練方法。

2.3.1 通道蒸餾

傳統的分類網絡在蒸餾時,往往對最後一層輸出的 logits 進行蒸餾;但是在檢測網絡中一般采用“特征圖”蒸餾的方法,直接讓學生網絡(student)輸出的特征圖拟合教師網絡(teacher)輸出的特征圖(一般不會選取整個特征圖,而是一些感興趣區域)。

這種方法的缺陷是特征圖中的每個 pixel 對蒸餾的損失貢獻相同。我們采用了每通道分布蒸餾 [6],即讓 student 輸出的每個通道的分布拟合 teacher 輸出的每個通道的分布。兩種方法的差別如下圖 6 所示:

YOLOv6量化部署實戰指南

圖6 使用空間次元蒸餾和通道次元蒸餾的對比示意

2.3.2 YOLOv6 量化感覺蒸餾架構

針對 YOLOv6s,我們選擇對 Neck(Rep-PAN)輸出的特征圖進行通道蒸餾(Channel-Wise Distillation, CW)。另外,我們采用“自蒸餾”的方法,教師模型是 FP32 精度的 YOLOv6s,學生模型是 INT8 精度的 YOLOv6s。下圖 7 是一個簡化示意圖,隻畫出了 Neck 的一個分支:

YOLOv6量化部署實戰指南

圖7 應用于 YOLOv6s 的通道蒸餾方案示意圖

如下表 4 所示,在 Partial QAT 中引入通道蒸餾方案(CW),量化精度進一步提升了 0.3%。

YOLOv6量化部署實戰指南

表4 Partial QAT 使用通道蒸餾提升對比

3. 部署時優化

3.1 圖優化

量化部署時,可以直接利用 TensorRT 的 PTQ 接口進行生成量化引擎,但是這種方法往往精度損失較大。是以,一般要先進行 QAT,使量化模型精度滿足業務需求,然後導出帶有“Quant”、“DeQuant”節點的 ONNX,最後再利用 TensorRT 建構量化引擎。我們發現這兩種方案最終生成的圖結構并不相同,導緻部署模型的實際運作效率存在很大的差異,通常 QAT 方法生成的模型效率更低。我們在 NVIDIA T4 機器上對量化模型進行了對比測試(見下表 5)。盡管 QAT INT8 模型的 QPS 比 FP16 高了~27%,但是離 PTQ INT8 還有較大差距。我們對此現象進行了細緻的分析,發現原因是 QAT 引入的“Quant”,“DeQuant”節點打破了原有 TensorRT 的融合政策,導緻了很多算子無法融合,進而影響了最終量化引擎的性能。在這一節中,我們以 YOLOv6s_repopt 為例,展示一種定位具體瓶頸的圖優化方法。在量化實踐中,圖優化是一個很實用的手段,我們可以依法炮制,提升模型的 QPS。

YOLOv6量化部署實戰指南

表5 PTQ 和 QAT 模型的 QPS 對比

3.1.1 性能分析

首先,我們利用 nsys 工具 [5] 對 QAT INT8 的模型和 PTQ INT8 模型進行了性能分析,如下表所示:

YOLOv6量化部署實戰指南

表6 PTQ/QAT 節點的 Kernel 運作時間分析

從中我們發現,QAT INT8 有 10.8% 的 kernel 執行了 permutationKernelPLC3 操作,這些操作對應 quantize_scale_node 節點,如下圖 8 所示:

YOLOv6量化部署實戰指南

圖8 permutationKernelPLC3 操作定位

3.1.2 圖結構分析

為什麼 QAT INT8會有大量的 permutationKernelPLC3 操作?我們利用 trtexec 和 pltEngine 工具,畫出了 PTQ INT8 和 QAT INT8 的計算圖,并進行了仔細的分析。下圖 9 是其中一個子圖的對比:

YOLOv6量化部署實戰指南

圖9 PTQ 與 QAT 子圖差別

QAT INT8 計算圖中 neck.reduce_layer1.conv 融合節點輸出精度是 FP32,并且跟了 2 個 quantize_scale_node 節點,而 PTQ INT8 圖中的 neck.reduce_layer1.conv 融合節點輸出的是 INT8。很顯然,QAT 圖中 FP32 和 INT8 之間的轉換會帶來額外的開銷。我們又利用 Netron 來分析 QAT INT8 的 ONNX 圖結構,找到了 neck.reduce_layer1.conv 這個位置,圖 10 給出該節點示意。

YOLOv6量化部署實戰指南

圖10 因 Scale 不同而産生了雙分支

通過分析 ONNX 圖結構,我們發現了QAT INT8 引擎中 neck.reduce_layer1.conv 輸出為 FP32,并且為兩個分支保留了quantize_scale_node 的原因。因為 neck.upsample1.upsample_transpose 分支的輸入量化 scale 為 0.083,而 neck.Rep_n3.conv1 分支的輸入量化 scale 為 0.105,這兩個節點輸入尺度是不同的,導緻 neck.reduce_layer1.conv 無法直接輸出為 INT8。

可以看出,對于同一個輸出,輸入到多路分支後為何 scale 不同的,原因是右邊的分支經過了 concat 操作,會導緻輸出的資料分布發生變化,再進行激活校準(Activation Calibration)時,會得到的不同的最佳截斷值 (Activaition Max)。

3.1.3 圖結構優化

根據上面的分析,如果一個節點的輸出,輸入到不同的分支節點中,并且分支節點的量化 scale 不同,則 quantize_scale_node 節點無法融合,進而導緻了額外的開銷。如何解決這個問題?我們使用了一個簡單的方法,就是強制使所有分支節點的量化 scale 相同(根據經驗,在同一數量級上的 scale 可以安全合并),即直接修改 QAT 網絡中的 Quantizer 節點的參數。我們整理了 YOLOv6s_repopt 中所有需要進行 scale 融合的節點(如表 7 所示),由于 TensorRT 的 8 bit 的量化範圍是[-127,127],是以隻需要将多路分支的 Activation Amax 設為同一個值,一般取多路分支中的最大值。

YOLOv6量化部署實戰指南

表7 需要融合 Scale 的節點清單

3.1.4 性能測試

經過以上的多路分支的 scale 融合後,我們再次利用 trtexec 和 pltEngine 工具,畫出了 QAT INT8 進行優化前後的圖結構。可以發現,quantize_scale_node 節點已經全部被融合。

YOLOv6量化部署實戰指南

圖11 圖優化後 INT8 圖節點變化

我們測試了經過圖優化的 QAT 模型,QPS 達到了 528,性能非常接近 PTQ 的 556,而且 mAP 依然保持優化前的 42.1%。

YOLOv6量化部署實戰指南

表8 圖優化後 QPS 對比

3.2 線上服務優化

我們在 NVIDIA T4 伺服器上進行了端到端的吞吐測試,利用“多執行個體”并發處理的技術,YOLOv6s_repopt INT8 QPS 達到了 552,相較 FP16 提升了~40%。我們對伺服器的各項名額進行了監測,發現此時 T4 GPU 的使用率隻有 95%,還有壓榨空間,而 16 核 CPU 使用率已經超過了 1500%,幾乎滿負荷運轉。我們推測整個線上服務的“瓶頸”可能在 CPU,而圖檔預處理會使用大量 CPU 資源。

YOLOv6量化部署實戰指南

表9 伺服器資源配置

3.2.1 DALI 預處理

為了解決 CPU 預處理帶來的“瓶頸”,我們采用了 NVIDIA 的 DALI 庫,将預處理直接放到 GPU 中運算。該庫可以在 GPU 上對二進制圖檔進行解碼和預處理,極大的緩解 CPU 瓶頸,下圖 12 為 DALI 的經典流程。

YOLOv6量化部署實戰指南

圖12 DALI 加速圖像預處理流程

3.2.2 吞吐測試

如下圖 13 所示,INT8 + DALI 的吞吐達到了 1182 imgs/s,比 INT8 吞吐提升了 1.14 倍。引入 DALI 預處理後,T4 GPU 使用率達到了100%,而 16 核 CPU 的使用率則下降到了 1100% 左右,部分 CPU 資源得到了“解放”。另外,我們也測試 FP16 + DALI 的吞吐,反而有略微的下降。我們推測是 DALI 搶占了部分 GPU 計算資源,而 FP16 服務的瓶頸在 GPU,是以對整體性能産生了負面影響。

YOLOv6量化部署實戰指南

圖13 使用 DALI 後吞吐測試提升對比

4. 總結

綜上所述,本文基于 YOLOv6 V1.0 版本,以 YOLOv6s 為例探讨了基于重參數化結構設計的 2D 檢測模型的量化難點和具體方案,在模型精度基本保持的前提下,通過量化加速,提升了約 40% 的 QPS。部署時的預處理優化則額外提升了 214%,極大地提升了工業部署吞吐能力。下表列出了本文嘗試的方法及疊加效果。

YOLOv6量化部署實戰指南

表10 本文使用的量化方案及效果對比

本文使用的速度測試環境見表 11, 測試輸入 batch size 為 1,尺寸為 640x640。

YOLOv6量化部署實戰指南

表11 速度測試環境

YOLOv6 版本更新

近日,YOLOv6 已經更新了 V2.0 版本,并新增了中大型網絡,對輕量級和小網絡的性能進行了全面更新,進一步提升綜合性能,量化效果也得到大幅提升,其中 YOLOv6-S 量化模型達到了 43.3mAP 和 869 FPS (TensorRT 8.4)。更多詳細内容請關注官方出品的技術報告 [7]。

YOLOv6量化部署實戰指南

表12 YOLOv6-S V2.0 量化效果

我們希望通過分享本文的實踐,進一步推動最新通用目标檢測算法的落地。未來,我們會和業界同行一道,探索更優的量化方案,持續提升量化精度和推理速度,助力降本增效,深化業務價值。

參考文獻

[1] YOLOv6:又快又準的目标檢測架構開源啦

[2] RepVGG: Making VGG-style ConvNets Great Again,https://arxiv.org/abs/2101.03697

[3] ReOpt: Re-parameterizing Your Optimizers rather than Architectures

[4] SNR: https://github.com/openppl-public/ppq/blob/8a849c9b14bacf2a5d0f42a481dfa865d2b75e66/ppq/quantization/measure/norm.py

[5] Nsight-systems: https://docs.nvidia.com/nsight-systems/UserGuide/index.html

[6] Channel-wise Knowledge Distillation for Dense Prediction, https://arxiv.org/abs/2011.13256

[7] YOLOv6: A Single-Stage Object Detection Framework for Industrial Applications, https://arxiv.org/abs/2209.02976

繼續閱讀