所用的目標檢測網絡爲GluonCV中的ssd_512_resnet50_v1_voc,在此使用預訓練模型
openvino安裝教程自己百度,我使用的是2019_R3.1版本,mxnet爲1.5.1版本,運行設備爲Intel Movidius Myriad X VPU
有時候在做邊緣計算或者沒有強大的GPU支持時候,mxnet以及pytorch,tf等框架的前向傳播的實時性是達不到要求的,所以可以考慮考慮Intel的openvino。我在使用自己訓練的火情識別的邊緣計算設備時候就需要openvino進行加速。也使用過tensorrt,但是mxnet轉onnx時候失敗了,有的算子mxnet沒有實現,自己也沒精力去研究,乾脆用openvino試試,發現還真挺好使。該文章進行記錄,說不定能幫助大家。
總體步驟:
1.加載SSD的gluon(0.5.0版本,比這個高的版本的ssd結構不一樣,openvino_2019.3.334是不能直接轉的,需要自己寫不支持的層)模型,生成*.params與*.json文件
2.使用openvino提供的工具mo_mxnet.py進行轉換
3.使用openvino進行前向傳播(部署)
STEP1 加載SSD的gluon模型,生成*.params與*.json文件
代碼很簡單,如下(數據輸入我使用比較常見的(1,3,512,512)
,可以自行設置,同時下文需要)
from mxnet import nd
from gluoncv import model_zoo
weight_path = "./hardhat.params"
net = model_zoo.get_model("ssd_512_resnet50_v1_voc", pretrained=True)
net.hybridize()
data_shape = (1, 3, 512, 512)
input_data = nd.random.uniform(-1, 1, data_shape)
_ = net(input_data)
net.export("TestSSD")
運行成功後,會在本地生成以下文件
第一步完成
STEP2 使用openvino提供的工具mo_mxnet.py進行轉換
mo_mxnet.py是openvino提供的工具,位置在<INSTALL_DIR>/deployment_tools/model_optimizer
我使用的mac默認安裝位置是/opt/intel/openvino
然後cd到第一步剛剛生成文件的路徑下
使用命令:
python /opt/intel/openvino/deployment_tools/model_optimizer/mo_mxnet.py --input_model TestSSD-0000.params \
--input_shape [1,3,512,512] –-enable_ssd_gluoncv --data_type FP16
命令解釋:
--input_model
這個不解釋了,就是會讀取剛剛生成的*.params與*.json文件
--input_shape
因爲我們生成的.json文件內是沒有指定網絡輸入的,所以這裏我們要指定網絡輸入數據shape,我使用比較常見的 (1, 3, 512, 512)
此外我用zsh會報錯,後來轉bash成功運行
--enable_ssd_gluoncv
因爲我們使用的gluoncv中的ssd包含了一些layer '_contrib_box_nms'
,openvino不支持,所以openvino使用DetectionOutput layer代替,通過enable_ssd_gluoncv開啓該替換
--data_type
後面的運行代碼需要FP16精度,你的準備轉換的模型可以不需要FP16,mo_mxnet.py會自動幫你轉
第二步完成
STEP3 使用openvino進行前向傳播(部署)
前向傳播所經過的步驟:
- Read the Intermediate Representation
- Prepare inputs and outputs format
- Create Inference Engine Core object
- Compile and Load Network to device
- Set input data
- Execute
- Get the output
大概是這麼多的步驟,我根據以上步驟粗糙的寫了一個腳本,以供大家參考
'''
@Author: your name
@Date: 2020-01-18 13:15:51
@LastEditTime : 2020-01-18 13:33:02
@LastEditors : Please set LastEditors
@Description: In User Settings Edit
@FilePath: /Desktop/ie.py
'''
"""01. Predict with pre-trained SSD models
==========================================
This article shows how to play with pre-trained SSD models with only a few
lines of code.
First let's import some necessary libraries:
"""
from gluoncv import model_zoo, data, utils
from matplotlib import pyplot as plt
from openvino.inference_engine import ie_api as ie
import numpy as np
######################################################################
# Load a pretrained model
# -------------------------
#
# Let's get an SSD model trained with 512x512 images on Pascal VOC
# dataset with ResNet-50 V1 as the base model. By specifying
# ``pretrained=True``, it will automatically download the model from the model
# zoo if necessary. For more pretrained models, please refer to
# :doc:`../../model_zoo/index`.
gluoncv_net = model_zoo.get_model('ssd_512_resnet50_v1_voc', pretrained=True)
core = ie.IECore()
net = ie.IENetwork('ssd-fp32-0000.xml', 'ssd-fp32-0000.bin')
######################################################################
# Pre-process an image
# --------------------
#
# Next we download an image, and pre-process with preset data transforms. Here we
# specify that we resize the short edge of the image to 512 px. But you can
# feed an arbitrarily sized image.
#
# You can provide a list of image file names, such as ``[im_fname1, im_fname2,
# ...]`` to :py:func:`gluoncv.data.transforms.presets.ssd.load_test` if you
# want to load multiple image together.
#
# This function returns two results. The first is a NDArray with shape
# `(batch_size, RGB_channels, height, width)`. It can be fed into the
# model directly. The second one contains the images in numpy format to
# easy to be plotted. Since we only loaded a single image, the first dimension
# of `x` is 1.
im_fname = utils.download('https://github.com/dmlc/web-data/blob/master/' +
'gluoncv/detection/street_small.jpg?raw=true',
path='street_small.jpg')
x, img = data.transforms.presets.ssd.load_test(im_fname, short=512)
print('Shape of pre-processed image:', x.shape)
######################################################################
# Inference and display
# ---------------------
#
# The forward function will return all detected bounding boxes, and the
# corresponding predicted class IDs and confidence scores. Their shapes are
# `(batch_size, num_bboxes, 1)`, `(batch_size, num_bboxes, 1)`, and
# `(batch_size, num_bboxes, 4)`, respectively.
#
# We can use :py:func:`gluoncv.utils.viz.plot_bbox` to visualize the
# results. We slice the results for the first image and feed them into `plot_bbox`:
exec_net = core.load_network(net, device_name="MYRIAD", num_requests=1)
input_names = net.inputs.keys()
input_data = list(x.asnumpy())
assert(len(input_data) == len(input_names))
input = dict(zip(input_names, input_data))
exec_net.requests[0].infer(input)
res = exec_net.requests[0].outputs
box1 = res['1208/DetectionOutput_'] # 這個1208的參數可能需要修改,自行輸出res查看就知道怎麼改了
"""
bbox: box1[0,0,:,3:7]
scores: box1[0,0,:,2]
label: box1[0,0,:,1]
"""
ax = utils.viz.plot_bbox(img, box1[0,0,:,3:7], box1[0,0,:,2],
box1[0,0,:,1], class_names=gluoncv_net.classes)
plt.show()
注:
- 我運行的設備是插着intel的計算棒的電腦,所以我使用
DEVICE = "MYRIAD"
, 你可以用CPU,但貌似要裝其他OPENCL啥子的東西 - 分了一個線程去讀取圖片,沒寫退出程序的邏輯,所以一旦沒再看到 預處理圖片輸出,就可以Ctrl+C退出了
info
的內容如下(數字代表位置): 0->當前結果所對應的圖片索引(多張圖片整合在一個Batch時會需要它,本文中就一張圖片) 1->label的索引 2->置信度 3~6->原圖中的左上右下座標點(xmin, ymin, xmax, ymax)- 要是你的平臺不是普通的x86,mxnet和gluoncv這倆庫可能安裝不了,是需要自行從源碼編譯安裝mxnet和gluoncv的 或者自己根據gluoncv的預處理函數
data.transforms.presets.ssd.load_test
以及畫框的函數utils.viz.plot_bbox
自己寫一個 - 這個可能要管理員權限運行(我遇到了NC_ERROR),
sudo su
->python3 test.py
或者寫一個sh腳本,然後在普通用戶下用sudo運行它,比如下面這個
#!/bin/bash
source /home/rainweic/intel/openvino/bin/setupvars.sh # 改你openvino安裝的路徑
python3 test.py #運行你的代碼