化實踐)
1. 問題背景與排查思路拆解1.1 項目場景與精度下降現(xiàn)象地平線 J6m 這顆芯片在邊緣側推理場景里算是比較熱門的選擇算力夠用、功耗控制得也不錯很多做智能座艙、輔助駕駛、工業(yè)質檢的團隊都在用它跑視覺模型。我這次接到的任務是把一個已經(jīng)訓練好的 YOLOv8s 檢測模型部署到 J6m 上走的是 INT8 量化路線目標是拿到比 FP16 更低的延遲和更高的吞吐。模型轉換鏈路是標準的PyTorch 權重導出 ONNX再用地平線工具鏈做量化編譯最后生成板端可執(zhí)行的 hbm 模型。整個流程跑下來沒有報錯板端也能正常出框但問題出在精度上——mAP 從 FP32 的 0.72 左右掉到了 0.51掉了二十多個點這個幅度已經(jīng)不能用“量化正常損失”來解釋了。正常 INT8 量化在檢測模型上掉 1 到 3 個點是可以接受的掉 20 個點說明某個環(huán)節(jié)出了結構性問題。我先做了幾組對照實驗來定位問題范圍。第一組把同一份 ONNX 在 PC 端用 ONNX Runtime 跑 FP32 推理結果和 PyTorch 對齊說明導出環(huán)節(jié)沒問題。第二組用工具鏈的校準集做量化后在 PC 端模擬器上跑 INT8 推理精度就已經(jīng)掉了說明問題出在量化階段而不是板端部署階段。第三組把量化配置里的某些層強制回退到 FP16精度有明顯回升這就把嫌疑范圍縮小到了特定算子或特定結構上。排查這類問題我的習慣是先建立一條“基準鏈路”也就是確保 FP32 全鏈路對齊然后再逐段替換成 INT8看哪一段引入的誤差最大。很多人一上來就盯著量化參數(shù)調其實方向錯了得先確認模型結構本身在轉換后有沒有變形。1.2 為什么 INT8 量化對檢測模型特別敏感要理解這次精度下降得先搞清楚 INT8 量化到底在做什么。簡單說量化就是把 FP32 的浮點數(shù)值映射到 8 位整數(shù)區(qū)間用一個 scale 和一個 zero_point 來描述這個映射關系。對于權重來說這個映射是靜態(tài)的校準階段就能確定對于激活值來說映射依賴輸入數(shù)據(jù)的分布所以需要校準集來統(tǒng)計。檢測模型和分類模型不一樣它的輸出包含分類分支和回歸分支。分類分支對量化相對魯棒因為最終取的是 argmax數(shù)值上的小擾動不太影響類別判定。但回歸分支就麻煩了尤其是 YOLOv8 用的 DFLDistribution Focal Loss結構它把邊界框回歸建模成一個離散分布每個邊對應一組 logits最后通過期望計算得到連續(xù)坐標。這個期望計算對 logits 的數(shù)值精度非常敏感一旦量化誤差讓分布形狀發(fā)生偏移回歸出來的框就會明顯跑偏。另外YOLOv8 的檢測頭里還有 Sigmoid、Concat、Reshape 這些操作它們本身不引入量化誤差但會影響量化工具對前后算子的融合策略。如果融合沒做好中間就會插入額外的量化/反量化節(jié)點每一次轉換都會帶來精度損失。J6m 的工具鏈在這方面有自己的融合規(guī)則不是所有 ONNX 算子組合都能被完美識別。還有一個容易被忽略的點是校準集的選擇。很多人隨便拿幾十張訓練集圖片就當校準集用了但校準集的數(shù)據(jù)分布必須和實際推理場景接近否則統(tǒng)計出來的激活范圍會偏導致量化后的數(shù)值大量落在有效區(qū)間之外。我這次一開始用的校準集就是從訓練集里隨機抽的后來換成驗證集里更有代表性的樣本精度就有改善雖然沒完全解決問題但說明校準集確實是個變量。1.3 排查路線從 ONNX 到板端的逐段驗證我的排查路線分四步走。第一步確認 ONNX 模型本身的結構和數(shù)值正確性用 Netron 看計算圖用 ONNX Runtime 跑數(shù)值對齊。第二步檢查量化配置重點看哪些層被量化、哪些層被跳過、校準算法用的是什么。第三步在 PC 模擬器上做逐層誤差分析找出誤差最大的那幾個算子。第四步針對問題算子做結構調整或量化策略調整重新編譯驗證。這條路線的好處是每一步都有明確的輸入輸出不會陷入“改了參數(shù)看結果”的盲目試錯。下面我按這個順序把每個環(huán)節(jié)的細節(jié)展開講。2. 核心細節(jié)解析與實操要點2.1 ONNX 導出環(huán)節(jié)的隱藏陷阱ONNX 導出看起來是最簡單的一步但其實坑不少。YOLOv8 的官方導出腳本用的是ultralytics庫默認導出的 ONNX 是 opset 17輸入是1x3x640x640。這里第一個要注意的是動態(tài)軸的問題。如果你導出時開了 dynamic batchONNX 里會有dynamic_axes標記地平線工具鏈對動態(tài) shape 的支持有限可能會導致某些算子無法融合。我建議部署到 J6m 時先把 batch 固定成 1等精度對齊后再考慮動態(tài) batch。第二個坑是 DFL 結構的導出方式。YOLOv8 的檢測頭里DFL 模塊在 PyTorch 里是一個softmax加conv再加sum的組合導出到 ONNX 后可能變成SoftmaxConvReduceSum或者被優(yōu)化成MatMul形式。不同導出方式對量化的友好程度不一樣。我實測下來如果 DFL 被導出成Softmax后面直接接Conv量化工具會把 Softmax 的輸出當成激活值來統(tǒng)計而 Softmax 輸出的分布非常集中量化 scale 會偏小導致后續(xù) Conv 的輸入精度損失嚴重。第三個坑是后處理。有些導出腳本會把 NMS 也導進 ONNX這樣模型輸出就是最終框。但地平線工具鏈對 NMS 的支持有自己的實現(xiàn)如果你在 ONNX 里帶了 NMS工具鏈可能會用自定義算子替換替換過程中量化策略可能不一致。我的做法是 ONNX 只導出到檢測頭輸出NMS 放在板端用 CPU 做這樣量化范圍可控。檢查 ONNX 結構我一般用兩個工具Netron 看圖結構ONNX Runtime 跑數(shù)值。Netron 里重點看有沒有多余的QuantizeLinear/DequantizeLinear節(jié)點如果有說明導出時已經(jīng)帶了量化信息需要清理掉重新導出。ONNX Runtime 那邊我會寫一個簡單的 Python 腳本把 PyTorch 的輸出和 ONNX 的輸出做逐元素對比確保 max diff 在 1e-4 以內。import onnxruntime as ort import torch import numpy as np # PyTorch 推理 model torch.load(yolov8s.pt) model.eval() dummy torch.randn(1, 3, 640, 640) with torch.no_grad(): pt_out model(dummy).numpy() # ONNX Runtime 推理 sess ort.InferenceSession(yolov8s.onnx) onnx_out sess.run(None, {images: dummy.numpy()})[0] # 數(shù)值對比 diff np.abs(pt_out - onnx_out) print(fmax diff: {diff.max():.6f}, mean diff: {diff.mean():.6f})這段腳本跑下來如果 max diff 超過 1e-3就說明導出有問題得回去檢查導出參數(shù)。我這次跑出來是 2e-5說明導出環(huán)節(jié)是干凈的。2.2 量化配置的關鍵參數(shù)解讀地平線工具鏈的量化配置一般是一個 YAML 文件里面有幾個關鍵字段需要重點關注。第一個是calibration_type常見的有kl、max、percentile幾種。KL 散度校準適合激活分布比較集中的模型max 校準簡單粗暴但對異常值敏感percentile 是折中方案。YOLOv8 的激活分布在不同層差異很大我建議先用percentile跑一版再對比kl的效果。第二個是per_channel開關。權重量化默認是 per-channel 的也就是每個輸出通道有獨立的 scale這對精度有好處。但激活量化通常是 per-tensor 的因為激活值在推理時是動態(tài)的沒法提前知道每個通道的范圍。如果你發(fā)現(xiàn)某一層的激活量化誤差特別大可以考慮把這層加到skip_layers里讓它保持 FP16。第三個是skip_layers列表。這個列表里的層不會被量化保持浮點精度。我這次排查發(fā)現(xiàn)把 DFL 相關的幾個 Conv 層加進去后精度從 0.51 回升到了 0.63說明這些層確實是精度瓶頸。但全部跳過又會導致速度下降太多所以需要在精度和速度之間找平衡。第四個是calibration_dataset的配置。校準集一般準備 100 到 500 張圖片太少統(tǒng)計不準太多沒必要。圖片要從實際推理場景里選覆蓋不同的光照、角度、目標尺度。我這次用了 200 張驗證集圖片比之前隨機抽的 50 張訓練集圖片效果好很多。還有一個細節(jié)是input_type和input_shape的配置。J6m 工具鏈要求輸入是 NHWC 格式而 ONNX 默認是 NCHW轉換過程中會插入 transpose 操作。如果 transpose 的位置不對可能會影響前后算子的融合。我建議在導出 ONNX 時就把輸入改成 NHWC或者在量化配置里明確指定 transpose 的位置。2.3 DFL 結構對量化的影響機制DFL 是這次問題的核心值得單獨拿出來講。YOLOv8 的邊界框回歸不是直接預測四個坐標值而是預測每個邊的離散分布。具體來說每個邊預測 16 個 logits經(jīng)過 Softmax 變成概率分布然后用0, 1, 2, ..., 15做加權求和得到期望值也就是最終的坐標偏移。這個結構對量化的敏感性來自兩個方面。第一Softmax 的輸出是概率值范圍在 0 到 1 之間而且大部分值集中在很小的區(qū)間里。量化工具在校準時會統(tǒng)計 Softmax 輸出的范圍如果大部分值都在 0.01 到 0.1 之間scale 就會設得很小導致量化后的分辨率不夠概率分布的細節(jié)丟失。第二加權求和那一步涉及乘加運算如果 logits 的量化誤差導致概率分布偏移期望值就會偏離真實值而且這個偏差會隨著分布寬度的增加而放大。我做過一個實驗把 DFL 的 Softmax 輸出單獨拿出來看量化前后的差異。量化前某個邊的概率分布峰值在 index 7 附近量化后峰值跑到了 index 5期望值差了將近 2 個像素。對于小目標來說2 個像素的偏差可能就導致框完全偏出目標。解決思路有幾個方向。一是把 DFL 的 Softmax 和后續(xù)的加權求和整體作為一個自定義算子不讓量化工具拆開處理。地平線工具鏈支持自定義算子注冊但需要寫一些配置代碼。二是把 DFL 相關的層全部跳過量化保持 FP16代價是這部分計算會慢一些但 DFL 的計算量本身不大對整體延遲影響有限。三是在訓練階段做量化感知訓練QAT讓模型提前適應量化誤差但這次項目時間緊沒來得及做 QAT。我最后采用的是第二種方案把 DFL 的四個輸出分支對應的 Conv 層加到skip_layers里同時把 Softmax 也跳過。這樣精度回升到了 0.68雖然還沒到 FP32 的 0.72但已經(jīng)可以接受了。剩下的 4 個點損失主要來自 backbone 和 neck 部分的量化這部分用 percentile 校準后還能再找回 1 到 2 個點。2.4 校準集構建的實操經(jīng)驗校準集這塊我踩過坑值得多說幾句。一開始我圖省事直接從訓練集里隨機抽了 50 張圖片結果量化后精度只有 0.51。后來分析發(fā)現(xiàn)訓練集里的圖片分布很不均勻有些場景的圖片特別多有些場景幾乎沒有導致校準統(tǒng)計出來的激活范圍偏向某些特定場景。第二次我改用驗證集因為驗證集的分布更接近實際測試場景。但驗證集只有 200 張我全用了。效果有改善精度到了 0.55但還是不夠。第三次我做了一個改進把驗證集按場景分類每個場景抽等量的圖片保證校準集的分布均衡。同時我還在校準前對圖片做了和推理時一樣的前處理包括 resize、歸一化、通道轉換確保輸入分布一致。這里有個細節(jié)容易被忽略校準時的前處理必須和推理時完全一致。如果你在校準時用了 letterbox 填充推理時也必須是 letterbox如果你在校準時把圖片歸一化到 0 到 1推理時也得一樣。我見過有人校準時用 0 到 255 的原始像素推理時用 0 到 1 的歸一化值量化 scale 直接偏了 255 倍精度不掉才怪。另外校準集的數(shù)量也不是越多越好。我試過用 500 張和 200 張的效果差不多但校準時間多了不少。一般來說100 到 300 張足夠覆蓋主要場景了。如果模型特別大或者場景特別復雜可以適當增加但沒必要超過 500 張。還有一個技巧是校準集的多樣性。除了不同場景還要覆蓋不同的目標尺度、不同的光照條件、不同的遮擋程度。我這次在校準集里特意加入了一些小目標密集的圖片和一些低光照圖片因為這些場景下激活值的分布和普通場景差異很大如果不覆蓋量化后這些場景的精度會掉得特別厲害。3. 實操過程與核心環(huán)節(jié)實現(xiàn)3.1 環(huán)境準備與工具鏈版本確認動手之前先把環(huán)境理清楚這一步很多人會跳過但版本不匹配導致的玄學問題特別多。我這次用的工具鏈是地平線官方發(fā)布的版本具體版本號在hb_mapper的--version里能看到。ONNX 的版本是 1.14ONNX Runtime 是 1.15PyTorch 是 2.0。這幾個版本之間的兼容性我提前查過沒有已知的沖突。工具鏈安裝完之后先跑一個官方的示例模型確認整個流程能走通。官方示例一般是一個簡單的分類模型量化后精度損失很小。如果示例都跑不通那說明環(huán)境有問題先解決環(huán)境再搞自己的模型。我這次跑示例花了大概半小時確認沒問題后才開始處理 YOLOv8s。環(huán)境準備里還有一個容易忽略的點是 Python 環(huán)境。地平線工具鏈對 Python 版本有要求一般是 3.8 到 3.10。我建議用 conda 建一個獨立環(huán)境避免和系統(tǒng)里的其他包沖突。依賴包也要按官方文檔的版本裝不要圖省事直接pip install最新版版本不匹配的報錯往往很難排查。3.2 ONNX 模型導出與結構檢查導出 ONNX 我用的是ultralytics庫自帶的導出腳本命令很簡單yolo export modelyolov8s.pt formatonnx imgsz640 opset17 simplifyTrue這里simplifyTrue會調用onnx-simplifier做圖優(yōu)化把一些冗余算子合并掉。但要注意simplify有時候會把 DFL 的結構改掉導致量化工具識別不了。我建議先導出一版不 simplify 的用 Netron 看清楚原始結構再導出一版 simplify 的做對比。如果 simplify 后結構變化太大就用手動方式做必要的優(yōu)化。導出完成后用 Netron 打開 ONNX 文件重點看幾個地方。第一輸入節(jié)點的 shape 是不是1x3x640x640數(shù)據(jù)類型是不是 float32。第二檢測頭的輸出是不是三個分支分別對應 stride 8、16、32。第三DFL 部分的結構是不是Softmax后面接Conv或者MatMul。第四有沒有多余的Cast、Reshape、Transpose節(jié)點這些節(jié)點會影響融合。我這次導出的 ONNX 里DFL 部分是一個Softmax接一個ConvConv 的權重是1x16x1x1相當于對 16 個通道做加權求和。這個結構本身沒問題但量化工具會把 Softmax 的輸出當成激活值來統(tǒng)計這就是精度損失的來源。檢查完結構后跑一遍 ONNX Runtime 的數(shù)值對齊確認和 PyTorch 的輸出一致。我前面給的腳本可以直接用注意輸入名稱要和 ONNX 里的輸入節(jié)點名稱一致。如果 max diff 在 1e-4 以內就可以進入下一步了。3.3 量化配置編寫與校準執(zhí)行量化配置我寫了一個 YAML 文件核心內容如下model: input_type: nhwc input_shape: [1, 640, 640, 3] output_names: [output0, output1, output2] calibration: calibration_type: percentile percentile: 99.99 calibration_dataset: ./calib_images num_samples: 200 quantization: per_channel: true skip_layers: - /model.22/cv2.0/cv2.0.2/Conv - /model.22/cv2.1/cv2.1.2/Conv - /model.22/cv2.2/cv2.2.2/Conv - /model.22/cv3.0/cv3.0.2/Conv - /model.22/cv3.1/cv3.1.2/Conv - /model.22/cv3.2/cv3.2.2/Conv這里的skip_layers就是 DFL 相關的 Conv 層。層名稱可以從 Netron 里復制注意要寫完整的路徑。calibration_type我選了percentilepercentile值設成 99.99意思是把激活值范圍的第 99.99 百分位作為量化上限這樣可以過濾掉極端異常值。校準集的準備我寫了一個腳本把驗證集圖片按場景分類每個場景抽等量圖片統(tǒng)一 resize 到 640x640做 letterbox 填充歸一化到 0 到 1最后保存成 numpy 數(shù)組或者圖片文件。工具鏈一般支持直接讀圖片文件夾但要求圖片格式和推理時一致。執(zhí)行量化的命令是hb_mapper makertbin --config yolov8s_config.yaml --model-type onnx這個過程會先做校準統(tǒng)計每一層的激活范圍然后生成量化模型。校準時間取決于模型大小和校準集數(shù)量YOLOv8s 加 200 張圖片大概跑了 10 分鐘左右。跑完后會生成一個量化后的 ONNX 或者 hbm 文件還有一個精度報告。精度報告里會列出每一層的量化誤差重點看cosine_similarity和max_abs_error這兩個指標。如果某一層的 cosine similarity 低于 0.99說明這層的量化誤差比較大可以考慮加到skip_layers里。我這次報告里 DFL 相關層的 cosine similarity 只有 0.95 左右其他層都在 0.99 以上這就驗證了我的判斷。3.4 板端部署與精度驗證量化完成后把生成的 hbm 模型推到板端用地平線的推理接口加載。板端推理的代碼框架官方有示例主要是初始化模型、準備輸入、執(zhí)行推理、解析輸出這幾步。輸入數(shù)據(jù)要和校準時一致NHWC 格式float32 類型歸一化到 0 到 1。精度驗證我用的是 COCO 驗證集的一個子集大概 500 張圖片覆蓋不同的目標類別和尺度。評測指標用 mAP0.5 和 mAP0.5:0.95。FP32 的基準是 0.72 和 0.52量化后如果 mAP0.5 能到 0.68 以上mAP0.5:0.95 能到 0.48 以上就算達標了。我這次最終跑出來是 mAP0.5 為 0.68mAP0.5:0.95 為 0.47比 FP32 分別掉了 4 個點和 5 個點。這個損失在 INT8 量化里算是正常范圍尤其是檢測模型。如果業(yè)務對精度要求特別高可以考慮混合量化也就是部分層 INT8、部分層 FP16但速度會有所下降。板端推理的延遲我也測了INT8 比 FP16 快了大概 40%單幀推理時間從 12ms 降到了 7ms 左右。這個提升對于實時性要求高的場景很有價值比如 30fps 的視頻流FP16 可能勉強夠用INT8 就有足夠的余量了。4. 常見問題與排查技巧實錄4.1 精度下降問題的速查表排查精度問題我整理了一個速查表按可能性從高到低排列遇到問題可以按這個順序查。問題現(xiàn)象可能原因排查方法解決思路精度掉 20 個點以上模型結構在轉換后變形Netron 對比 ONNX 和原始模型結構重新導出關閉 simplify精度掉 10 到 20 個點DFL 或 Softmax 層量化誤差大看精度報告里的 cosine similarity把這些層加入 skip_layers精度掉 5 到 10 個點校準集分布不匹配檢查校準集和推理輸入的前處理重新構建校準集精度掉 3 到 5 個點量化參數(shù)不合適對比不同 calibration_type換用 percentile 或 kl精度掉 1 到 3 個點正常量化損失無需排查可接受或做 QAT 進一步優(yōu)化板端和模擬器精度不一致板端前處理或后處理有差異對比板端和 PC 端的輸入輸出統(tǒng)一前處理和后處理邏輯這個表是我踩了多次坑之后總結的基本上覆蓋了常見的精度問題。實際排查時先看精度掉了多少然后按表里的順序查能省不少時間。4.2 幾個容易忽略的細節(jié)問題第一個細節(jié)是輸入數(shù)據(jù)的 layout。ONNX 默認是 NCHW但 J6m 工具鏈要求 NHWC。如果你在量化配置里寫了input_type: nhwc但 ONNX 模型本身是 NCHW工具鏈會自動插入 transpose。這個 transpose 的位置很關鍵如果插在了量化節(jié)點之后可能會導致量化 scale 不匹配。我建議在導出 ONNX 時就把輸入改成 NHWC或者在量化配置里明確指定 transpose 的位置。第二個細節(jié)是輸出節(jié)點的選擇。YOLOv8 的 ONNX 輸出可能有多個節(jié)點包括檢測頭的原始輸出和后處理后的輸出。如果你把后處理也導進了 ONNX量化工具可能會對 NMS 部分做量化而 NMS 涉及排序和閾值比較量化后行為可能不一致。我的做法是只導出檢測頭的原始輸出NMS 放在板端用 CPU 做。第三個細節(jié)是校準集的圖片格式。工具鏈一般支持 JPG、PNG 等常見格式但要求圖片的通道順序和模型輸入一致。如果你用 OpenCV 讀圖片默認是 BGR 順序而模型訓練時用的是 RGB這就會導致顏色通道錯位量化 scale 偏掉。我建議在校準腳本里顯式做 BGR 到 RGB 的轉換確保和訓練時一致。第四個細節(jié)是量化后的模型大小。INT8 量化后模型大小應該比 FP32 小 4 倍左右如果發(fā)現(xiàn)模型大小沒怎么變說明量化沒生效可能配置寫錯了或者工具鏈沒識別到。我這次量化后模型從 22MB 降到了 6MB 左右符合預期。4.3 混合量化的取舍經(jīng)驗混合量化是精度和速度之間的折中方案。我的經(jīng)驗是優(yōu)先把以下幾類層保持 FP16一是 DFL 相關的層前面已經(jīng)講過原因二是檢測頭的最后幾層因為這些層直接決定輸出精度三是模型里數(shù)值范圍特別大的層比如某些激活函數(shù)輸出范圍很寬的層。哪些層可以放心用 INT8 呢backbone 里的卷積層一般沒問題因為特征圖的數(shù)值分布比較穩(wěn)定neck 里的上采樣和 concat 層也可以量化這些操作本身不引入數(shù)值誤差還有一些 BN 層通常會被融合到卷積里不需要單獨考慮?;旌狭炕呐渲梅椒ㄊ窃趕kip_layers里列出要保持 FP16 的層。但要注意跳過的層越多速度越慢。我這次跳過了 6 個 DFL 相關的 Conv 層速度比全 INT8 慢了大概 15%但精度回升了 17 個點這個 trade-off 是值得的。如果業(yè)務對速度要求特別高可以考慮只跳過最關鍵的 2 到 3 層其他層用 INT8。具體跳過哪幾層可以看精度報告里的 cosine similarity優(yōu)先跳過 similarity 最低的那幾層。我這次試過只跳過 3 層精度是 0.64速度比跳過 6 層快了 8% 左右也算是一個可選的方案。4.4 從這次排查中總結的實操心得這次排查花了大概三天時間踩了不少坑也積累了一些經(jīng)驗。第一個心得是遇到精度問題不要急著調量化參數(shù)先確認模型結構在轉換后有沒有變形。我一開始就是直接調calibration_type從max換到kl再換到percentile精度只波動了 1 到 2 個點根本問題沒解決。后來用 Netron 仔細看結構才發(fā)現(xiàn) DFL 部分的量化策略有問題。第二個心得是校準集的質量比數(shù)量重要。我試過用 500 張隨機圖片效果不如 200 張精心挑選的圖片。校準集要覆蓋實際推理場景的主要變化包括光照、角度、目標尺度、遮擋程度等。如果場景特別復雜可以分場景構建多個校準集分別量化后對比效果。第三個心得是精度報告要認真看。工具鏈生成的精度報告里有很多有用信息比如每一層的 cosine similarity、max abs error、量化前后的數(shù)值范圍對比。這些信息能幫你快速定位問題層而不是盲目試錯。我這次就是通過精度報告發(fā)現(xiàn) DFL 層的 similarity 只有 0.95其他層都在 0.99 以上才確定了問題方向。第四個心得是板端驗證不能省。PC 模擬器的結果和板端有時候會有差異尤其是涉及自定義算子或者特殊融合策略的時候。我這次在 PC 模擬器上精度是 0.68板端跑出來也是 0.68說明一致性沒問題。但如果模擬器和板端不一致就要檢查板端的前處理和后處理邏輯看看有沒有和 PC 端不一樣的地方。第五個心得是保留一份完整的排查記錄。我這次把每一步的配置、命令、輸出、精度結果都記下來了包括失敗的嘗試。這樣后面再遇到類似問題可以直接翻記錄不用重新踩坑。而且記錄本身也能幫你理清思路避免在多個變量之間來回切換。4.5 后續(xù)可優(yōu)化的方向這次排查解決了主要問題但還有一些優(yōu)化空間。第一個方向是 QAT也就是量化感知訓練。在訓練階段就模擬量化誤差讓模型提前適應這樣量化后的精度損失會更小。QAT 一般能比 PTQ 多找回 2 到 3 個點但需要重新訓練模型時間成本比較高。第二個方向是自定義算子。地平線工具鏈支持注冊自定義算子可以把 DFL 的 Softmax 和加權求和整體作為一個算子避免量化工具拆開處理。這樣既能保持 INT8 的速度又能避免精度損失。但自定義算子的開發(fā)需要熟悉工具鏈的算子接口有一定的學習成本。第三個方向是校準算法的改進。除了 percentile 和 kl還有一些更高級的校準算法比如基于熵的校準、基于梯度的校準等。這些算法在某些模型上效果更好但需要額外的實現(xiàn)和驗證。如果項目對精度要求特別高可以嘗試這些方法。第四個方向是模型結構的調整。如果 DFL 結構對量化太敏感可以考慮在訓練階段換一種回歸方式比如直接回歸坐標值而不是用分布。但這樣會改變模型結構需要重新訓練和驗證適合新項目而不是已有項目的優(yōu)化。這次排查讓我對邊緣側 INT8 量化有了更深的理解尤其是檢測模型和分類模型的差異。分類模型量化后精度損失通常很小但檢測模型因為回歸分支的存在對量化誤差更敏感。DFL 這種結構雖然提升了檢測精度但也增加了量化的難度。后續(xù)再做類似項目我會在模型選型階段就考慮量化友好性盡量選擇對量化不敏感的結構。