作者:英特爾物聯(lián)網(wǎng)行業(yè)創(chuàng)新大使 楊雪鋒
OpenVINO 2022.2版開始支持英特爾獨(dú)立顯卡,還能通過“累計(jì)吞吐量”同時(shí)啟動(dòng)集成顯卡 + 獨(dú)立顯卡助力全速 AI 推理。本文基于 C# 和 OpenVINO,將 PP-TinyPose 模型部署在英特爾獨(dú)立顯卡上。
1.1 PP-TinyPose 模型簡(jiǎn)介
PP-TinyPose 是飛槳 PaddleDetecion 針對(duì)移動(dòng)端設(shè)備優(yōu)化的實(shí)時(shí)關(guān)鍵點(diǎn)檢測(cè)模型,可流暢地在移動(dòng)端設(shè)備上執(zhí)行多人姿態(tài)估計(jì)任務(wù)。PP-TinyPose 可以基于人體17個(gè)關(guān)鍵點(diǎn)數(shù)據(jù)集訓(xùn)練后,識(shí)別人體關(guān)鍵點(diǎn),獲得人體姿態(tài),如圖 1所示。
圖 1 PP-TinyPose識(shí)別效果圖
PP-TinyPose 開源項(xiàng)目倉庫:
https://gitee.com/paddlepaddle/PaddleDetection/tree/release/2.5/configs/keypoint/tiny_pose
1.1.1
PP-TinyPose 框架
PP-TinyPose 提供了完整的人體關(guān)鍵點(diǎn)識(shí)別解決方案,主要包括行人檢測(cè)以及關(guān)鍵點(diǎn)檢測(cè)兩部分。行人檢測(cè)通過PP-PicoDet模型來實(shí)現(xiàn),關(guān)鍵點(diǎn)識(shí)別通過 Lite-HRNet 骨干網(wǎng)絡(luò)+DARK關(guān)鍵點(diǎn)矯正算法來實(shí)現(xiàn),如下圖所示:
圖 2 PP-TinyPose人體關(guān)鍵點(diǎn)識(shí)別
1.2 構(gòu)建開發(fā)環(huán)境
本文構(gòu)建的開發(fā)環(huán)境,如下所示:
OpenVINOTM:2022.2.0
OpenCV:4.5.5
Visual Studio:2022
C#框架:.NET 6.0
OpenCvSharp:OpenCvSharp4
1.2.1
下載項(xiàng)目完整源代碼
項(xiàng)目所使用的源碼已在完整開源,讀者可以直接克隆到本地。
git clone https://gitee.com/guojin-yan/Csharp_and_OpenVINO_deploy_PP-TinyPose.git
1.3 在 C# 中調(diào)用 OpenVINO Runtime API
由于 OpenVINO Runtime 只有 C++ 和 Python API 接口,需要在 C# 中通過動(dòng)態(tài)鏈接庫方式調(diào)用 OpenVINO Runtime C++ API。具體教程參考《在C#中調(diào)用OpenVINO 模型》,對(duì)應(yīng)的參考范例:
https://github.com/guojin-yan/OpenVinoSharp.git
1.3.1
在 C# 中構(gòu)建 Core 類
為了更方便的使用,可以在 C# 中,將調(diào)用細(xì)節(jié)封裝到 Core 類中。根據(jù)模型推理的步驟,構(gòu)建模型推理類:
(1)構(gòu)造函數(shù)
public Core(string model_file, string device_name){ // 初始化推理核心 ptr = NativeMethods.core_init(model_file, device_name); }
向右滑動(dòng)查看完整代碼
在該方法中,主要是調(diào)用推理核心初始化方法,初始化推理核心,讀取本地模型,將模型加載到設(shè)備、創(chuàng)建推理請(qǐng)求等模型推理步驟。
(2)設(shè)置模型輸入形狀
// @brief 設(shè)置推理模型的輸入節(jié)點(diǎn)的大小 // @param input_node_name 輸入節(jié)點(diǎn)名 // @param input_size 輸入形狀大小數(shù)組 public void set_input_sharp(string input_node_name, ulong[] input_size) { // 獲取輸入數(shù)組長(zhǎng)度 int length = input_size.Length; if (length == 4) { // 長(zhǎng)度為4,判斷為設(shè)置圖片輸入的輸入參數(shù),調(diào)用設(shè)置圖片形狀方法 ptr = NativeMethods.set_input_image_sharp(ptr, input_node_name, ref input_size[0]); } else if (length == 2) { // 長(zhǎng)度為2,判斷為設(shè)置普通數(shù)據(jù)輸入的輸入?yún)?shù),調(diào)用設(shè)置普通數(shù)據(jù)形狀方法 ptr = NativeMethods.set_input_data_sharp(ptr, input_node_name, ref input_size[0]); } else { // 為防止輸入發(fā)生異常,直接返回 return; } }
向右滑動(dòng)查看完整代碼
(3)加載推理數(shù)據(jù)
// @brief 加載推理數(shù)據(jù) // @param input_node_name 輸入節(jié)點(diǎn)名 // @param input_data 輸入數(shù)據(jù)數(shù)組 public void load_input_data(string input_node_name, float[] input_data) { ptr = NativeMethods.load_input_data(ptr, input_node_name, ref input_data[0]); } // @brief 加載圖片推理數(shù)據(jù) // @param input_node_name 輸入節(jié)點(diǎn)名 // @param image_data 圖片矩陣 // @param image_size 圖片矩陣長(zhǎng)度 public void load_input_data(string input_node_name, byte[] image_data, ulong image_size, int type) { ptr = NativeMethods.load_image_input_data(ptr, input_node_name, ref image_data[0], image_size, type); }
向右滑動(dòng)查看完整代碼
加載推理數(shù)據(jù)主要包含圖片數(shù)據(jù)和普通的矩陣數(shù)據(jù),其中對(duì)于圖片的預(yù)處理,也已經(jīng)在 C++ 中進(jìn)行封裝,保證了圖片數(shù)據(jù)在傳輸中的穩(wěn)定性。
(4)模型推理
// @brief 模型推理 public void infer() { ptr = NativeMethods.core_infer(ptr); }
(5)讀取推理結(jié)果數(shù)據(jù)
// @brief 讀取推理結(jié)果數(shù)據(jù) // @param output_node_name 輸出節(jié)點(diǎn)名 // @param data_size 輸出數(shù)據(jù)長(zhǎng)度 // @return 推理結(jié)果數(shù)組 public T[] read_infer_result(string output_node_name, int data_size) { // 獲取設(shè)定類型 string t = typeof(T).ToString(); // 新建返回值數(shù)組 T[] result = new T[data_size]; if (t == "System.Int32") { // 讀取數(shù)據(jù)類型為整形數(shù)據(jù) int[] inference_result = new int[data_size]; NativeMethods.read_infer_result_I32(ptr, output_node_name, data_size, ref inference_result[0]); result = (T[])Convert.ChangeType(inference_result, typeof(T[])); return result; } else { // 讀取數(shù)據(jù)類型為浮點(diǎn)型數(shù)據(jù) float[] inference_result = new float[data_size]; NativeMethods.read_infer_result_F32(ptr, output_node_name, data_size, ref inference_result[0]); result = (T[])Convert.ChangeType(inference_result, typeof(T[])); return result; } }
在讀取模型推理結(jié)果時(shí),支持讀取整形數(shù)據(jù)和浮點(diǎn)型數(shù)據(jù)。
(6)清除地址
// @brief 刪除創(chuàng)建的地址 public void delet() { NativeMethods.core_delet(ptr); }
完成上述封裝后,在 C# 平臺(tái)下,調(diào)用 Core 類,就可以方便實(shí)現(xiàn) OpenVINO 推理程序了。
1.4 下載并轉(zhuǎn)換 PP-PicoDet 模型
1.4.1
PP-PicoDet 模型簡(jiǎn)介
Picodet_s_320_lcnet_pedestrian Paddle 格式模型信息如下表所示,其默認(rèn)的輸入為動(dòng)態(tài)形狀,需要將該模型的輸入形狀變?yōu)殪o態(tài)形狀。
表 1 Picodet_s_320_lcnet_pedestrian Paddle 格式模型信息
1.4.2
模型下載與轉(zhuǎn)換
第一步,下載模型
命令行直接輸入以下模型導(dǎo)出代碼,使用 PaddleDetecion 自帶的方法,下載預(yù)訓(xùn)練模型并將模型轉(zhuǎn)為導(dǎo)出格式。
導(dǎo)出 picodet_s_320_lcnet_pedestrian 模型:
python tools/export_model.py -c configs/picodet/application/pedestrian_detection/picodet_s_320_lcnet_pedestrian.yml -o export.benchmark=False export.nms=False weights=https://bj.bcebos.com/v1/paddledet/models/keypoint/tinypose_enhance/picodet_s_320_lcnet_pedestrian.p dparams --output_dir=output_inference
導(dǎo)出 picodet_s_192_lcnet_pedestrian 模型:
python tools/export_model.py -c configs/picodet/application/pedestrian_detection/picodet_s_192_lcnet_pedestrian.yml -o export.benchmark=False export.nms=False weights=https://bj.bcebos.com/v1/paddledet/models/keypoint/tinypose_enhance/picodet_s_192_lcnet_pedestrian.p dparams --output_dir=output_inference
此處導(dǎo)出模型的命令與我們常用的命令導(dǎo)出增加了兩個(gè)指令:
export.benchmark=False 和 export.nms=False
主要是關(guān)閉模型后處理以及打開模型極大值抑制。如果不關(guān)閉模型后處理,模型會(huì)增加一個(gè)輸入,且在模型部署時(shí)會(huì)出錯(cuò)。
第二步,將模型轉(zhuǎn)換為ONNX格式
該方式需要安裝 paddle2onnx 和 onnxruntime 模塊。導(dǎo)出方式比較簡(jiǎn)單,比較注意的是需要指定模型的輸入形狀,用于固定模型批次的大小。在命令行中輸入以下指令進(jìn)行轉(zhuǎn)換:
paddle2onnx --model_dir output_inference/picodet_s_320_lcnet_pedestrian --model_filename model.pdmodel -- params_filename model.pdiparams --input_shape_dict "{'image':[1,3,320,320]}" --opset_version 11 --save_filepicodet_s_320_lcnet_pedestrian.onnx
第三步,轉(zhuǎn)換為IR格式
利用 OpenVINO 模型優(yōu)化器,可以實(shí)現(xiàn)將 ONNX 模型轉(zhuǎn)為 IR 格式
mo --input_model picodet_s_320_lcnet_pedestrian.onnx --input_shape [1,3,256,192] --data_type FP16
1.5 下載并轉(zhuǎn)換 PP-TinyPose 模型
1.5.1
PP-TinyPose 模型簡(jiǎn)介
PP-TinyPose 模型信息如下表所示,其默認(rèn)的輸入為動(dòng)態(tài)形狀,需要將該模型的輸入形狀變?yōu)殪o態(tài)形狀。
表 2 PP-TinyPose 256×192 Paddle 模型信息
1.5.2
模型下載與轉(zhuǎn)換
第一步,下載模型
命令行直接輸入以下代碼,或者瀏覽器輸入后面的網(wǎng)址即可。
wget https://bj.bcebos.com/v1/paddledet/models/keypoint/tinypose_enhance/tinypose_256x192.zip
下載好后將其解壓到文件夾中,便可以獲得 Paddle 格式的推理模型。
第二步,轉(zhuǎn)換為 ONNX 格式
該方式需要安裝 paddle2onnx 和 onnxruntime 模塊。在命令行中輸入以下指令進(jìn)行轉(zhuǎn)換,其中轉(zhuǎn)換時(shí)需要指定 input_shape,否者推理時(shí)間會(huì)很長(zhǎng):
paddle2onnx --model_dir output_inference/tinypose_256_192/paddle --model_filename model.pdmodel -- params_filename model.pdiparams --input_shape_dict "{'image':[1,3,256,192]}" --opset_version 11 --save_file tinypose_256_192.onnx
第三步,轉(zhuǎn)換為 IR 格式
利用OpenVINO 模型優(yōu)化器,可以實(shí)現(xiàn)將 ONNX 模型轉(zhuǎn)為 IR 格式。
cd .openvino ools mo --input_model paddle/model.pdmodel --input_shape [1,3,256,192] --data_type FP16
1.6 編寫 OpenVINO 推理程序
1.6.1
實(shí)現(xiàn)行人檢測(cè)
第一步,初始化 PicoDet 行人識(shí)別類
// 行人檢測(cè)模型 string mode_path_det = @"E:Text_ModelTinyPosepicodet_v2_s_320_pedestrianpicodet_s_320_lcnet_pedestrian.onnx"; // 設(shè)備名稱 string device_name = "CPU"; PicoDet pico_det = new PicoDet(mode_path_det, device_name);
首先初始化行人識(shí)別類,將本地模型讀取到內(nèi)存中,并將模型加載到指定設(shè)備中。
第二步,設(shè)置輸入輸出形狀
Size size_det = new Size(320, 320); pico_det.set_shape(size_det, 2125);
根據(jù)我們使用的模型,設(shè)置模型的輸入輸出形狀。
第三步,實(shí)現(xiàn)行人檢測(cè)
// 測(cè)試圖片 string image_path = @"E:Git_space基于Csharp和OpenVINO部署PP-TinyPoseimagedemo_3.jpg"; Mat image = Cv2.ImRead(image_path); List result_rect = pico_det.predict(image);
在進(jìn)行模型推理時(shí),使用 OpenCvSharp 讀取圖像,然后帶入預(yù)測(cè),最終獲取行人預(yù)測(cè)框。最后將行人預(yù)測(cè)框繪制到圖片上,如下圖所示。
圖 3 行人位置預(yù)測(cè)結(jié)果
1.6.2
實(shí)現(xiàn)人體姿態(tài)識(shí)別
第一步,初始化 P 人體姿勢(shì)識(shí)別 PPTinyPose 類
// 關(guān)鍵點(diǎn)檢測(cè)模型 // onnx格式 string mode_path_pose = @"E:Text_ModelTinyPose inypose_128_96 inypose_128_96.onnx"; // 設(shè)備名稱 string device_name = "CPU"; PPTinyPose tiny_pose = new PPTinyPose(mode_path_pose, device_name);
首先初始化人體姿勢(shì)識(shí)別 PPTinyPose 類,將本地模型讀取到內(nèi)存中,并加載到設(shè)備上。
第二步,設(shè)置輸入輸出形狀
Size size_pose = new Size(128, 96); tiny_pose.set_shape(size_pose);
PP-TinyPose 模型輸入與輸出有對(duì)應(yīng)關(guān)系,因此只需要設(shè)置輸入尺寸
第三步,實(shí)現(xiàn)姿勢(shì)預(yù)測(cè)
// 測(cè)試圖片 string image_path = @"E:Git_space基于Csharp和OpenVINO部署PP-TinyPoseimagedemo_3.jpg"; Mat image = Cv2.ImRead(image_path); Mat result_image = tiny_pose.predict(image);
在進(jìn)行模型推理時(shí),使用 OpenCvSharp 讀取圖像,然后帶入預(yù)測(cè),最終獲取人體姿勢(shì)結(jié)果,如下圖所示。
圖 4 人體姿態(tài)繪制效果圖
1.6.3
推理速度測(cè)試
本項(xiàng)目在蝰蛇峽谷上完成測(cè)試,CPU 為 i7-12700H,自帶英特爾 銳炬 Xe集成顯卡;獨(dú)立顯卡為英特爾銳炫 A770M 獨(dú)立顯卡 + 16G 顯存,如下圖所示。
圖 5 蝰蛇峽谷
測(cè)試代碼已開源:
https://gitee.com/guojin-yan/Csharp_and_OpenVINO_deploy_PP-TinyPose.git
測(cè)試結(jié)果如下表所示
表 3 PP-PicoDet 與 PP-TinyPose 模型運(yùn)行時(shí)間(ms)
注:模型讀取:讀取本地模型,加載到設(shè)備,創(chuàng)建推理通道;
加載數(shù)據(jù):將待推理數(shù)據(jù)進(jìn)行處理并加載到模型輸入節(jié)點(diǎn);
模型推理:模型執(zhí)行推理運(yùn)算;
結(jié)果處理:在模型輸出節(jié)點(diǎn)讀取輸出數(shù)據(jù),并轉(zhuǎn)化為我們所需要的結(jié)果數(shù)據(jù)。
1.7 總結(jié)與未來工作展望
本文完整介紹了在 C# 中基于 OpenVINO 部署 PP-TinyPose 模型的完整流程,并開源了完整的項(xiàng)目代碼。
從表3的測(cè)試結(jié)果可以看到,面對(duì)級(jí)聯(lián)的小模型,由于存在數(shù)據(jù)從 CPU 傳到 GPU,GPU 處理完畢后,結(jié)果從 GPU 傳回 CPU 的時(shí)間消耗,獨(dú)立顯卡相對(duì) CPU 并不具備明顯優(yōu)勢(shì)。
未來
改進(jìn)方向
借助 OpenVINO 預(yù)處理 API,將預(yù)處理和后處理集成到 GPU 中去。
參考教程:使用OpenVINO 預(yù)處理API進(jìn)一步提升YOLOv5推理性能
借助OpenVINO 異步推理 API,提升 GPU 利用率。
參考教程:蝰蛇峽谷上實(shí)現(xiàn) YOLOv5 模型的 OpenVINO 異步推理程序
仔細(xì)分析 CPU 和 GPU 之間的數(shù)據(jù)傳輸性能瓶頸,嘗試鎖頁內(nèi)存、異步傳輸?shù)葍?yōu)化技術(shù),“隱藏” CPU 和 GPU 之間的數(shù)據(jù)傳輸時(shí)間消耗。
-
英特爾
+關(guān)注
關(guān)注
61文章
9964瀏覽量
171773 -
cpu
+關(guān)注
關(guān)注
68文章
10863瀏覽量
211763 -
gpu
+關(guān)注
關(guān)注
28文章
4740瀏覽量
128948 -
物聯(lián)網(wǎng)
+關(guān)注
關(guān)注
2909文章
44635瀏覽量
373365 -
顯卡
+關(guān)注
關(guān)注
16文章
2434瀏覽量
67611
原文標(biāo)題:基于C#和OpenVINO?在英特爾獨(dú)立顯卡上部署PP-TinyPose模型 | 開發(fā)者實(shí)戰(zhàn)
文章出處:【微信號(hào):英特爾物聯(lián)網(wǎng),微信公眾號(hào):英特爾物聯(lián)網(wǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論