女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

旭日X3派BPU部署教程系列之帶你輕松走出模型部署新手村

地瓜機器人 ? 2022-11-29 14:37 ? 次閱讀

安裝準備

本部分主要介紹在使用工具鏈前必須的環境準備工作,包含開發機部署(個人電腦)和開發板部署(例如旭日開發板等包含BPU設備)兩個部分。

開發機部署(個人電腦)

官方的示例教程的開發機都是Linux系統,實際上Windows系統也是可以的。最建議的方式是利用docker,模型轉換過程主要還是基于CPU,用不到GPU,所以用docker就夠了。

(1)安裝docker

考慮到用戶多數是基于個人電腦,所以相關環境的配置都是基于Windows的。相關文檔內提供了Docker Desktop Installer.exe安裝文件(見地平線開發者社區),安裝之后,用管理員方式啟動得到如下界面。

1.png

我們可以從地平線天工開物cpu docker hub獲取部署所需要的CentOS Docker鏡像。使用最新鏡像v1.13.6,以管理員模式運行CMD,輸入docker,可以顯示出docker的幫助信息。

選擇最新版本,則在cmd中輸入命令docker pull openexplorer/ai_toolchain_centos_7:v1.13.6,即可自動開始docker的安裝。

2.png

安裝成功之后,即可在docker中查看成功安裝的工具鏈鏡像:

3.png

(2)配置天工開物OpenExplorer

OpenExplorer工具包的下載,需要wget支持,wget的下載鏈接為GNU Wget for Windows,安裝好之后即可在cmd中通過如下命令下載工具包,解壓后,工具包的內容如下所示,如果需要其他版本的,可以參考官網信息資料下載專區。

4.png

docker除了要掛載OpenExplorer工具包,還要掛載數據集文件夾,通過如下指令可以下載官方提供的數據集,或者從相關文檔中的的OpenExplorer/dataset文件夾中下載,下載之后記得解壓。

# cifar wget -c ftp://vrftp.horizon.ai/Open_Explorer/eval_dataset/cifar-10.tar.gz # cityscapes wget -c ftp://vrftp.horizon.ai/Open_Explorer/eval_dataset/cityscapes.tar.gz # coco wget -c ftp://vrftp.horizon.ai/Open_Explorer/eval_dataset/coco.tar.gz # imagenet wget -c ftp://vrftp.horizon.ai/Open_Explorer/eval_dataset/imagenet.tar.gz # VOC wget -c ftp://vrftp.horizon.ai/Open_Explorer/eval_dataset/VOC.tar.gz

(PS.由于作者在Windows下解壓導致部分軟連接消失,因此補充一些必要的軟連接更新)

# 重新構建model_zoo軟連接 rm /open_explorer/ddk/samples/ai_toolchain/horizon_model_convert_sample/01_common/model_zoo ln -s /open_explorer/ddk/samples/ai_toolchain/model_zoo /open_explorer/ddk/samples/ai_toolchain/horizon_model_convert_sample/01_common/model_zoo

(3) 啟動Docker

按照教程,啟動docker要執行run_docker.sh,可直接按照本文教程直接配置好指令即可。在進入docker之前,先記錄兩個內容:

5.png

天工開物OpenExplorer根目錄:我的環境下是"D:\05 - 項目\01 - 旭日x3派\horizon_xj3_open_explorer_v2.2.3_20220617",記得加雙引號防止出現空格,該目錄要掛載在docker中/open_explorer目錄下;

dataset根目錄:我的環境下是"D:\01 - datasets",記得加雙引號防止出現空格,該目錄需要掛載在docker中的/data/horizon_x3/data目錄下;

*輔助文件夾根目錄:官方教程其實是沒有這個過程的,我把這個掛載在docker里,就是充當個類似U盤的介質。比如在我的環境下是"D:\05 - 項目\01 - 旭日x3派\BPUCodes",我可以在windows里面往這個文件夾拷貝數據,這些數據就可以在docker中使用,在docker中的路徑為/data/horizon_x3/codes。

那么,在cmd(管理員)中輸入如下指令即可進入docker(切記要確保剛剛安裝的軟件docker desktop是開啟的),值得注意的是CMD不支持換行,記得刪掉后面的\然后整理為一行,這時我們可以看到由命令行掛載的3個目錄。

import cv2 # 打開攝像頭并顯示 docker run -it --rm \ -v "D:\05 - 項目\01 - 旭日x3派\horizon_xj3_open_explorer_v2.2.3_20220617":/open_explorer \ -v "D:\01 - datasets":/data/horizon_x3/data \ -v "D:\05 - 項目\01 - 旭日x3派\BPUCodes":/data/horizon_x3/codes \ openexplorer/ai_toolchain_centos_7:v1.13.6

6.png

至此,已經成功通過Docker鏡像進入了完整的工具鏈開發環境。可以鍵入 hb_mapper --help 命令驗證下是否可以正常得到幫助信息,hb_mapper 是工具鏈的一個常用工具, 在后文的模型轉換部分對其有詳細介紹。

7.png

除了通過掛載個額外的文件夾來實現文件的拷貝,還有一個方法可以直接將文件拷貝到目標目錄。

假如我們要拷貝一個文件"C:\Users\Zhaoxi-Li\Downloads\Pangolin-0.8.tar.gz"到docker中的/root/downloads下(目錄要存在),那么用管理員權限新開一個cmd,輸入docker ps,記錄CONTAINER ID,然后按照docker cp 本地文件的路徑 container_id:的方式輸入docker cp "C:\Users\Zhaoxi-Li\Downloads\Pangolin-0.8.tar.gz" 677de3a8b719:/root/downloads即可完成文件拷貝。

8.png

開發板部署(旭日3派為例)

在使用之前,一定要按照教程多方位玩轉《地平線新發布AIoT開發板——旭日X3派(Sunrise x3 Pi)》(可于「地平線開發者社區」-「開發者論壇」搜索查看)完成系統的啟動。

工具鏈的部分補充工具未包含在系統鏡像中,這些工具已經放置在Open Explorer發布包中。因此在我們剛剛拉取的docker中,輸入cd /open_explorer/ddk/package/board/,執行命令bash install.sh 192.168.0.104,其中192.168.0.104為開發板IP地址,可用ifconfig查看。

這個功能主要就是拷貝hrt_bin_dump和hrt_model_exec到開發板,并在開發板的/etc/profile里面添加幾個環境,添加內容如下所示。

#Horizon Open Explorer ENV export PATH=/userdata/.horizon/:/userdata/.horizon/ai_express_webservice_display/sbin/:$PATH export HORIZON_APP_PATH=/userdata/.horizon/:$HORIZON_APP_PATH #Horizon Open Explorer ENV

在開發板里輸入hrt_model_exec,如果有如下輸出,說明開發板部署完成。

9.png

模型部署

BPU的工具鏈是非常長的,在部署之前一定要先理解下每個流程的含義。

模型準備

支持Caffe模型和ONNX模型,Caffe模型的支持度是最高的。咱們常用的Pytorch模型是可以轉為ONNX模型的。實際上,OpenCV內部集成的dnn模塊也是以caffe為主的,所以盡管Caffe在學術圈不火了,但它在工業圈一直廣泛使用。

驗證模型

驗證模型中所用的層是否可以在BPU中使用。需要利用hb_mapper checker后面跟一堆參數來對模型進行配置。配置信息如下:

--model-type:輸入的模型類型,onnx或caffe ;

--march:芯片類型,這個板子只能填bernoulli2;

--proto:若模型為caffe,則填入caffe所需的prototxt文件。onnx模型就不用寫這個參數;

--model:模型文件,caffe就是*.caffemodel,onnx模型就是.onnx;

--input-shape:模型數據輸入的名稱和維度,比如輸入層名稱叫input1,維度為1x3x128x128,那么該參數就可以寫為--input-shape input1 1x3x128x128。如果我們的模型有多個輸入,比如第二個輸入層名稱叫input2,維度為1x96x28x28,那么參數設置就寫為--input-shape input1 1x3x128x128 --input-shape input2 1x96x28x28(該參數可選,不寫的話程序會自動識別參數,如果指定以指定為主);

--output:設置輸出日志文件(已經移除,默認存在根目錄的hb_mapper_checker.log中);

注意:如果模型檢查不通過,控制臺會有明顯的ERROR信息,一般都會檢查出某些層不支持BPU,這時候可以寫個自定義層來解決,后面會提供個例子來展示不通過情況的處理辦法。

轉換模型

模型檢查通過之后,就可以通過配置一個yaml文件來將模型文件轉為可以在BPU上運行的文件了,后面配置模型時候會進行詳細介紹。

--model-type:根據模型類型指定caffe或onnx;

--config:模型編譯的配置文件,內容采用yaml格式,文件名使用.yaml后綴。

模型性能、精度分析與調優

初時BPU的時候都會疑惑,為什么轉換模型后精度會有變化?因為模型轉換后是由float轉為int8計算的,這個過程必有精度損失。如果精度差異較大,就需要按照官方教程進行調優。

Yolov3部署示例

將yolov3放置在docker文件中的/open_explorer/ddk/samples/ai_toolchain/horizon_model_convert_sample/04_detection/02_yolov3_darknet53/mapper路徑下,以官方示例,來初步了解下BPU的相關操作流程。

10.png

模型準備

prototxt和caffemodel文件放置在docker中的/open_explorer/ddk/samples/ai_toolchain/model_zoo/mapper/detection/yolov3_darknet53路徑下。

11.png

驗證模型

/open_explorer/ddk/samples/ai_toolchain/horizon_model_convert_sample/04_detection/02_yolov3_darknet53/mapper,進入該路徑后,輸入 ./01_check.sh,遇到下述這些輸出,就代表轉換完成了。

12.png

前面已經介紹了,模型驗證需要利用hb_mapper checker后面跟一堆參數來對模型進行配置,下面這些就是 ./01_check.sh的主要內容。

13.png

下面帶各位來理解這些參數:

--model-type:我們這些模型是Caffe,所以填caffe;

--march:旭日X3派只能填bernoulli2;

--proto:填prototxt文件路徑

即../../../01_common/model_zoo/mapper/detection/yolov3_darknet53/yolov3_transposed.prototxt;

--model:填caffemodel文件路徑

即../../../01_common/model_zoo/mapper/detection/yolov3_darknet53/yolov3.caffemodel;

--input-shape:這里沒有指定,代碼可以自動去查找。

14.png

轉換模型

在轉換模型之前需要準備校準數據,輸入./02_preprocess.sh會自動從docker的open_explorer包中抽取數據;再輸入./03_build.sh,輸出一大堆的命令行,等待一段時間之后會輸出。

15.png

這里我們可以發現每一層網絡都要評估一個相似度,這也是為什么要準備校準數據,因為BPU是INT8計算,所以注定會有精度損失。而且這些誤差也是可以傳遞的,所以到后面精度是越來越低的。如果網絡深度過高,也會導致整體精度的下降。

16.png

為了更好的理解這些轉換流程,將對其中的準備校準數據、模型轉換過程進行一個完全解讀。

(1)原理解讀:準備校準數據

這個過程調用了腳本./02_preprocess.sh,這個腳本核心調用的是python文件,data_preprocess.py的源碼可以自行去查看。

python3 ../../../data_preprocess.py \ --src_dir ../../../01_common/calibration_data/coco \ --dst_dir ./calibration_data_rgb_f32 \ --pic_ext .rgb \ --read_mode opencv

然而data_preprocess.py并不適合初學者進行閱讀,因為其兼容了太多東西,很簡單的一些功能硬是寫復雜了,那么就圍繞這個模型,給各位縷縷校準數據到底要準備啥。

首先要搞清楚,我們要準備的校準數據是什么樣的: 校準數據要將圖像數據按照目標尺寸、目標顏色(rgb or bgr等)、目標排布(CHW or HWC)進行存儲。那么下面,帶著這些問題進行處理,先構建一個基本處理流程:

①加載一個文件夾下的所有圖像地址信息。圖像目錄為/open_explorer/ddk/samples/ai_toolchain/horizon_model_convert_sample/01_common/calibration_data/coco;

②對每個圖像按照校準格式進行輸出。從prototxt我們知道圖像的尺寸為416x416,從./03_build.sh調用的yaml文件可知圖像輸入格式為rgb,數據排布為CHW;

③將轉換后的圖像利用numpy.tofile函數存到目標文件夾下(你在哪轉換的,就要在哪個目錄存校準數據文件夾calibration_data)。

開始寫我們自己的Python代碼,每個步驟都寫了注釋,各位可以直接理解。

# prepare_calibration_data.py import os import cv2 import numpy as np src_root = '/open_explorer/ddk/samples/ai_toolchain/horizon_model_convert_sample/01_common/calibration_data/coco' cal_img_num = 100 # 想要的圖像個數 dst_root = '/open_explorer/ddk/samples/ai_toolchain/horizon_model_convert_sample/04_detection/02_yolov3_darknet53/mapper/calibration_data' ## 1. 從原始圖像文件夾中獲取100個圖像作為校準數據 num_count = 0 img_names = [] for src_name in sorted(os.listdir(src_root)): if num_count > cal_img_num: break img_names.append(src_name) num_count += 1 # 檢查目標文件夾是否存在,如果不存在就創建 if not os.path.exists(dst_root): os.system('mkdir {0}'.format(dst_root)) ## 2 為每個圖像轉換 # 參考了OE中/open_explorer/ddk/samples/ai_toolchain/horizon_model_convert_sample/01_common/python/data/下的相關代碼 # 轉換代碼寫的很棒,很智能,考慮它并不是官方python包,所以我打算換一種寫法 ## 2.1 定義圖像縮放函數,返回為np.float32 # 圖像縮放為目標尺寸(W, H) # 值得注意的是,縮放時候,長寬等比例縮放,空白的區域填充顏色為pad_value, 默認127 def imequalresize(img, target_size, pad_value=127.): target_w, target_h = target_size image_h, image_w = img.shape[:2] img_channel = 3 if len(img.shape) > 2 else 1 # 確定縮放尺度,確定最終目標尺寸 scale = min(target_w * 1.0 / image_w, target_h * 1.0 / image_h) new_h, new_w = int(scale * image_h), int(scale * image_w) resize_image = cv2.resize(img, (new_w, new_h)) # 準備待返回圖像 pad_image = np.full(shape=[target_h, target_w, img_channel], fill_value=pad_value) # 將圖像resize_image放置在pad_image的中間 dw, dh = (target_w - new_w) // 2, (target_h - new_h) // 2 pad_image[dh:new_h + dh, dw:new_w + dw, :] = resize_image return pad_image ## 2.2 開始轉換 for each_imgname in img_names: img_path = os.path.join(src_root, each_imgname) img = cv2.imread(img_path) # BRG, HWC img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # RGB, HWC img = imequalresize(img, (416, 416)) img = np.transpose(img, (2, 0, 1)) # RGB, CHW # 將圖像保存到目標文件夾下 dst_path = os.path.join(dst_root, each_imgname + '.rgbchw') print("write:%s" % dst_path) # 圖像加載默認就是uint8,但是不加這個astype的話轉換模型就會出錯 # 轉換模型時候,加載進來的數據竟然是float64,不清楚內部是怎么加載的。 img.astype(np.uint8).tofile(dst_path) print('finish')

(2)原理解讀:轉換配置

模型轉換的核心在于配置目標的yaml文件,官方也提供了一個yolov3_darknet53_config.yaml可供用戶直接試用,每個參數都給了注釋,我能感受到開發者的誠意。然而模型轉換的配置文件參數太多,如果想改參數都不知道如何下手。

本節目的是引導各位快速上手,因此一些參數我暫時不解釋意義,用默認即可。該模板可將待配置的30多個參數壓縮到9個參數,方便各位快速的配置簡單模型。本yaml模板適用于的模型具有如下屬性:

  • 無自定義層,換句話說,BPU支持該模型的所有層;
  • 輸入節點只有1個,且輸入是圖像。

先復制這個模板到代碼根目錄,命名為"yolov3_simple.yaml",然后根據后面的思維導圖進行配置具體參數。

model_parameters: # [待配置參數],見思維導圖"模型參數組"部分 prototxt: '***.prototxt' caffe_model: '****.caffemodel' onnx_model: '****.onnx' output_model_file_prefix: 'mobilenetv1' # 默認參數,暫不需要理解 march: 'bernoulli2' input_parameters: # [待配置參數],見思維導圖"輸入信息參數組/原始模型參數"部分 input_type_train: 'bgr' input_layout_train: 'NCHW' # [待配置參數],見思維導圖"輸入信息參數組/轉換后模型參數"部分 input_type_rt: 'yuv444' # [待配置參數],見思維導圖"輸入信息參數組/輸入數據預處理"部分 norm_type: 'data_mean_and_scale' mean_value: '103.94 116.78 123.68' scale_value: '0.017' # 默認參數,暫不需要理解 input_layout_rt: 'NHWC' # 校準參數組,全部默認 calibration_parameters: cal_data_dir: './calibration_data' calibration_type: 'max' max_percentile: 0.9999 # 編譯參數組,全部默認 compiler_parameters: compile_mode: 'latency' optimize_level: 'O3' debug: False # 別看官網寫的可選,實際上不寫這個出bug

思維導圖如下所示,帶著這個圖,請各位耐心地跟我一步步配置,僅需要配置9個即可。

17.png

模型參數組參數model_parameters配置:

output_model_file_prefix:給轉換后的模型起個名,這里叫做'yolov3_selfyaml',注意字符串前后都要有個單引號;

prototxt:caffe的prototxt,這里為'../../../01_common/model_zoo/mapper/detection/yolov3_darknet53/yolov3_transposed.prototxt';

caffe_model:caffe的模型文件,這里為'../../../01_common/model_zoo/mapper/detection/yolov3_darknet53/yolov3.caffemodel';

onnx_model:刪掉。因為我們用的是Caffe。

輸入信息組參數配置input_parameters:

input_type_train:原始浮點模型的輸入數據格式,支持多種圖像格式,這里設置為'rgb'(這就是前文校準模型時為什么要將BGR轉為RGB); input_layout_train:從前文的prototxt可以看出,數據輸入排布為'NCHW'(所以在模型校準時我們將圖像數據由HWC轉為CHW) input_type_rt:模型轉換后,我們期望輸入的圖像格式。我們在訓練模型和部署模型的時候,圖像輸入格式是可以變的,NV12是一些相機返回的原始數據格式,作為嘗試設置為'nv12'; norm_type:網絡不可能拿原始圖像數據作為輸入的,一般都要進行一個歸一化操作。這里用的模型對應的歸一化代碼為inpBlob = cv2.dnn.blobFromImage(frame, 1.0 / 255, (inWidth, inHeight), (0, 0, 0), swapRB=False, crop=False),無減均值項,只有尺度項。因此,該屬性設置為'data_scale'; mean_value:刪掉,因為網絡沒有均值項; scale_value:尺度為1.0 / 255,因此設置為0.003921568627451。

最終,我們的yaml文件內容如下所示:

model_parameters: prototxt: '../../../01_common/model_zoo/mapper/detection/yolov3_darknet53/yolov3_transposed.prototxt' caffe_model: '../../../01_common/model_zoo/mapper/detection/yolov3_darknet53/yolov3.caffemodel' output_model_file_prefix: 'yolov3_selfyaml' march: 'bernoulli2' input_parameters: input_type_train: 'rgb' input_layout_train: 'NCHW' input_type_rt: 'nv12' norm_type: 'data_scale' scale_value: 0.003921568627451 input_layout_rt: 'NHWC' calibration_parameters: cal_data_dir: './calibration_data' calibration_type: 'max' max_percentile: 0.9999 compiler_parameters: compile_mode: 'latency' optimize_level: 'O3' debug: False

之后,用我們親手準備的校準數據和配置的輕量yaml進行模型轉換,在控制臺輸入指令hb_mapper makertbin --config yolov3_simple.yaml --model-type caffe。

模型推理

在官方給的demo中,04_inference.sh可以直接調用執行好的模型進行推理,但是為了我覺得這種方案對于未來要如何部署自己的模型是無意義的。因此我閱讀了官方推理的demo之后,自己寫個完整的推理過程。模型推理流程主要可以分為以下三個步驟:

①數據預處理,生成推理所需數據;

②利用處理好的數據進行模型推理,得到輸出;

③將輸出轉換成最終數據,也就是后處理過程。

(PS.使用的測試圖像路徑為/open_explorer/ddk/samples/ai_toolchain/horizon_model_convert_sample/01_common/test_data/det_images/kite.jpg)

在上一節中,模型轉換后有三個關鍵文件:

yolov3_selfyaml_original_float_model.onnx:圖像量化前的模型; yolov3_selfyaml_quantized_model.onnx:圖像量化后的模型; yolov3_selfyaml.bin:在BPU上用于推理的模型文件,輸出結果與yolov3_selfyaml_quantized_model.onnx一致。

下面將給出推理一張圖像的相關代碼,其中我把圖像格式轉換,以及yolo后處理的細節封裝在一個包里,相關的代碼已經放在社區里供大家參考。

18.png

以下是inference_model.py的代碼細節,在每個關鍵過程中都給出了相關的注釋:

19.png

從代碼可以獲知模型會輸出三層,每層的維度為(1, 13, 13, 255) (1, 26, 26, 255) (1, 52, 52, 255),對著下圖,可以很容易對應的是網絡的哪一層。

import numpy as np import cv2 import os from horizon_tc_ui import HB_ONNXRuntime from bputools.format_convert import imequalresize, bgr2nv12_opencv, nv122yuv444 from bputools.yolo_postproc import modelout2predbbox, recover_boxes, nms, draw_bboxs modelpath_prefix = '/open_explorer/ddk/samples/ai_toolchain/horizon_model_convert_sample' # img_path 圖像完整路徑 img_path = os.path.join(modelpath_prefix, '01_common/test_data/det_images/kite.jpg') # model_path 量化模型完整路徑 model_root = os.path.join(modelpath_prefix, '04_detection/02_yolov3_darknet53/mapper/model_output') model_path = os.path.join(model_root, 'yolov3_selfyaml_quantized_model.onnx') # 1. 加載模型,獲取所需輸出HW sess = HB_ONNXRuntime(model_file=model_path) sess.set_dim_param(0, 0, '?') model_h, model_w = sess.get_hw() # 2 加載圖像,根據前面模型,轉換后的模型是以NV12作為輸入的 # 但在OE驗證的時候,需要將圖像再由NV12轉為YUV444 imgOri = cv2.imread(img_path) img = imequalresize(imgOri, (model_w, model_h)) nv12 = bgr2nv12_opencv(img) yuv444 = nv122yuv444(nv12, [model_w, model_h]) # 3 模型推理 input_name = sess.input_names[0] output_name = sess.output_names output = sess.run(output_name, {input_name: np.array([yuv444])}, input_offset=128) print(output_name) print(output[0].shape, output[1].shape, output[2].shape) # ['layer82-conv-transposed', 'layer94-conv-transposed', 'layer106-conv-transposed'] # (1, 13, 13, 255) (1, 26, 26, 255) (1, 52, 52, 255) # 4 檢測結果后處理 # 由output恢復416*416模式下的目標框 pred_bbox = modelout2predbbox(output) # 將目標框恢復到原始分辨率 bboxes = recover_boxes(pred_bbox, (imgOri.shape[0], imgOri.shape[1]), input_shape=(model_h, model_w), score_threshold=0.3) # 對檢測出的框進行非極大值抑制,抑制后得到的框就是最終檢測框 nms_bboxes = nms(bboxes, 0.45) print("detected item num: {0}".format(len(nms_bboxes))) # 繪制檢測框 draw_bboxs(imgOri, nms_bboxes) cv2.imwrite('detected.png', imgOri)

上板運行

我們將下圖所示的一些文件拖到旭日X3派開發板中,注意inference_model_bpu.py跟docker中是有微小的改動的。

20.png

注意,在執行前要安裝一些包sudo pip3 install EasyDict pycocotools,切記要加sudo,這樣安裝的路徑不是用戶目錄,在運行BPU模型時候,也是必須要加sudo的。

21.png

inference_model_bpu.py的源碼如下所示,與在docker中不同,nv12不需要再轉為yuv444了,模型的運行也有一些差別,而后處理幾乎沒有變化。

import numpy as np import cv2 import os from hobot_dnn import pyeasy_dnn as dnn from bputools.format_convert import imequalresize, bgr2nv12_opencv, nv122yuv444 from bputools.yolo_postproc import modelout2predbbox, recover_boxes, nms, draw_bboxs def get_hw(pro): if pro.layout == "NCHW": return pro.shape[2], pro.shape[3] else: return pro.shape[1], pro.shape[2] modelpath_prefix = '' # img_path 圖像完整路徑 img_path = 'COCO_val2014_000000181265.jpg' # model_path 量化模型完整路徑 model_path = 'yolov3_selfyaml.bin' # 1. 加載模型,獲取所需輸出HW models = dnn.load(model_path) model_h, model_w = get_hw(models[0].inputs[0].properties) # 2 加載圖像,根據前面模型,轉換后的模型是以NV12作為輸入的 # 但在OE驗證的時候,需要將圖像再由NV12轉為YUV444 imgOri = cv2.imread(img_path) img = imequalresize(imgOri, (model_w, model_h)) nv12 = bgr2nv12_opencv(img) # 3 模型推理 t1 = cv2.getTickCount() outputs = models[0].forward(nv12) t2 = cv2.getTickCount() outputs = (outputs[0].buffer, outputs[1].buffer, outputs[2].buffer) print(outputs[0].shape, outputs[1].shape, outputs[2].shape) # (1, 13, 13, 255) (1, 26, 26, 255) (1, 52, 52, 255) print('time consumption {0} ms'.format((t2-t1)*1000/cv2.getTickFrequency())) # 4 檢測結果后處理 # 由output恢復416*416模式下的目標框 pred_bbox = modelout2predbbox(outputs) # 將目標框恢復到原始分辨率 bboxes = recover_boxes(pred_bbox, (imgOri.shape[0], imgOri.shape[1]), input_shape=(model_h, model_w), score_threshold=0.3) # 對檢測出的框進行非極大值抑制,抑制后得到的框就是最終檢測框 nms_bboxes = nms(bboxes, 0.45) print("detected item num: {0}".format(len(nms_bboxes))) # 繪制檢測框 draw_bboxs(imgOri, nms_bboxes) cv2.imwrite('detected.png', imgOri)

手部關鍵點檢測網絡

手部關鍵點檢測是做手勢識別的一個關鍵過程,該代碼基于Caffe,而且無自定義層,因此作為個引子,帶領各位先初步使用BPU。

模型準備

在前期安裝準備中,我們掛載了一個目錄-v "D:\05 - 項目\01 - 旭日x3派\BPUCodes":/data/horizon_x3/codes,下載好代碼后,按照如下方式放置相關文件,此時可以發現docker中也有這些文件。

22.png

驗證模型

驗證前,先將docker根目錄切換到模型根目錄下cd /data/horizon_x3/codes/HandKeypointDetection/hand/。模型驗證需要利用hb_mapper checker后面跟一堆參數來對模型進行配置。下面帶各位來配置這些參數:

--model-type:我們這些模型是Caffe,所以填caffe

--march:旭日3派只能填bernoulli2

--proto:填prototxt文件名,即pose_deploy.prototxt

--model:填caffemodel文件名,即pose_iter_102000.caffemodel

--input-shape:打開prototxt文件,查找input屬性,可以發現模型只有一個輸入,輸入層的名稱為image,輸入圖像的維度大小為1x3x368x368,那么這個參數設置就寫為image 1x3x368x368。

23.png

綜上所述,在docker中需要輸入如下指令來完成模型驗證過程:

hb_mapper checker \ --model-type caffe \ --march bernoulli2 \ --proto pose_deploy.prototxt \ --model pose_iter_102000.caffemodel \ --input-shape image 1x3x368x368

輸出結果如下所示,可以看到整個流程的轉換狀態以及每個節點是在BPU還是CPU上運行的。整個控制臺的運行結果默認存在根目錄的hb_mapper_checker.log中。

24.png

轉換模型

與前面流程不同,這里先配置yaml文件,再準備校準數據。

(1)配置yaml文件

模型參數組參數model_parameters配置:

output_model_file_prefix:給轉換后的模型起個名,這里叫做'handkpdet'(hand keypoint detection);

prototxt:caffe的prototxt,這里為'pose_deploy.prototxt';

caffe_model:caffe的模型文件,這里為'pose_iter_102000.caffemodel'

onnx_model:刪掉。因為我們用的是Caffe。

輸入信息組參數配置input_parameters:

input_type_train:原始浮點模型的輸入數據格式,支持多種圖像格式。我們這個模型,輸入的是彩色圖,考慮到opencv加載圖像默認是BGR通道,因此這里設置為'bgr';

input_layout_train:從前文的prototxt可以看出,數據輸入排布為'NCHW';

input_type_rt:模型轉換后,我們期望輸入的圖像格式。我們在訓練模型和部署模型的時候,圖像輸入格式是可以變的,NV12是一些相機返回的原始數據格式,考慮到我們測試仍然基于本地圖像,因此這里仍然設置為'bgr';

norm_type:網絡不可能拿原始圖像數據作為輸入的,一般都要進行一個歸一化操作。這里用的模型對應的歸一化代碼為inpBlob = cv2.dnn.blobFromImage(frame, 1.0 / 255, (inWidth, inHeight), (0, 0, 0), swapRB=False, crop=False),無減均值項,只有尺度項。因此,該屬性設置為'data_scale';

mean_value:刪掉,因為網絡沒有均值項;

scale_value:尺度為1.0 / 255,因此設置為'0.0039'。

最終,我們的yaml文件handpoint.yaml內容為:

model_parameters: prototxt: 'pose_deploy.prototxt' caffe_model: 'pose_iter_102000.caffemodel' output_model_file_prefix: 'handkpdet' march: 'bernoulli2' input_parameters: input_type_train: 'bgr' input_layout_train: 'NCHW' input_type_rt: 'bgr' norm_type: 'data_scale' scale_value: '0.0039' input_layout_rt: 'NHWC' calibration_parameters: cal_data_dir: './calibration_data' calibration_type: 'max' max_percentile: 0.9999 compiler_parameters: compile_mode: 'latency' optimize_level: 'O3' debug: False

(2)準備校準數據

考慮到這個模型的輸入只有一個,因此,準備校準數據部分的代碼可以參考上一節的內容,需要修改的只有兩個地方,原始數據地址,和顏色轉換部分(取消了BGR轉RGB的過程),數據集用的是FreiHAND_pub_v2_eval.zip。

25.png

docker中,校準數據形式如下圖所示,共計100張。

26.png

(3)開始轉換

數據準備就緒,輸入命令hb_mapper makertbin --config handpoint.yaml --model-type caffe開始轉換我們的模型!等待一段時間之后,模型轉換成功,從結果可以看出來,模型的損失并不是很高!!感覺有戲,(☆▽☆)。

27.png

模型推理

由于該模型與前面的模型相似,都是以一張圖像作為輸入的,因此自己要補充的工作主要有兩點:

  • 完成圖像預處理部分。前面的yaml文件指明了,量化后的模型是以BGR、NHWC格式作為輸入的。因此,只需要調用resize成目標模型大小就行,opencv加載圖像時候默認是HWC格式。
  • 完成圖像后處理部分。圖像后處理一般與推理平臺沒有太大的關系,完整的流程都會有這個過程。

在docker中推理的完整代碼如下所示:

import numpy as np import cv2 import os from horizon_tc_ui import HB_ONNXRuntime import copy # img_path 圖像完整路徑 img_path = '/data/horizon_x3/codes/HandKeypointDetection/hand/FreiHAND_pub_v2_eval/evaluation/rgb/00000253.jpg' # model_path 量化模型完整路徑 model_path = '/data/horizon_x3/codes/HandKeypointDetection/hand/model_output/handkpdet_quantized_model.onnx' # 1. 加載模型,獲取所需輸出HW sess = HB_ONNXRuntime(model_file=model_path) sess.set_dim_param(0, 0, '?') model_h, model_w = sess.get_hw() # 2 加載圖像,根據前面yaml,量化后的模型以BGR NHWC形式輸入 imgOri = cv2.imread(img_path) img = cv2.resize(imgOri, (model_w, model_h)) # 3 模型推理 input_name = sess.input_names[0] output_name = sess.output_names output = sess.run(output_name, {input_name: np.array([img])}, input_offset=128) print(output_name) print(output[0].shape) # ['net_output'] # (1, 22, 46, 46) # 4 檢測結果后處理 # 繪制關鍵點 nPoints = 22 threshold = 0.1 POSE_PAIRS = [[0, 1], [1, 2], [2, 3], [3, 4], [0, 5], [5, 6], [6, 7], [7, 8], [0, 9], [9, 10], [10, 11], [11, 12], [0, 13], [13, 14], [14, 15], [15, 16], [0, 17], [17, 18], [18, 19], [19, 20]] imgh, imgw = imgOri.shape[:2] points = [] imgkp = copy.deepcopy(imgOri) for i in range(nPoints): probMap = output[0][0, i, :, :] probMap = cv2.resize(probMap, (imgw, imgh)) minVal, prob, minLoc, point = cv2.minMaxLoc(probMap) if prob > threshold: cv2.circle(imgkp, (int(point[0]), int(point[1])), 8, (0, 255, 255), thickness=-1, lineType=cv2.FILLED) cv2.putText(imgkp, "{}".format(i), (int(point[0]), int(point[1])), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, lineType=cv2.LINE_AA) points.append((int(point[0]), int(point[1]))) else: points.append(None) # 繪制骨架 imgskeleton = copy.deepcopy(imgOri) for pair in POSE_PAIRS: partA = pair[0] partB = pair[1] if points[partA] and points[partB]: cv2.line(imgskeleton, points[partA], points[partB], (0, 255, 255), 2) cv2.circle(imgskeleton, points[partA], 8, (0, 0, 255), thickness=-1, lineType=cv2.FILLED) cv2.circle(imgskeleton, points[partB], 8, (0, 0, 255), thickness=-1, lineType=cv2.FILLED) # 保存關鍵點和骨架圖 cv2.imwrite('handkeypoint.png', imgkp) cv2.imwrite('imgskeleton.png', imgskeleton)

上板運行

在開發板運行的程序與上述推理代碼差異不大,注意好模型的輸入數據格式即可,這里要注意,輸出的outputs與docker中有差異,要做output = (outputs[0].buffer,)轉換,這樣可以直接兼容后面的后處理部分,進而生成結果圖。

import numpy as np import cv2 import os from hobot_dnn import pyeasy_dnn as dnn import copy def get_hw(pro): if pro.layout == "NCHW": return pro.shape[2], pro.shape[3] else: return pro.shape[1], pro.shape[2] # img_path 圖像完整路徑 img_path = '20220806023323.jpg' # model_path 量化模型完整路徑 model_path = 'handkpdet.bin' # 1. 加載模型,獲取所需輸出HW models = dnn.load(model_path) model_h, model_w = get_hw(models[0].inputs[0].properties) # 2 加載圖像,根據前面yaml,量化后的模型以BGR NHWC形式輸入 imgOri = cv2.imread(img_path) img = cv2.resize(imgOri, (model_w, model_h)) # 3 模型推理 t1 = cv2.getTickCount() outputs = models[0].forward(img) t2 = cv2.getTickCount() output = (outputs[0].buffer,) print(outputs[0].buffer.shape) # (1, 22, 46, 46) print('time consumption {0} ms'.format((t2-t1)*1000/cv2.getTickFrequency())) # 4 檢測結果后處理 # 繪制關鍵點 nPoints = 22 threshold = 0.1 POSE_PAIRS = [[0, 1], [1, 2], [2, 3], [3, 4], [0, 5], [5, 6], [6, 7], [7, 8], [0, 9], [9, 10], [10, 11], [11, 12], [0, 13], [13, 14], [14, 15], [15, 16], [0, 17], [17, 18], [18, 19], [19, 20]] imgh, imgw = imgOri.shape[:2] points = [] imgkp = copy.deepcopy(imgOri) for i in range(nPoints): probMap = output[0][0, i, :, :] probMap = cv2.resize(probMap, (imgw, imgh)) minVal, prob, minLoc, point = cv2.minMaxLoc(probMap) if prob > threshold: cv2.circle(imgkp, (int(point[0]), int(point[1])), 8, (0, 255, 255), thickness=-1, lineType=cv2.FILLED) cv2.putText(imgkp, "{}".format(i), (int(point[0]), int(point[1])), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2, lineType=cv2.LINE_AA) points.append((int(point[0]), int(point[1]))) else: points.append(None) # 繪制骨架 imgskeleton = copy.deepcopy(imgOri) for pair in POSE_PAIRS: partA = pair[0] partB = pair[1] if points[partA] and points[partB]: cv2.line(imgskeleton, points[partA], points[partB], (0, 255, 255), 2) cv2.circle(imgskeleton, points[partA], 8, (0, 0, 255), thickness=-1, lineType=cv2.FILLED) cv2.circle(imgskeleton, points[partB], 8, (0, 0, 255), thickness=-1, lineType=cv2.FILLED) # 保存關鍵點和骨架圖 cv2.imwrite('handkeypoint.png', imgkp) cv2.imwrite('imgskeleton.png', imgskeleton)

我自己拍了兩張圖進行測試,第一排是晚上拍的,手指頭有點串味哈哈,整體檢測耗時在480ms左右,網絡深度沒有yolo高,也許是橫向的特征比較多。

28.png

原作者:小璽璽
原鏈接:本文轉自地平線開發者社區

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 模型
    +關注

    關注

    1

    文章

    3479

    瀏覽量

    49926
  • BPU
    BPU
    +關注

    關注

    0

    文章

    4

    瀏覽量

    2045
收藏 人收藏

    評論

    相關推薦
    熱點推薦

    部署image_classification模型卡住了怎么解決?

    我按照如下教程部署,然后編譯卡住了,誰能幫忙看看是咋回事。 https://github.com/STMicroelectronics/stm32ai-modelzoo-services/blob
    發表于 04-27 06:29

    ORinNano離線部署Deepseek R1大模型教程

    ORinNano離線部署Deepseek R1大模型教程
    的頭像 發表于 04-10 15:32 ?239次閱讀
    ORinNano離線<b class='flag-5'>部署</b>Deepseek R1大<b class='flag-5'>模型</b>教程

    【幸狐Omni3576邊緣計算套件試用體驗】DeepSeek 部署及測試

    【幸狐 Omni3576 邊緣計算套件測評】DeepSeek 部署及測試 本文介紹了幸狐 Omni3576 邊緣計算套件實現 DeepSeek 部署及測試的相關流程,包括模型介紹、部署
    發表于 03-21 19:31

    MSP430部署

    MSP430可以部署簡單的模型
    發表于 03-16 19:29

    K230D部署模型失敗的原因?

    MicroPython部署的無法正常運行,采用C++版本的無法實現部署 嘗試解決過程 1.考慮到可能是固件不匹配的問題,重新燒錄了流程(生成模型后給的readme)中要求的固件,依舊無法成功
    發表于 03-11 06:19

    如何部署OpenVINO?工具套件應用程序?

    編寫代碼并測試 OpenVINO? 工具套件應用程序后,必須將應用程序安裝或部署到生產環境中的目標設備。 OpenVINO?部署管理器指南包含有關如何輕松使用部署管理器將應用程序打包并
    發表于 03-06 08:23

    添越智創基于 RK3588 開發板部署測試 DeepSeek 模型全攻略

    的 AI 處理效率,成為部署各類 AI 模型的關鍵依托。 憑借這些卓越的硬件性能,RK3588 開發板在保持低功耗的同時,展現出強大的運算能力,無疑是部署 DeepSeek 模型的不二
    發表于 02-14 17:42

    研華邊緣AI Box MIC-ATL3S部署Deepseek R1模型

    隨著深度求索(DeepSeek)大模型的發布引發行業熱議,研華科技基于昇騰Atlas平臺邊緣AI Box MIC-ATL3S正式發布與Deepseek R1模型部署流程。該平臺依托昇
    的頭像 發表于 02-14 16:08 ?951次閱讀
    研華邊緣AI Box MIC-ATL<b class='flag-5'>3</b>S<b class='flag-5'>部署</b>Deepseek R1<b class='flag-5'>模型</b>

    摩爾線程宣布成功部署DeepSeek蒸餾模型推理服務

    。 據悉,DeepSeek開源模型在多語言理解與復雜推理任務中一直表現出卓越的性能,其V3、R1等系列模型更是備受業界關注。而此次摩爾線程所實現的DeepSeek蒸餾
    的頭像 發表于 02-06 13:49 ?685次閱讀

    基于 Flexus 云服務器 X 實例體驗大模型部署體驗測評

    也很快。但是大家目前都是在體驗,能不能部署一下試試呢? 今天,我們就以華為云 Flexus 云服務器 X 實例來部署一下,順便測測其性能看看。 在華為云 828 B2B 企業節狂潮中,Flexus
    的頭像 發表于 12-24 12:27 ?490次閱讀
    基于 Flexus 云服務器 <b class='flag-5'>X</b> 實例體驗大<b class='flag-5'>模型</b><b class='flag-5'>部署</b>體驗測評

    企業AI模型部署攻略

    當下,越來越多的企業開始探索和實施AI模型,以提升業務效率和競爭力。然而,AI模型部署并非易事,需要企業在多個層面進行細致的規劃和準備。下面,AI部落小編為企業提供一份AI模型
    的頭像 發表于 12-23 10:31 ?508次閱讀

    AI模型部署邊緣設備的奇妙之旅:目標檢測模型

    并非易事,它涉及到從選擇合適的算法架構到針對特定硬件平臺進行優化等一系列復雜的工作。 接下來,我們將詳細介紹如何在資源受限的邊緣設備上成功部署目標檢測模型,探索其背后的原理和技術,并討論解決該領域內常見
    發表于 12-19 14:33

    如何開啟Stable Diffusion WebUI模型推理部署

    如何開啟Stable Diffusion WebUI模型推理部署
    的頭像 發表于 12-11 20:13 ?425次閱讀
    如何開啟Stable Diffusion WebUI<b class='flag-5'>模型</b>推理<b class='flag-5'>部署</b>

    用Ollama輕松搞定Llama 3.2 Vision模型本地部署

    Ollama 是一個開源的大語言模型服務工具,它的核心目的是簡化大語言模型(LLMs)的本地部署和運行過程,請參考《Gemma 2+Ollama在算力魔方上幫你在LeetCode解題》,一條命令完成
    的頭像 發表于 11-23 17:22 ?3412次閱讀
    用Ollama<b class='flag-5'>輕松</b>搞定Llama 3.2 Vision<b class='flag-5'>模型</b>本地<b class='flag-5'>部署</b>

    企業AI模型部署怎么做

    AI模型部署作為這一轉型過程中的關鍵環節,其成功實施對于企業的長遠發展至關重要。在此,AI部落小編為您介紹企業AI模型部署的步驟以及注意事項。
    的頭像 發表于 11-04 10:15 ?495次閱讀