[Amazon SageMaker] 組み込みアルゴリズム(ObjectDetection)で作成したモデルをOpencVINOで使用してみました

2021.05.15

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フォーマットのモデルです。


Converting a MXNet* Model

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などがあります。