地平線 bev 參考演算法板端一致性驗證教程

地平线智能驾驶开发者發表於2024-12-08

01 前言

由於部署時資料來源的硬體不同以及應用開發的高效性要求,往往會使得在板端部署階段的資料準備操作與訓練時有所差異,導致在同樣的輸入下,量化模型的輸出結果和板端部署模型的輸出結果不一致。

本文將基於開發者社群中已經發布的地平線 bev 參考演算法板端輸入資料準備教程,以 bev_mt_lss 參考演算法為例,介紹 PC 端和板端輸出一致性驗證的過程。

02 PC 端輸入獲取

PC 端輸入的獲取主要包括輸入資料準備、輸出節點配置和執行推理指令碼這三個步驟,下面將對其進行逐一介紹。

2.1 輸入資料準備

bev_mt_lss 參考演算法的 PC 端輸入為:

獲取到 6V 影像和 homography 矩陣後,配置 config 檔案的 infer_cfg 欄位中輸入路徑引數 infer_inputs:

infer_cfg = dict(
    model=model,
    infer_inputs=dict(
        #6V影像的存放路徑
        imagedir="./tmp_orig_data/nuscenes/infer_imgs/single_frame/imgs",
        #homography矩陣的存放路徑
        homo="./tmp_orig_data/nuscenes/infer_imgs/single_frame/homo/ego2img.npy",
    ),
    ...
)

bev 參考演算法的輸入的 6V 影像的有順序的,所以需要在 config 檔案的 process_inputs 函式中定義輸入影像的順序,如下所示:

def process_inputs(infer_inputs, transforms=None):

    resize_size = resize_shape[1:]
    input_size = val_data_shape[1:]
    orig_imgs = []
    #定義輸入影像的順序
    input_list=[
    'n008-2018-08-01-15-16-36-0400__CAM_FRONT_LEFT__1533151603504799.jpg',
    'n008-2018-08-01-15-16-36-0400__CAM_FRONT__1533151603512404.jpg',
    'n008-2018-08-01-15-16-36-0400__CAM_FRONT_RIGHT__1533151603520482.jpg',
    'n008-2018-08-01-15-16-36-0400__CAM_BACK_LEFT__1533151603547405.jpg',
    'n008-2018-08-01-15-16-36-0400__CAM_BACK__1533151603537558.jpg',
    'n008-2018-08-01-15-16-36-0400__CAM_BACK_RIGHT__1533151603528113.jpg'
    ]
    #for i, img in enumerate(os.listdir(infer_inputs["imagedir"])):
    for i,img in enumerate(input_list):
        img = os.path.join(infer_inputs["imagedir"], img)
        img, orig_shape = process_img(img, resize_size, input_size)
        orig_imgs.append({"name": i, "img": img})
        
        ...
    return model_input, vis_inputs

6V 影像的輸入順序為:FRONT_LEFT,FRONT,FRONT_RIGHT,BACK_LEFT,BACK,BACK_RIGHT

2.2 輸出節點配置

2.2.1 dump 分割頭輸出

在 docker 環境下,進入到/usr/local/lib/python3.8/dist-packages/hat/models/task_modules/fcn/head.py 目錄下,在 FCNHead 類的 forward 函式中儲存分割頭的輸出,如下所示:

#step1:匯入fx_wrap和numpy
from hat.utils.model_helpers import fx_wrap
import numpy as np 
 
    #step2:定義儲存輸出的函式saveoutput並使用fx_warp
    @fx_wrap()
    def saveoutput(self,seg_pred):
        seg_pred=seg_pred.as_subclass(torch.Tensor)
        seg_pred=seg_pred.view(-1,1).cpu().numpy()
        print("------start to save seghead output------")
        np.savetxt("./lss/seg_pred.txt",seg_pred,fmt='%d', delimiter=',')
        print("-----save seghead output ok------")
        return seg_pred
    def forward(self, inputs: List[torch.Tensor]):
        x = inputs[self.input_index]
        x = self.convs(x)
        if self.dropout:
            x = self.dropout(x)
        seg_pred = self.cls_seg(x)
        #step3:呼叫saveoutput函式
        seg_pred=self.saveoutput(seg_pred)
        if self.training:
            if self.upsample_output_scale:
                seg_pred = self.resize(seg_pred)
            if self.argmax_output:
                seg_pred = seg_pred.argmax(dim=1)
        
        if self.dequant_output:
            seg_pred = self.dequant(seg_pred)
        return seg_pred

2.2.2 dump 檢測頭輸出

本節以 bev 參考演算法檢測頭的“height"屬性輸出為例,介紹如何匯出 PC 端的檢測頭輸出,將其儲存為 txt 檔案。

在 docker 環境下,進入到/usr/local/lib/python3.8/dist-packages/hat/models/task_modules/centerpoint/head.py 目錄下,在 TaskHead 類的 forward 函式中 dump 檢測頭的輸出,如下所示:

#step1:匯入fx_wrap和numpy
from hat.utils.model_helpers import fx_wrap
import numpy as np
    #step2:定義儲存指定檢測頭的輸出函式 
    @fx_wrap()
    def saveoutput(self,x):
        x=self.__getattr__("height")(x).as_subclass(torch.Tensor)
        x=x.view(-1,1).cpu().numpy()
        print("------start to save dethead output------")
        np.savetxt("./lss/output_height.txt",x,fmt='%d', delimiter=',')
        print("-----save dethead output ok------")
        return x  
    def forward(self, x):
        ret_dict = {}
        #step3:呼叫輸出儲存函式
        x = self.saveoutput(x)
        for head in self.heads:
            ret_dict[head] = self.dequant(self.__getattr__(head)(x))
        return ret_dict

本節僅選擇了檢測頭的一個類別的 height 輸出一致性的驗證,也可以選擇在/usr/local/lib/python3.8/dist-packages/hat/models/task_modules/centerpoint/head.py 中儲存檢測頭的其它屬性輸出來驗證一致性。

2.3 執行 infer.py

最後,執行推理指令碼 infer.py:

#啟動docker
#進入到OE包的ddk/samples/ai_toolchain/horizon_model_train_sample/scripts目錄下
python3 tools/infer.py -c  ./configs/bev/bev_mt_lss_efficientnetb0_nuscenes.py

執行 infer.py 之前請參考【參考演算法】地平線 Bev_mt_lss 參考演算法-v1.2.1 3.1.3 節對 config 檔案進行必要的修改

執行 infer.py 完畢後,生成的 seg_pred.txt 即為模型的分割頭輸出,output_height.txt 為檢測頭的 “height” 輸出。

03 板端輸入獲取

板端端輸入的獲取主要包括輸入資料準備和執行 hrt_model_exec 工具這兩個步驟,下面將對其進行逐一介紹。

3.1 輸入資料準備

3.2 執行 hrt_model_exec 工具

獲取到 bev_mt_lss 板端 hbm 的 3 個輸入後,在板端執行 hrt_model_exec 工具來 dump 模型的輸出,命令如下:

hrt_model_exec infer --model_file=model.hbm --input_file=inputnv12_lss.bin,fpoints.bin,dpoints.bin --enable_dump True --dump_format txt

工具執行完成後,會在當前路徑下生成數個 txt 檔案,分割頭對應的輸出是 model_infer_output_0.txt,檢測頭的“height”屬性對應的輸出是 model_infer_output_32.txt 檔案。

可透過 hrt_model_exec model_info --model_file model.hbm 來獲取模型輸出節點的資訊。

04 輸出結果對比

將 2.3 節匯出的 PC 端分割頭的輸出 seg_pred.txt 和檢測頭輸出 output_height.txt 分別與 3.2 節 dump 出的 model_infer_output_0.txt 和 model_infer_output_32.txt 對比,如果數值相同,則說明一致性驗證透過。

相關文章