本文將介紹基于 OpenVINO 模型優化器或預處理 API 將數據預處理嵌入 AI 模型的常見技巧,幫助讀者在硬件投入不變的情況下,進一步提升端到端的 AI 推理程序的性能。本文所有范例程序已開源:
https://gitee.com/ppov-nuc/resnet_ov_ppp.git,
并在基于第12 代英特爾酷睿處理器的 AI 開發者套件上完成測試。
以 YOLOv5 模型轉換為例,使用模型優化器命令:
mo --input_model yolov5s.onnx --data_type FP16
向右滑動查看完整代碼
將 yolov5s.onnx 模型轉為 IR 格式模型,并將模型精度從 FP32 轉為 FP16——這是最常見的模型優化器使用方式。基于上述 IR 模型,在編寫 AI 推理程序時,由于圖像數據的數值精度和形狀,跟模型輸入節點要求的數值精度和形狀不一樣,所以還需要將數據在輸入模型前對其進行預處理。
以YOLOv5模型為例,使用YOLOv5代碼倉自帶的zidane.jpg圖像,打印出圖像的數值精度和形狀,以及模型輸入節點的數值精度和形狀,對比如下,如圖1-1所示。
圖1-1 OpenCV 讀入的圖像 vs 模型輸入節點
從上圖可以看出,通過 OpenCV 的 imread() 函數讀取的圖像數據,在數據形狀、數值精度、數值范圍等地方,與模型輸入節點的要求不一樣,如下表所示:
由于存在上述的差異,數據在傳入模型前必須進行預處理,以滿足模型輸入節點的要求。數據預處理可以在推理代碼中編程實現,也可以用模型優化器實現,或者用OpenVINO 預處理 API 實現,本文將依次詳細介紹。
1.1用模型優化器實現數據預處理
1.1.1模型優化器預處理參數
模型優化器可以將顏色通道順序調整、圖像數據歸一化等預處理操作嵌入模型,參考《OpenVINO 模型轉換技術要點解讀》。通過指定參數:
--mean_values:所有輸入數據將減去 mean_values, 即 input - mean_values
--scale_values:所有輸入數據將除以 scales_values,當同時指定 mean_values 和 scale_values 時,模型優化器執行(input - mean_values)÷scales_values
--reverse_input_channels:將輸入通道順序從 RGB 轉換為 BGR(反之亦然)
當上述三個操作同時指定時,預處理順序為:
輸入數據
→→reverse_input_channels→→mean_values→→scale_values→→原始模型
在轉換模型時,假設推理程序使用 OpenCV 庫讀取圖像,則可以在模型優化器中增加 mean_values、scale_values 和 reverse_input_channels 三個參數,把顏色通道順序調整和圖像數據歸一化操作嵌入模型。若推理程序使用非 OpenCV 庫讀取圖像,例如 PIL.Image,則無需添加 --reverse_input_channels 參數。
下面本文將以 ResNet 模型為例,展示使用模型優化器將預處理嵌入模型的完整過程。
1.1.2將 ResNet 模型的預處理嵌入模型
ResNet 不僅是2015年 ILSVRC 大賽冠軍,還是產業實踐中常用的卷積神經網絡模型。PyTorch 已將 ResNet 集成到 torchvision 中,將 PyTorch 格式的 ResNet 模型轉為 ONNX 格式,完整代碼如下:
from torchvision.models import resnet50, ResNet50_Weights import torch # https://pytorch.org/vision/stable/models/generated/torchvision.models.resnet50.html weights = ResNet50_Weights.IMAGENET1K_V2 model = resnet50(weights=weights, progress=False).cpu().eval() # define input and output node dummy_input = torch.randn(1, 3, 224, 224, device="cpu") input_names, output_names = ["images"], ['output'] torch.onnx.export(model, dummy_input, "resnet50.onnx", verbose=True, input_names=input_names, output_names=output_names, opset_version=13 )
向右滑動查看完整代碼
在導出 PyTorch 格式模型為 ONNX 格式時,需要注意的是算子版本(opset_version)最好≥11。
另外,OpenVINO 2022.2支持ONNX 1.8.1,即 opset_version=13, 所以本文將 opset_version 設置為13。
基于 ImageNet 1k 數據集訓練的 ResNet 模型的歸一化參數為:
mean_values= [123.675,116.28,103.53]
scale_values=[58.395,57.12,57.375]
將 ONNX 模型轉換為 OpenVINO IR 模型的命令為:
mo -m resnet50.onnx --mean_values=[123.675,116.28,103.53] -- scale_values=[58.395,57.12,57.375] --data_type FP16 --reverse_input_channels
向右滑動查看完整代碼
當獲得 ResNet50 的 IR 模型后,可以使用下面的程序,完成推理計算
from openvino.runtime import Core import cv2 import numpy as np core = Core() resnet50 = core.compile_model("resnet50.xml", "CPU") output_node = resnet50.outputs[0] # Resize img = cv2.resize(cv2.imread("cat.jpg"), [224,224]) # Layout: HWC -> NCHW blob = np.expand_dims(np.transpose(img, (2,0,1)), 0) result = resnet50(blob)[output_node] print(np.argmax(result))
向右滑動查看完整代碼
在上面的推理代碼中,仍有調整圖像尺寸,改變圖像數據布局等操作在推理代碼中實現,接下來,本文將介紹用 OpenVINO 預處理 API,將更多預處理操作嵌入模型中。
1.2用OpenVINO 預處理 API 實現數據預處理
從 OpenVINO2022.1開始,OpenVINO提供一套預處理 API,將數據預處理嵌入模型,參考《使用 OpenVINO 預處理 API 進一步提升 YOLOv5 推理性能》。將數據預處理嵌入模型的好處是:
提高 AI 模型的移植性(推理代碼無需考慮編寫預處理程序)
提高推理設備(例如,英特爾集成顯卡/獨立顯卡)的利用率
提高 AI 程序端到端的性能
使用 OpenVINO 預處理 API 將預處理嵌入模型的完整范例程序 export_resnet_ov_ppp.py,如下所示:
from openvino.preprocess import PrePostProcessor, ColorFormat, ResizeAlgorithm from openvino.runtime import Core, Layout, Type, serialize # ======== Step 0: read original model ========= core = Core() model = core.read_model("resnet50.onnx") # ======== Step 1: Preprocessing ================ ppp = PrePostProcessor(model) # Declare section of desired application's input format ppp.input("images").tensor() .set_element_type(Type.u8) .set_spatial_dynamic_shape() .set_layout(Layout('NHWC')) .set_color_format(ColorFormat.BGR) # Specify actual model layout ppp.input("images").model().set_layout(Layout('NCHW')) # Explicit preprocessing steps. Layout conversion will be done automatically as last step ppp.input("images").preprocess() .convert_element_type() .convert_color(ColorFormat.RGB) .resize(ResizeAlgorithm.RESIZE_LINEAR) .mean([123.675, 116.28, 103.53]) .scale([58.624, 57.12, 57.375]) # Dump preprocessor print(f'Dump preprocessor: {ppp}') model = ppp.build() # ======== Step 2: Save the model with preprocessor================ serialize(model, 'resnet50_ppp.xml', 'resnet50_ppp.bin')
向右滑動查看完整代碼
export_resnet_ov_ppp.py 運行結果,如下圖所示:
從上面的代碼可見,使用 OpenVINO 預處理 API,可以將圖像尺寸調整、彩色通道轉換、數據歸一化、數據布局轉換全部集成到模型中,并且無需運行模型優化器,即可以將 ONNX 模型導出為 IR 模型。
基于 resnet50_ppp.xml 的完整推理程序,如下所示:
from openvino.runtime import Core import cv2 import numpy as np core = Core() resnet50_ppp = core.compile_model("resnet50_ppp.xml", "CPU") output_node = resnet50_ppp.outputs[0] blob = np.expand_dims(cv2.imread("cat.jpg"),0) result = resnet50_ppp(blob)[output_node] print(np.argmax(result))
向右滑動查看完整代碼
如上所示,基于內嵌預處理的 IR 模型,OpenVINO 推理程序變得更加簡單清晰,易讀易懂了。五行 Python 核心代碼實現了內嵌預處理的 ResNet 模型推理!
1.3使用模型緩存技術進一步縮短首次推理時延
在《在蝰蛇峽谷上實現 YOLOv5 模型的 OpenVINO異步推理程序》討論了 AI 應用程序端到端的性能。對于首次推理時延來說,模型的載入和編譯時間,會極大增加首次推理的端到端的運行時間。
使用模型緩存技術,將極大的縮短首次推理時延,如下圖所示。
使用模型緩存技術,只需要添加一行代碼:
core.set_property({'CACHE_DIR': './cache/ppp'})
完整范例代碼如下所示:
from openvino.runtime import Core import cv2 import numpy as np core = Core() core.set_property({'CACHE_DIR': './cache/ppp'}) # 使用模型緩存技術 resnet50_ppp = core.compile_model("resnet50_ppp.xml", "CPU") output_node = resnet50_ppp.outputs[0] blob = np.expand_dims(cv2.imread("cat.jpg"),0) result = resnet50_ppp(blob)[output_node] print(np.argmax(result))
向右滑動查看完整代碼
當第二次運行推理程序時,OpenVINO 運行時將從緩存文件夾直接加載已編譯好的模型,極大的優化了首次推理時延。
1.4總結
本文詳細介紹了通過模型優化器和 OpenVINO預處理 API,將數據預處理嵌入 AI 模型的技術。將數據預處理嵌入模型,簡化了推理程序編寫,提升推理計算設備利用率并提升了 AI 程序端到端的性能。最后,本文還介紹了通過模型緩存技術,進一步優化 AI 程序端到端的首次推理時延性能。
審核編輯:湯梓紅
-
處理器
+關注
關注
68文章
19395瀏覽量
230672 -
英特爾
+關注
關注
61文章
10002瀏覽量
172115 -
AI
+關注
關注
87文章
31399瀏覽量
269806 -
模型
+關注
關注
1文章
3290瀏覽量
49023
原文標題:將數據預處理嵌入AI模型的常見技巧 | 開發者實戰
文章出處:【微信號:英特爾物聯網,微信公眾號:英特爾物聯網】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論