博客專欄

EEPW首頁(yè) > 博客 > 天工開物|征程 6 啟航新章:量化流程PTQ篇

天工開物|征程 6 啟航新章:量化流程PTQ篇

發(fā)布人:地平線開發(fā)者 時(shí)間:2024-09-19 來(lái)源:工程師 發(fā)布文章

01  概論:PTQ 基礎(chǔ)

目前在 GPU 上訓(xùn)練的模型大部分都是浮點(diǎn)模型,即參數(shù)使用的是 float 類型存儲(chǔ)。而地平線 BPU 架構(gòu)的計(jì)算平臺(tái)使用的是 int8 的計(jì)算精度(業(yè)內(nèi)計(jì)算平臺(tái)的通用精度),能運(yùn)行定點(diǎn)量化模型。

地平線 征程 6 算法工具鏈(以下簡(jiǎn)稱工具鏈)作為專業(yè)量化工具,是一套完整的邊緣計(jì)算平臺(tái)算法落地解決方案,可以幫助您把浮點(diǎn)模型量化為定點(diǎn)模型,并在地平線計(jì)算平臺(tái)上快速部署自研算法模型。當(dāng)需要對(duì)量化后的參數(shù)進(jìn)行調(diào)整時(shí),又可以將量化方法分為訓(xùn)練后量化(PTQ)和量化感知訓(xùn)練(QAT)。

其中訓(xùn)練后量化 PTQ 是使用一批校準(zhǔn)數(shù)據(jù)對(duì)訓(xùn)練好的模型進(jìn)行校準(zhǔn),將訓(xùn)練過(guò)的FP32模型直接轉(zhuǎn)換為定點(diǎn)計(jì)算的模型,過(guò)程中無(wú)需對(duì)原始模型進(jìn)行任何訓(xùn)練。只對(duì)幾個(gè)超參數(shù)調(diào)整就可完成量化過(guò)程,過(guò)程簡(jiǎn)單快速,無(wú)需訓(xùn)練,此方法已被廣泛應(yīng)用于大量的端側(cè)和云側(cè)部署場(chǎng)景,我們優(yōu)先推薦您嘗試 PTQ 方法來(lái)查看是否滿足您的部署精度和性能要求 。如下即為 PTQ 流程所需數(shù)據(jù)和基本步驟:

圖片

本文章聚焦訓(xùn)練后量化(PTQ),展示 PTQ 基本流程以及和上一代計(jì)算平臺(tái)工具鏈之間的使用差異。



02 PTQ量化&編譯

征程 6 PTQ 的使用方式、yaml 配置參數(shù)等均和 征程 5 保持一致,詳細(xì)說(shuō)明可見(jiàn)用戶手冊(cè)《6.2 PTQ 轉(zhuǎn)換工具》,下文將對(duì)其中部分功能點(diǎn)的使用方式做具體說(shuō)明。

圖片


2.1 校準(zhǔn)數(shù)據(jù)

當(dāng)前版本已支持在 yaml 文件中配置 色彩轉(zhuǎn)換(如 nv12—>bgr)和 歸一化(mean & scale),同時(shí)在數(shù)據(jù)保存上,也支持復(fù)用征程 5 上使用的 bin 格式(np.tofile)。   與征程 5 不同的是,征程 6 的 PTQ 需要手動(dòng)對(duì)校準(zhǔn)數(shù)據(jù)做歸一化。   另外,征程 6 也支持使用 np.save 將數(shù)據(jù)保存為 npy 格式。


2.2  前處理節(jié)點(diǎn)

征程 6 PTQ 前處理節(jié)點(diǎn)的配置方式和征程 5 保持一致,可以完全復(fù)用。需要注意的是:

  • 征程 5 的前處理節(jié)點(diǎn)在 *_original_float.onnx 階段就已經(jīng)插入;

  • 征程 6 只在 *_quantized.bc*.hbm 模型上插入,各階段 onnx 模型推理時(shí)的輸入數(shù)據(jù)則完全一致。另外,征程 6 也提供 HBRuntime 推理庫(kù),使用同一套接口推理各階段 onnx 模型 以及 HBIR(*.bc) 模型,詳細(xì)說(shuō)明可參考用戶手冊(cè)的HBRuntime推理庫(kù)章節(jié)。


2.2.1 input_type_rt

當(dāng)前版本已支持配置 input_type_rt: nv12:

input_parameters:
 input_type_rt: 'nv12'    # 配置為nv12或gray時(shí),input_source默認(rèn)自動(dòng)選擇為pyramid


以單輸入 nv12模型為例,在 X86 環(huán)境使用 hb_model_info 工具查看 *_quantized.bc 的模型信息,其輸入節(jié)點(diǎn)已經(jīng)被拆分成 yuv 兩個(gè)分量;進(jìn)一步在 qemu 環(huán)境使用 hrt_model_exec model_info 工具查看 *.hbm 的模型信息,其 input_sourcepyramid 類型。


圖片

圖片



*_quantized.bc*.hbm

hb_model_info *_quantized.bc -v 可以生成其可視化 onnx,如下圖所示,已插入前處理節(jié)點(diǎn)

圖片



2.2.2 數(shù)據(jù)歸一化

目前 PTQ 已支持配置歸一化參數(shù),其使用方式和 征程 5 保持一致,值得注意的是:校準(zhǔn)數(shù)據(jù)準(zhǔn)備時(shí)手動(dòng)在代碼中加入了歸一化操作,如果此處配置了歸一化參數(shù),為推理準(zhǔn)備數(shù)據(jù)如果參考校準(zhǔn)數(shù)據(jù)準(zhǔn)備流程是要移除校準(zhǔn)數(shù)據(jù)準(zhǔn)備中的重復(fù)操作:

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)境打印模型信息,確認(rèn)已成功編譯為 resizer 模型:  

圖片


2.4 Batch輸入拆分

當(dāng)前 Alpha 版本在部署端,暫不支持 Batch>1Pyramid/Resizer模型 以連續(xù)地址輸入數(shù)據(jù)進(jìn)行推理,因此需要將 batch 輸入顯式地拆分成 batch 份并提供獨(dú)立地址。當(dāng)前 PTQ 鏈路拆分模型 batch 輸入的方式包含如下幾種:

拆分方式一:

  • 適用場(chǎng)景:適用于任何模型

  • 正常轉(zhuǎn)換模型,并基于生成的 ptq_model.onnx,調(diào)用 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è)輸入節(jié)點(diǎn)按batch維度(0)做拆分,方式同QAT
func = ptq_bc.functions[0]
# 依據(jù)部署需要,維護(hù)一個(gè)獨(dú)立地址部署的輸入節(jié)點(diǎn)名稱列表,或index列表
# 輸入節(jié)點(diǎn)名采用上一節(jié)的方式進(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ì)導(dǎo)致節(jié)點(diǎn)數(shù)變多,因此建議從后往前拆
#     2.就算batch=1,該接口也會(huì)嘗試拆分,會(huì)導(dǎo)致輸入節(jié)點(diǎn)的name增加 “_0” 后綴

quantized_bc = convert(ptq_bc, "nash-e")

compile(
 quantized_bc,
 march="nash-e",
 path="./*.hbm"
)

拆分方式二:

  • 適用場(chǎng)景:當(dāng)前版本僅適用于 單輸入 模型,暫不支持多輸入模型   直接使用 separate_batch 拆分 batch(要求原始模型為單輸入且 batch=1,并配合使用input_batch配置 batch 數(shù)):

input_parameters:
 input_batch: 16
 separate_batch: True

拆分方式三:

  • 適用場(chǎng)景:在 DL 框架內(nèi)拆分 batch 輸入后重新導(dǎo)出 ONNX 模型



2.5 刪除指定節(jié)點(diǎn)

當(dāng)前版本已支持刪除指定名稱/類型的節(jié)點(diǎn),其支持刪除的算子類型和 yaml 配置方式和征程 5 保持一致。   需要注意:與 征程 5 不同,征程 6 沒(méi)有提供 **hb_model_modifier** 工具用于修改模型節(jié)點(diǎn)。

model_parameters:
 remove_node_type: Quantize;Transpose;Dequantize;Cast;Reshape;Softmax
 #remove_node_name:


03  性能評(píng)估

性能測(cè)試可以分為靜態(tài)測(cè)試和動(dòng)態(tài)測(cè)試兩種模式或階段。


3.1 靜態(tài)評(píng)估

靜態(tài)評(píng)估是編譯器根據(jù)模型的結(jié)構(gòu)和計(jì)算平臺(tái)架構(gòu)通過(guò)靜態(tài)的分析預(yù)估出的模型 BPU 部分的性能情況。需要注意因?yàn)樵u(píng)估需要計(jì)算平臺(tái)深層的架構(gòu)信息做支撐,目前靜態(tài)評(píng)估的結(jié)果僅 BPU 部分,不含 CPU/DSP 等性能情況。如果想獲取全面的性能數(shù)據(jù)還需要通過(guò)動(dòng)態(tài)評(píng)估。   靜態(tài)評(píng)估是通過(guò)地平線提供的 hb_compile 工具進(jìn)行的,該工具集成了模型編譯與性能分析的功能。在模型轉(zhuǎn)換編譯完成后,會(huì)在yaml文件配置的 working_dir 路徑下生成編譯器預(yù)估的模型BPU部分的模型靜態(tài)評(píng)估文件:model.html(可讀性更好)model.json。用戶可通過(guò)他們了解模型的靜態(tài)評(píng)估結(jié)果。   另外,如果用戶需要,也可以通過(guò) python 組件的hbdk4.compiler主動(dòng)進(jìn)行性能評(píng)估,參考代碼如下:

from hbdk4.compiler import hbm_perf
hbm_perf("model.hbm")


3.2 動(dòng)態(tài)測(cè)試

動(dòng)態(tài)評(píng)估是通過(guò)測(cè)試工具hrt_model_exec實(shí)際在板端運(yùn)行被測(cè)試模型最終獲取性能結(jié)果的過(guò)程。因?yàn)闇y(cè)試過(guò)程就是模型推理過(guò)程的真實(shí)在線,因此是對(duì)模型推理過(guò)程所需的系統(tǒng)依賴的一個(gè)全面評(píng)估,該過(guò)程有效彌補(bǔ)了靜態(tài)評(píng)估僅針對(duì) BPU 部分測(cè)評(píng)的不足。   hrt_model_exec工具的具體使用方法可以參考用戶使用手冊(cè) 和 部署部分的文章,這里不單獨(dú)贅述。


04  精度評(píng)測(cè)

精度評(píng)測(cè)是通過(guò)一批測(cè)試數(shù)據(jù)集(包含真值)、推理腳本以及結(jié)果后處理程序獲取優(yōu)化前后模型的精度信息,進(jìn)而了解模型從浮點(diǎn)模型量化為定點(diǎn)模型過(guò)程中帶來(lái)的精度損失情況。需要用戶了解的是后量化方式是基于幾十或上百?gòu)埿?zhǔn)數(shù)據(jù)實(shí)現(xiàn)的模型從浮點(diǎn)到定點(diǎn)轉(zhuǎn)換過(guò)程,無(wú)論是數(shù)據(jù)的規(guī)模還是模型參數(shù)的表達(dá)寬度都與原始模型訓(xùn)練過(guò)程有很大的差距,精度損失在一定程度上是不可避免地。地平線轉(zhuǎn)換工具經(jīng)過(guò)大量實(shí)際生產(chǎn)經(jīng)驗(yàn)驗(yàn)證和優(yōu)化,在大部分情況下可以將精度損失保持在1%以內(nèi),這在業(yè)界已經(jīng)是很牛的存在。   通過(guò)模型編譯過(guò)程我們了解*_quantized_model.bc是過(guò)程的產(chǎn)物之一,雖然最后的hbm模型才是將部署到計(jì)算平臺(tái)的模型,考慮到方便在Ubuntu開發(fā)機(jī)上完成精度評(píng)測(cè),我們一般通過(guò)bc模型文件來(lái)進(jìn)行精度評(píng)測(cè)過(guò)程。模型推理參考代碼如下:   下方示例代碼不僅適用于quantized模型,對(duì)originaloptimizedonnx模型同樣適用(替換模型文件即可),根據(jù)模型的輸入類型和layout要求準(zhǔn)備數(shù)據(jù)即可。

import numpy as np
# 加載地平線依賴庫(kù)
from horizon_tc_ui.hb_runtime import HBRuntime

# 準(zhǔn)備模型運(yùn)行的輸入,此處`input.npy`為處理好的數(shù)據(jù)
data = np.load("input.npy")    
# 加載模型文件,根據(jù)實(shí)際模型進(jìn)行設(shè)置
# ONNX模型
sess = HBRuntime("model.onnx")
# HBIR模型
sess = HBRuntime("model.bc")
# 獲取輸入&輸出節(jié)點(diǎn)名稱
input_names = sess.input_names
output_names = sess.output_names

# 準(zhǔn)備輸入數(shù)據(jù),根據(jù)實(shí)際輸入類型和layout進(jìn)行準(zhǔn)備,配置格式要求為字典形式,輸入名稱和輸入數(shù)據(jù)組成鍵值對(duì)
# 如模型僅有一個(gè)輸入
input_feed = {input_names[0]: data}
# 如模型有多個(gè)輸入
input_feed = {input_names[0]: data1, input_names[1]: data2}
# 進(jìn)行模型推理,推理的返回值是一個(gè)list,依次與output_names指定名稱一一對(duì)應(yīng)
output = sess.run(output_names, input_feed)

當(dāng)然,這里主要描述了模型精度分析基本流程和推理代碼,如果評(píng)估發(fā)現(xiàn)結(jié)果不符合預(yù)期,可以參考用戶手冊(cè)中的 PTQ 模型精度調(diào)優(yōu) 章節(jié)的內(nèi)容嘗試調(diào)優(yōu),其中 PTQ 精度debug 工具 征程6 與征程 5 使用方式一致,精度分析推薦流程也一致,具體請(qǐng)參考社區(qū)文章 精度驗(yàn)證及調(diào)優(yōu)建議流程。主要區(qū)別就是征程 6 平臺(tái)的性能評(píng)估過(guò)程是通過(guò)(*_quantized_model.bchbir 格式的定點(diǎn)模型進(jìn)行的。最后,實(shí)在無(wú)法解決可尋求地平線的技術(shù)支持。  


聲明: 該文章內(nèi)容為學(xué)習(xí)過(guò)程對(duì)學(xué)習(xí)資料的整理和歸納


*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。



關(guān)鍵詞: 算法 自動(dòng)駕駛

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉