天工開(kāi)物|征程 6 啟航新章:量化流程PTQ篇
目前在 GPU 上訓練的模型大部分都是浮點(diǎn)模型,即參數使用的是 float 類(lèi)型存儲。而地平線(xiàn) BPU 架構的計算平臺使用的是 int8 的計算精度(業(yè)內計算平臺的通用精度),能運行定點(diǎn)量化模型。
地平線(xiàn) 征程 6 算法工具鏈(以下簡(jiǎn)稱(chēng)工具鏈)作為專(zhuān)業(yè)量化工具,是一套完整的邊緣計算平臺算法落地解決方案,可以幫助您把浮點(diǎn)模型量化為定點(diǎn)模型,并在地平線(xiàn)計算平臺上快速部署自研算法模型。當需要對量化后的參數進(jìn)行調整時(shí),又可以將量化方法分為訓練后量化(PTQ)和量化感知訓練(QAT)。
其中訓練后量化 PTQ 是使用一批校準數據對訓練好的模型進(jìn)行校準,將訓練過(guò)的FP32模型直接轉換為定點(diǎn)計算的模型,過(guò)程中無(wú)需對原始模型進(jìn)行任何訓練。只對幾個(gè)超參數調整就可完成量化過(guò)程,過(guò)程簡(jiǎn)單快速,無(wú)需訓練,此方法已被廣泛應用于大量的端側和云側部署場(chǎng)景,我們優(yōu)先推薦您嘗試 PTQ 方法來(lái)查看是否滿(mǎn)足您的部署精度和性能要求 。如下即為 PTQ 流程所需數據和基本步驟:
本文章聚焦訓練后量化(PTQ),展示 PTQ 基本流程以及和上一代計算平臺工具鏈之間的使用差異。
02 PTQ量化&編譯
征程 6 PTQ 的使用方式、yaml 配置參數等均和 征程 5 保持一致,詳細說(shuō)明可見(jiàn)用戶(hù)手冊《6.2 PTQ 轉換工具》,下文將對其中部分功能點(diǎn)的使用方式做具體說(shuō)明。
2.1 校準數據
當前版本已支持在 yaml 文件中配置 色彩轉換(如 nv12—>bgr)和 歸一化(mean & scale),同時(shí)在數據保存上,也支持復用征程 5 上使用的 bin 格式(np.tofile)。 與征程 5 不同的是,征程 6 的 PTQ 需要手動(dòng)對校準數據做歸一化。 另外,征程 6 也支持使用 np.save 將數據保存為 npy 格式。
2.2 前處理節點(diǎn)
征程 6 PTQ 前處理節點(diǎn)的配置方式和征程 5 保持一致,可以完全復用。需要注意的是:
征程 5 的前處理節點(diǎn)在 *_original_float.onnx 階段就已經(jīng)插入;
征程 6 只在 *_quantized.bc 和 *.hbm 模型上插入,各階段 onnx 模型推理時(shí)的輸入數據則完全一致。另外,征程 6 也提供 HBRuntime 推理庫,使用同一套接口推理各階段 onnx 模型 以及 HBIR(*.bc) 模型,詳細說(shuō)明可參考用戶(hù)手冊的HBRuntime推理庫章節。
2.2.1 input_type_rt
當前版本已支持配置 input_type_rt: nv12:
input_parameters:
input_type_rt: 'nv12' # 配置為nv12或gray時(shí),input_source默認自動(dòng)選擇為pyramid
以單輸入 nv12模型為例,在 X86 環(huán)境使用 hb_model_info 工具查看 *_quantized.bc 的模型信息,其輸入節點(diǎn)已經(jīng)被拆分成 y 和 uv 兩個(gè)分量;進(jìn)一步在 qemu 環(huán)境使用 hrt_model_exec model_info 工具查看 *.hbm 的模型信息,其 input_source 為 pyramid 類(lèi)型。
*_quantized.bc | *.hbm |
hb_model_info *_quantized.bc -v 可以生成其可視化 onnx,如下圖所示,已插入前處理節點(diǎn)
2.2.2 數據歸一化
目前 PTQ 已支持配置歸一化參數,其使用方式和 征程 5 保持一致,值得注意的是:校準數據準備時(shí)手動(dòng)在代碼中加入了歸一化操作,如果此處配置了歸一化參數,為推理準備數據如果參考校準數據準備流程是要移除校準數據準備中的重復操作:
input_parameters:
norm_type: 'data_mean_and_scale'
mean_value: 127 127 127
scale_value: 0.0078125 0.0078125 0.0078125
2.3 Resizer輸入
目前 PTQ 已支持配置 input_source 來(lái)指定是否為 resizer 輸入,參考如下:
input_parameters:
input_type_rt: 'nv12'
compiler_parameters:
input_source: {'input0':'resizer'} #resizer僅支持input_type_rt配置為nv12或gray
環(huán)境打印模型信息,確認已成功編譯為 resizer 模型:
2.4 Batch輸入拆分
當前 Alpha 版本在部署端,暫不支持 Batch>1 的 Pyramid/Resizer模型 以連續地址輸入數據進(jìn)行推理,因此需要將 batch 輸入顯式地拆分成 batch 份并提供獨立地址。當前 PTQ 鏈路拆分模型 batch 輸入的方式包含如下幾種:
拆分方式一:
適用場(chǎng)景:適用于任何模型
正常轉換模型,并基于生成的 ptq_model.onnx,調用 hbdk python api 進(jìn)行 batch 拆分后重新編譯模型,參考代碼如下:
import onnx
from hbdk4.compiler.onnx import export
from hbdk4.compiler import convert, compile
ptq_onnx = onnx.load("./*_ptq_model.onnx")
ptq_bc = export(ptq_onnx)
# 將該模型第一個(gè)輸入節點(diǎn)按batch維度(0)做拆分,方式同QAT
func = ptq_bc.functions[0]
# 依據部署需要,維護一個(gè)獨立地址部署的輸入節點(diǎn)名稱(chēng)列表,或index列表
# 輸入節點(diǎn)名采用上一節的方式進(jìn)行了自定義修改
batch_input = ["input_name1"]
for input in func.inputs[::-1]:
for name in batch_input[::-1]:
if name in input.name:
input.insert_split(dim=0)
# ps:
# 1.insert_split會(huì )導致節點(diǎn)數變多,因此建議從后往前拆
# 2.就算batch=1,該接口也會(huì )嘗試拆分,會(huì )導致輸入節點(diǎn)的name增加 “_0” 后綴
quantized_bc = convert(ptq_bc, "nash-e")
compile(
quantized_bc,
march="nash-e",
path="./*.hbm"
)
拆分方式二:
適用場(chǎng)景:當前版本僅適用于 單輸入 模型,暫不支持多輸入模型 直接使用 separate_batch 拆分 batch(要求原始模型為單輸入且 batch=1,并配合使用input_batch配置 batch 數):
input_parameters:
input_batch: 16
separate_batch: True
拆分方式三:
適用場(chǎng)景:在 DL 框架內拆分 batch 輸入后重新導出 ONNX 模型
2.5 刪除指定節點(diǎn)
當前版本已支持刪除指定名稱(chēng)/類(lèi)型的節點(diǎn),其支持刪除的算子類(lèi)型和 yaml 配置方式和征程 5 保持一致。 需要注意:與 征程 5 不同,征程 6 沒(méi)有提供 **hb_model_modifier** 工具用于修改模型節點(diǎn)。
model_parameters:
remove_node_type: Quantize;Transpose;Dequantize;Cast;Reshape;Softmax
#remove_node_name:
03 性能評估
性能測試可以分為靜態(tài)測試和動(dòng)態(tài)測試兩種模式或階段。
3.1 靜態(tài)評估
靜態(tài)評估是編譯器根據模型的結構和計算平臺架構通過(guò)靜態(tài)的分析預估出的模型 BPU 部分的性能情況。需要注意因為評估需要計算平臺深層的架構信息做支撐,目前靜態(tài)評估的結果僅 BPU 部分,不含 CPU/DSP 等性能情況。如果想獲取全面的性能數據還需要通過(guò)動(dòng)態(tài)評估。 靜態(tài)評估是通過(guò)地平線(xiàn)提供的 hb_compile 工具進(jìn)行的,該工具集成了模型編譯與性能分析的功能。在模型轉換編譯完成后,會(huì )在yaml文件配置的 working_dir 路徑下生成編譯器預估的模型BPU部分的模型靜態(tài)評估文件:model.html(可讀性更好)和model.json。用戶(hù)可通過(guò)他們了解模型的靜態(tài)評估結果。 另外,如果用戶(hù)需要,也可以通過(guò) python 組件的hbdk4.compiler主動(dòng)進(jìn)行性能評估,參考代碼如下:
from hbdk4.compiler import hbm_perf
hbm_perf("model.hbm")
3.2 動(dòng)態(tài)測試
動(dòng)態(tài)評估是通過(guò)測試工具hrt_model_exec實(shí)際在板端運行被測試模型最終獲取性能結果的過(guò)程。因為測試過(guò)程就是模型推理過(guò)程的真實(shí)在線(xiàn),因此是對模型推理過(guò)程所需的系統依賴(lài)的一個(gè)全面評估,該過(guò)程有效彌補了靜態(tài)評估僅針對 BPU 部分測評的不足。 hrt_model_exec工具的具體使用方法可以參考用戶(hù)使用手冊 和 部署部分的文章,這里不單獨贅述。
04 精度評測
精度評測是通過(guò)一批測試數據集(包含真值)、推理腳本以及結果后處理程序獲取優(yōu)化前后模型的精度信息,進(jìn)而了解模型從浮點(diǎn)模型量化為定點(diǎn)模型過(guò)程中帶來(lái)的精度損失情況。需要用戶(hù)了解的是后量化方式是基于幾十或上百張校準數據實(shí)現的模型從浮點(diǎn)到定點(diǎn)轉換過(guò)程,無(wú)論是數據的規模還是模型參數的表達寬度都與原始模型訓練過(guò)程有很大的差距,精度損失在一定程度上是不可避免地。地平線(xiàn)轉換工具經(jīng)過(guò)大量實(shí)際生產(chǎn)經(jīng)驗驗證和優(yōu)化,在大部分情況下可以將精度損失保持在1%以?xún)?,這在業(yè)界已經(jīng)是很牛的存在。 通過(guò)模型編譯過(guò)程我們了解*_quantized_model.bc是過(guò)程的產(chǎn)物之一,雖然最后的hbm模型才是將部署到計算平臺的模型,考慮到方便在Ubuntu開(kāi)發(fā)機上完成精度評測,我們一般通過(guò)bc模型文件來(lái)進(jìn)行精度評測過(guò)程。模型推理參考代碼如下: 下方示例代碼不僅適用于quantized模型,對original和optimized等onnx模型同樣適用(替換模型文件即可),根據模型的輸入類(lèi)型和layout要求準備數據即可。
import numpy as np
# 加載地平線(xiàn)依賴(lài)庫
from horizon_tc_ui.hb_runtime import HBRuntime
# 準備模型運行的輸入,此處`input.npy`為處理好的數據
data = np.load("input.npy")
# 加載模型文件,根據實(shí)際模型進(jìn)行設置
# ONNX模型
sess = HBRuntime("model.onnx")
# HBIR模型
sess = HBRuntime("model.bc")
# 獲取輸入&輸出節點(diǎn)名稱(chēng)
input_names = sess.input_names
output_names = sess.output_names
# 準備輸入數據,根據實(shí)際輸入類(lèi)型和layout進(jìn)行準備,配置格式要求為字典形式,輸入名稱(chēng)和輸入數據組成鍵值對
# 如模型僅有一個(gè)輸入
input_feed = {input_names[0]: data}
# 如模型有多個(gè)輸入
input_feed = {input_names[0]: data1, input_names[1]: data2}
# 進(jìn)行模型推理,推理的返回值是一個(gè)list,依次與output_names指定名稱(chēng)一一對應
output = sess.run(output_names, input_feed)
當然,這里主要描述了模型精度分析基本流程和推理代碼,如果評估發(fā)現結果不符合預期,可以參考用戶(hù)手冊中的 PTQ 模型精度調優(yōu) 章節的內容嘗試調優(yōu),其中 PTQ 精度debug 工具 征程6 與征程 5 使用方式一致,精度分析推薦流程也一致,具體請參考社區文章 精度驗證及調優(yōu)建議流程。主要區別就是征程 6 平臺的性能評估過(guò)程是通過(guò)(*_quantized_model.bc)hbir 格式
*博客內容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀(guān)點(diǎn),如有侵權請聯(lián)系工作人員刪除。