この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
1 はじめに
CX事業本部の平内(SIN)です。
OpenVINO ツールキットでは、モデルをIRと呼ばれる中間表現フォーマットにして利用します。そして、同ツールキットには、各種のフレームワークで作成したモデルを、IRに変換するツールが含まれています。
以前、Amazon SageMaker(以下、SageMaker)の組み込みアルゴリズム(画像分類)で作成したモデルを変換して使用してみました。
今回、同じ要領で、組み込みアルゴリズム(物体検出)で作成したモデルを同じ要領で変換しようとした際に、下記のエラーとなってしまいました。
[ ERROR ] Exception occurred during running replacer "REPLACEMENT_ID" \
(<class 'extensions.load.mxnet.loader.MxNetLoader'>): \
Unexpected exception happened during extracting attributes for node multibox_target.
Original exception message: Operation '_contrib_MultiBoxTarget'\
not supported. Please register it as custom op.
以前作業した時より、OpenVINOのバージョンも上がり、最新では、少しパスも変わっていたので、改めて手順をまとめました。
% ls -la /opt/intel | grep openvino
lrwxr-xr-x 1 root wheel 19 5 12 02:35 openvino_2021 -> openvino_2021.3.394
drwxrwxr-x 11 root wheel 352 5 12 02:35 openvino_2021.3.394
2 モデル
変換に使用したモデルは、下記で作成したものです。
出力先に格納されている、model.tar.gzを解凍すると、3つのファイルが格納されています。
こちらは、一見、MXNet形式のモデルですが、MXNetフレームワークで使用するためには変換が必要です。
下記は、その手順です。
変換すると、以下のようになります。
この形式であれば、OpenVINOのModel Optimizerによる変換が可能です。
3 Model Optimizer
Model Optimizerは、OpenVINOツールキットをインストールする手順の中で展開されるようになっています。 参考:Model Optimizer Developer Guide
変換作業は、Model Optimizerがインストールされてたディレクトリの、mo_mxnet.py(MXNet用)を実行するだけです。
最初に、modelの中に、MXNetのモデルを置き、FP16用とFP32用を作成するためディレクトリを作成しておきます。
% tree . -L 2
.
├── FP16
├── FP32
└── model
├── deploy_model_algo_1-0000.params
└── deploy_model_algo_1-symbol.json
以下は、FP32で作成している例です。
最初に、INTEL_OPENVINO_DIRという環境変数に、最新のOpenVINOのパスを設定しています。
% export INTEL_OPENVINO_DIR=/opt/intel/openvino_2021
% echo $INTEL_OPENVINO_DIR
/opt/intel/openvino_2021
% $INTEL_OPENVINO_DIR/deployment_tools/model_optimizer/mo.py --input_model model/deploy_model_algo_1-0000.params --input_shape "[1,3,512,512]" --data_type FP32 --output_dir FP32
% tree . -L 2
.
├── FP16
├── FP32
│ ├── deploy_model_algo_1-0000.bin
│ ├── deploy_model_algo_1-0000.mapping
│ └── deploy_model_algo_1-0000.xml
└── model
├── deploy_model_algo_1-0000.params
└── deploy_model_algo_1-symbol.json
出力先に、.xmlと .bin が作成されていますが、これが、IRフォーマットのモデルです。
4 コード
以下は、生成したOpenVINOを使用して、MacBook Pro (2.3 GHz クアッドコアIntel Core i7) 上で推論しているコードです。
推論時間は、0.5sec程度となっていました。
processing_time 0.50sec
processing_time 0.48sec
processing_time 0.50sec
processing_time 0.51sec
import numpy as np
import cv2
import time
from openvino.inference_engine import IECore
class Model:
def __init__(self, ie, device, model):
net = ie.read_network(model=model+'.xml', weights=model+'.bin')
self.__input_blob_name = list(net.inputs.keys())[0]
self.__output_blob_name = list(net.outputs.keys())[0]
self.__exec_net = ie.load_network(network=net, device_name=device, num_requests=1)
self.input_size = net.inputs[self.__input_blob_name].shape
def infer(self, data):
prob = self.__exec_net.infer(inputs={self.__input_blob_name: data})
return prob[self.__output_blob_name]
class ProductDetector(Model):
def __init__(self, ie, device, model_path):
super().__init__(ie, device, model_path)
# super().input_sizeから取得可能ですが、分かりやすいようにSHAPE=512で表現しています
self.__SHAPE = 512
# 入力インターフェースへの画像変換
def __prepare_frame(self, frame):
img = cv2.resize(frame, (self.__SHAPE, self.__SHAPE)) # 800*600 -> 512*512
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # BGR -> RGB
img = img.transpose((2, 0, 1)) # 512,512,3 -> 3,512,512
return img[np.newaxis, :] # 3,512,512 -> 1,3,512,512
def infer(self, frame):
height, width = frame.shape[:2]
frame = self.__prepare_frame(frame)
detections = []
result = super().infer(frame)
for obj in result[0][0]:
_, clsid, conf, x1, y1, x2, y2 = obj
x1 = int(x1 * width/self.__SHAPE * self.__SHAPE)
y1 = int(y1 * height/self.__SHAPE * self.__SHAPE)
x2 = int(x2 * width/self.__SHAPE * self.__SHAPE)
y2 = int(y2 * height/self.__SHAPE * self.__SHAPE)
detections.append([int(clsid), conf, x1, y1, x2, y2])
return detections
def main():
CLASSE_NAMES=["ChipStar","Curry","Pringles","SeaFood","Butamen"]
COLORS = [(0,0,175),(0,200,200),(0,175,0),(175,0,0),(0,100,255)]
# OpenVINO
DEVICE = "CPU"
MODEL = "./FP32/deploy_model_algo_1-0000"
ie = IECore()
person_detector = ProductDetector(ie, DEVICE, MODEL)
# OpenCV
WIDTH = 640
HEIGHT = 480
DEVICE_ID = 0
FPS = 24
cap = cv2.VideoCapture(DEVICE_ID)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
cap.set(cv2.CAP_PROP_FPS, FPS)
# フォーマット・解像度・FPSの取得
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = cap.get(cv2.CAP_PROP_FPS)
print("fps:{} width:{} height:{}".format(fps, width, height))
while(True):
_, frame = cap.read()
if(frame is None):
continue
start = time.time() # 時間計測
detections = person_detector.infer(frame)
processing_time = time.time() - start
print("processing_time {:.2f}sec".format(processing_time))
for detection in detections:
clsid, conf, x1, y1, x2, y2 = detection
if(conf < 0.6):
continue
print("{} {:.1f} ({},{})-({},{})".format(CLASSE_NAMES[clsid], conf, x1, y1, x2, y2))
color = COLORS[clsid]
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
text = "{} {:.2f}".format(CLASSE_NAMES[clsid], conf)
cv2.putText(frame, text, (x1, y1), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 1, cv2.LINE_AA)
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
main()
5 最後に
今回は、SageMakerで作成した物体検出モデルをOpenVINOツールキットで利用してみました。MXNetのままで、実行した時は、推論に2.0sec近くかかってしまっていたので、OpenVINOに変換する価値はあったと思います。
モデルの利用方法を検討する場合など、結構時間がかかると思うのですが、SageMakerのエンドポイントだと、課金がかさんでしまうので、ちょっとぐらい遅くても、ローカルデバイスで実行できるのは助かります。
なお、OpenVINOツールキットでは、モデルごとにCPU、GPUを振り分けて使用したり、USBで追加可能なNCSなどがあります。