摘要:“高性能推理”是ModelBox宣傳的主要特性之一,不信謠不傳謠的我決定通過原生API和ModelBox實作相同案例進行對比,看一下ModelBox推理是否真的“高性能”。
本文分享自華為雲社群《ModelBox推理真的高效嗎?》,作者:吳小魚。
“高性能推理”是ModelBox宣傳的主要特性之一,不信謠不傳謠的我決定通過原生API和ModelBox實作相同案例進行對比,看一下ModelBox推理是否真的“高性能”。
我們分别使用onnxruntime與ModelBox Windows SDK對相同的模型實作相同的推理邏輯進行端到端性能對比,為了防止測試視訊幀率成為性能瓶頸,我們準備了120fps的視訊作為測試輸入。
如果對Windows ModelBox SDK使用還不熟悉,可以參考我們的ModelBox 端雲協同AI開發套件(Windows)上手指南。案例所需資源(代碼、模型、測試資料等)均可從obs桶下載下傳。
案例說明
為了充分考驗不同架構的推理性能,我決定做一個稍微有那麼一點點繁瑣的雙階段單人人體關鍵點檢測案例。案例具體流程如下:
其中,人形檢測使用開源YOLOV7-tiny預訓練模型,關鍵點檢測使用開源PP-TinyPose預訓練模型,在進行人形跟蹤後我們過濾得到最早出現的id的檢測框進行關鍵點檢測。
onnxruntime推理
原生API推理代碼位于資源包的onnxruntime_infer目錄下,具體的代碼組織為:
onnxruntime_infer
├─onnxruntime_infer.py # 推理入口腳本
├─utils.py # 人形檢測後處理
├─sort.py # 跟蹤
├─hrnet_post.py # 關鍵點檢測後處理
└─smooth.py # 關鍵點時序濾波
其中,入口腳本onnxruntime_infer.py中指定了使用的模型檔案與測試視訊:
cam = cv2.VideoCapture("../data/dance_120fps.mp4")
size = (int(cam.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cam.get(cv2.CAP_PROP_FRAME_HEIGHT)))
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
out_fps = cam.get(cv2.CAP_PROP_FPS)
res_cam = cv2.VideoWriter("../hilens_data_dir/rt_result.mp4", fourcc, out_fps, size)
det_sess = rt.InferenceSession("../model/det_human/yolov7-tiny.onnx", providers=["DmlExecutionProvider"])
pose_sess = rt.InferenceSession("../model/det_pose/pose.onnx", providers=["CPUExecutionProvider"])
人形檢測模型為gpu推理,關鍵點檢測模型為cpu推理,在使用ModelBox Windows SDK推理時也保持了同樣的硬體配置。
fps取檢測預處理開始到繪制關鍵點這一區間進行測試:
class DetPre:
def __init__(self, net_h=320, net_w=320):
self.net_h = net_h
self.net_w = net_w
def __call__(self, img_data):
buffer_meta = {}
buffer_meta["time"] = time.time()
resized_image, ratio, (dw, dh) = self.letterbox(img_data)
...
total_time += time.time() - buffer_meta.get("time")
idx += 1
res_img, pose_data = draw_pose(im, filter_box, pose_data, total_time / idx)
...
結果視訊rt_result.mp4儲存在hilens_data_dir檔案夾下,檢視結果:
可以看到,雙階段單人關鍵點技能在onnxruntime推理可以達到36fps左右。
ModelBox Windows SDK推理
ModelBox Windows SDK推理代碼位于資源包的single_human_pose目錄下,具體的代碼組織為:
single_human_pose
├─bin
│ ├─main.bat // 啟動腳本
│ └─mock_task.toml // 本地模拟運作輸入輸出配置檔案
├─data
│ └─dance_120fps.mp4 // 測試視訊
├─etc
│ └─flowunit // 功能單元目錄
│ ├─det_post // 檢測後處理
│ ├─det_pre // 檢測預處理
│ ├─draw_pose // 關鍵點繪制
│ ├─expand_box // 單人圖像切分
│ ├─object_tracker // 人形跟蹤
│ └─pose_post // 姿态後處理
├─graph
│ └─single_human_pose.toml // 技能流程圖
├─hilens_data_dir // 運作結果目錄
│ ├─log
│ ├─mb_profile // 性能統計目錄
│ │ ├─performance_[time].toml
│ │ └─trace_[time].toml
│ ├─dance_result.mp4 // 運作結果視訊
│ └─rt_result.mp4
├─model // 推理功能單元
│ ├─det_human // 人形檢測推理
│ │ ├─det_human.toml // 推理配置檔案
│ │ └─yolov7-tiny.onnx // 推理模型
│ └─det_pose // 關鍵點檢測推理
│ ├─det_pose.toml
│ └─pose.onnx
└─build_project.sh
我們可以檢視技能流程圖graph/single_human_pose.toml了解技能邏輯:
fps在關鍵點繪制功能單元中進行計算,計算的為端到端全流程fps:
class draw_poseFlowUnit(modelbox.FlowUnit):
def open(self, config):
...
self.start_time = time.time()
self.idx = 0
...
def process(self, data_context):
...
self.idx += 1
self.draw(out_img, bbox, pose_data, self.idx / (time.time() - self.start_time))
...
在bin/mock_task.toml中配置輸入輸出:
# 任務輸入,mock模拟目前僅支援一路rtsp或者本地url
# rtsp攝像頭,type = "rtsp", url裡面寫入rtsp位址
# 其它用"url",比如可以是本地檔案位址, 或者httpserver的位址,(攝像頭 url = "0")
[input]
type = "url"
url = "../data/dance_120fps.mp4"
# 任務輸出,目前僅支援"webhook", 和本地輸出"local"(輸出到螢幕,url="0", 輸出到rtsp,填寫rtsp位址)
# (local 還可以輸出到本地檔案,這個時候注意,檔案可以是相對路徑,是相對這個mock_task.toml檔案本身)
[output]
type = "local"
url = "../hilens_data_dir/dance_result.mp4"
在技能流程圖中開啟性能統計配置項:
[profile]
profile=true
trace=true
之後輕按兩下bin/main.bat或在bash中運作技能:
./bin/main.bat
運作完成後生成的視訊與性能統計檔案都在hilens_data_dir檔案夾下:
可以看到使用ModelBox SDK進行推理可以達到79fps,名不虛傳哇,我們可以在Chrome浏覽器chrome://tracing/中加載性能統計檔案檢視:
逐項檢視後發現耗時最久的是檢測後處理功能單元,平均耗時11.69ms,因為ModelBox是靜态圖并行推理,fps取決于耗時最久的功能單元,理論計算fps = 1000 / 11.69 \approx 85fps=1000/11.69≈85,與我們在程式中打點計算結果接近。
總結:ModelBox真的很快,nice!
點選關注,第一時間了解華為雲新鮮技術~