この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
1 はじめに
CX事業本部の平内(SIN)です。
先日、Amazon SageMaker(以下、SageMaker)のビルトインアルゴリズムであるオブジェクト検出(Object Detection)で作成したモデルを変換して、MacOSにインストールしたMXNet上で利用してみました。
今回は、同じ要領で、RaspberryPiで利用可能かどうかを確認してみました。
結論(感想)から言ってしまうと・・・動作はしますが、推論にちょっと時間がかかるため、リアルタイム的な利用は難しいという感じです。
2 RaspberryPi
Raspberri Piは、Model4で、OSは、今年5月の最新版(Raspberry Pi OS (32-bit) with desktop and recommended software)2020-05-27-raspios-buster-full-armhf.img です
$ cat /proc/cpuinfo | grep Revision
Revision : c03112
$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description: Raspbian GNU/Linux 10 (buster)
Release: 10
Codename: buster
$ uname -a
Linux raspberrypi 4.19.118-v7l+ #1311 SMP Mon Apr 27 14:26:42 BST 2020 armv7l GNU/Linux
3 MXNet
MXNetは、最新の1.6.0が、ちょっとうまく動作させることが出来ず、1つ前の1.5.0を利用しました。
(1) Ver 1.6.0
下記のように、pipを利用すると、最新の1.6.0がインストールされます。
$ pip3 install mxnet
しかし、importの段階で、下記のようなエラーとなってしまいました。
$ python3
>>> import mxnet
OSError: /home/pi/.local/lib/python3.7/site-packages/mxnet/libmxnet.so: wrong ELF class: ELFCLASS64
>>>
今回は、上記エラーの回避を諦めました。
(2) Ver 1.5.0
1.5.0のインストールは、下記に置かれている、mxnet-1.6.0-py2.py3-none-any.whlを利用させて頂きました。
http://mxnet-public.s3.amazonaws.com/
pipでのインストールは、以下のとおりです。
$ pip3 install https://mxnet-public.s3.amazonaws.com/install/raspbian/mxnet-1.5.0-py2.py3-none-any.whl
Successfully built numpy
Installing collected packages: numpy, mxnet
Successfully installed mxnet-1.5.0 numpy-1.15.2
なお、上記のインストールだけでは、ライブラリ不足となっておりましたので、これを追加しました。
OSError: libopenblas.so.0: cannot open shared object file: No such file or directory
$ sudo apt-get install libopenblas-base
バージョン1.5.0が、利用可能になっている様子です。
$ python3
Python 3.7.3 (default, Dec 20 2019, 18:57:59)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> import mxnet
>>> mxnet.__version__
'1.5.0'
>>>
参考:https://github.com/apache/incubator-mxnet/issues/17978
4 利用状況
RaspberryPi上で推論している様子です。時間はかかりますが、一応、動作できています。
下記が、ログの一例です。1回の推論に10秒弱かかっています。
$ python3 index.py
[04:57:56] /work/mxnet/src/nnvm/legacy_json_util.cc:204: Warning: loading symbol saved by MXNet version 10501 with lower version of MXNet v10500. May cause undefined behavior. Please update MXNet if you encounter any issue
fps:24.0 width:800.0 height:600.0
inference start
[PRETZEL]0.8488292694091797 21, 45, 353, 487
inference finish:9.958193302154541[sec]
inference start
[PRIME]0.836922824382782 98, 118, 388, 499
inference finish:9.596295356750488[sec]
inference start
[OREO]0.9958897233009338 57, 155, 449, 502
inference finish:9.709836483001709[sec]
inference start
[CRATZ]0.9407762289047241 21, 88, 322, 468
inference finish:9.705724239349365[sec]
inference start
[ASPARA]0.7363123297691345 57, 134, 368, 511
inference finish:9.655270338058472[sec]
5 コード
使用したPython3のコードは、以下のとおりです。
変換で生成したモデルを、./modelに置き、Webカメラの画像を入力インターフェースに変換して推論にかけています。
import mxnet as mx
import cv2
import time
import numpy as np
from collections import namedtuple
# Webカメラ
DEVICE_ID = 0
WIDTH = 800
HEIGHT = 600
FPS = 24
MODEL_PATH = './model/deploy_model_algo_1'
CLASSES = ['ASPARA','CRATZ','PRETZEL','PRIME','OREO']
COLORS = [(128, 0, 0),(0, 128, 0),(0, 0, 128),(128, 128, 0),(0, 128,128)]
def main():
# Model Initialize
SHAPE = 512
input_shapes=[('data', (1, 3, SHAPE, SHAPE))]
Batch = namedtuple('Batch', ['data'])
sym, arg_params, aux_params = mx.model.load_checkpoint(MODEL_PATH, 0)
mod = mx.mod.Module(symbol=sym, label_names=[], context=mx.cpu())
mod.bind(for_training=False, data_shapes=input_shapes)
mod.set_params(arg_params, aux_params)
# Video Initialize
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)
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
print("inference start")
start = time.time()
# 入力インターフェースへの画像変換
frame = frame[0 : int(height), 0 : int(height)] # 800*600 -> 600*600
frame = cv2.resize(frame, (SHAPE, SHAPE)) # 600*600 -> 512*512
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # BGR -> RGB
img = img.transpose((2, 0, 1)) # 512,512,3 -> 3,512,512
img = img[np.newaxis, :] # 3,512,512 -> 1,3,512,512
# 推論
mod.forward(Batch([mx.nd.array(img)]))
prob = mod.get_outputs()[0].asnumpy()
prob = np.squeeze(prob)
index = int(prob[:, 0][0])
confidence = prob[0][1]
x1 = int(prob[0][2] * SHAPE)
y1 = int(prob[0][3] * SHAPE)
x2 = int(prob[0][4] * SHAPE)
y2 = int(prob[0][5] * SHAPE)
# 表示
print("[{}]{} {}, {}, {}, {}".format(CLASSES[index], confidence, x1, y1, x2, y2))
if(confidence > 0.6): # 信頼度
frame = cv2.rectangle(frame,(x1, y1), (x2, y2), COLORS[index],2)
frame = cv2.rectangle(frame,(x1, y1), (x1 + 150,y1-20), COLORS[index], -1)
label = "{} {:.2f}".format(CLASSES[index], confidence)
frame = cv2.putText(frame,label,(x1+2, y1-2), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 1, cv2.LINE_AA)
elapsed_time = time.time() - start
print ("inference finish:{0}".format(elapsed_time) + "[sec]")
# 画像表示
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 読み飛ばし
for _ in range(int(fps*10)):
_, dmy = cap.read()
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
6 最後に
今回は、RaspberryPiにインストールしたMXNet上で試してみました。
推論に10秒程度必要ということで、リアルタイム(的)な要件には、ちょっと厳しいと思います。しかし、推論にかかるコストは非常に低くなると思うので、要件によっては有りかも知れません。