OpenVINO-DeeplabV3
I wrote an English translation, here
#◆ 前回記事
CPU単体で無理やり RealTime Semantic Segmentaion その1 [1 FPS / CPU only]
#◆ はじめに
GithubとForumでフィードバックをガンガン頂けるので助かる。
世間に必要とされているか、必要とされていないか、がよく分かる。
Commitした直後に何者かが既に Star を付けてくれている。。。
なんか、動きを監視されてるみたいでオジサン怖い。。。
さておき、今回も1分読了可能な記事を目指す。
今回はカップラーメン1個で十分。
昨日投稿の実装から、 CPU単体でのセマンティック・セグメンテーション
を4〜5倍高速化した。
今回は、DeeplabV3 + MobilenetV2
のモデルを使用。
DeeplabV3に関しては、 mine820さん が DeepLab v3+(意訳) - mine820 - Qiita に英語論文の日本語訳をまとめてくださっている。
OpenVINOの概要や各種キッティングの手順、性能評価の結果(国外エンジニアとの協力調査) は 前々回記事 に記載しているため、そちらを参照願う。
この記事の実装を行うと、シングルボードコンピュータのCPU単体
で、下図のようなスピードでリアルタイムにセグメンテーションできる。
Intel Neural Compute Stick も GPU のどちらも使用せずに CPU単体 でセグメンテーションする 男気実装(改)
今回は、動画再生とUSBカメラ撮影の2種類を試行した。
十分速い!?
もうね、GPUいらなくね?
すいません、、、いくらなんでも言い過ぎました。
ただ、GPUとか外付けVPUとか小細工しなくても、シングルボードコンピュータ単体で、セマンティック・セグメンテーションが使い物になりそうな雰囲気ではあります。
↓ 画像をクリックすると Youtube で再生できる。
東南アジア系? ちょこまかと動きがせわしないので微妙な感じ。
本人初登場です。 綺麗にセグメントされている。
車、ちゃんと拾えてるね。 バスに対する努力の色が見えるw
#◆ 環境
- LattePanda Alpha (Intel 7th Core m3-7y30)
- Ubuntu 16.04 x86_64
- OpenVINO toolkit 2018 R4 (2018.4.420)
- Python 3.5
- OpenCV 3.4.3
- PIL
- DeeplabV3 + MobliletV2 (Pascal VOC 2012)
#◆ 実装
従前のとおり、推論デバイスは CPU
GPU
NCS1/NCS2
から選択可能。
Github - OpenVINO-DeeplabV3 - PINTO0309 で、OpenVINO本体以外のリソース一式を調達可能な状態にしておいた。
CPU用カーネル拡張ライブラリを取り込まないと正常に動作しない、が、 ".so"ファイル の取り込み動作そのものはロジック中に実装してあるため、気にする必要は無い。
#!/usr/bin/env python
import sys
import os
from argparse import ArgumentParser
import numpy as np
import cv2
import time
from PIL import Image
import tensorflow as tf
from tensorflow.python.platform import gfile
from openvino.inference_engine import IENetwork, IEPlugin
class _model_preprocess():
def __init__(self):
graph = tf.Graph()
f_handle = gfile.FastGFile("pbmodels/frozen_inference_graph.pb", "rb")
graph_def = tf.GraphDef.FromString(f_handle.read())
with graph.as_default():
tf.import_graph_def(graph_def, name='')
self. sess = tf.Session(graph=graph)
def _pre_process(self, image):
seg_map = self.sess.run("sub_7:0", feed_dict={"ImageTensor:0": [image]})
return seg_map
class _model_postprocess():
def __init__(self):
graph = tf.Graph()
f_handle = gfile.FastGFile("pbmodels/frozen_inference_graph.pb", "rb")
graph_def = tf.GraphDef.FromString(f_handle.read())
with graph.as_default():
new_input = tf.placeholder(tf.int64, shape=(1, 513, 513), name="new_input")
tf.import_graph_def(graph_def, input_map={"ArgMax:0": new_input}, name='')
self.sess = tf.Session(graph=graph)
def _post_process(self, image_ir, image):
seg_map = self.sess.run("SemanticPredictions:0", feed_dict={"ImageTensor:0": [image], "new_input:0": np.int64(image_ir)})
return seg_map
_pre = _model_preprocess()
_post = _model_postprocess()
def build_argparser():
parser = ArgumentParser()
parser.add_argument("-pp", "--plugin_dir", help="Path to a plugin folder", type=str, default=None)
parser.add_argument("-d", "--device", help="Specify the target device to infer on; CPU, GPU, FPGA or MYRIAD is acceptable. Sample will look for a suitable plugin for device specified (CPU by default)", default="CPU", type=str)
parser.add_argument("-nt", "--number_top", help="Number of top results", default=10, type=int)
parser.add_argument("-pc", "--performance", help="Enables per-layer performance report", action='store_true')
return parser
def main_IE_infer():
camera_width = 320
camera_height = 240
m_input_size=513
fps = ""
framepos = 0
frame_count = 0
vidfps = 0
skip_frame = 0
elapsedTime = 0
args = build_argparser().parse_args()
model_xml = "lrmodels/FP32/frozen_inference_graph.xml"
model_bin = os.path.splitext(model_xml)[0] + ".bin"
seg_image = Image.open("data/input/009649.png")
palette = seg_image.getpalette() # Get a color palette
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FPS, 10)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, camera_width)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, camera_height)
#cap = cv2.VideoCapture("data/input/testvideo2.mp4")
#camera_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
#camera_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
#frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
#vidfps = int(cap.get(cv2.CAP_PROP_FPS))
#print("videosFrameCount =", str(frame_count))
#print("videosFPS =", str(vidfps))
time.sleep(1)
plugin = IEPlugin(device=args.device, plugin_dirs=args.plugin_dir)
if "CPU" in args.device:
plugin.add_cpu_extension("lib/libcpu_extension.so")
if args.performance:
plugin.set_config({"PERF_COUNT": "YES"})
# Read IR
net = IENetwork.from_ir(model=model_xml, weights=model_bin)
input_blob = next(iter(net.inputs))
exec_net = plugin.load(network=net)
while cap.isOpened():
t1 = time.time()
#cap.set(cv2.CAP_PROP_POS_FRAMES, framepos) # Uncomment only when playing video files
ret, image = cap.read()
if not ret:
break
ratio = 1.0 * m_input_size / max(image.shape[0], image.shape[1])
shrink_size = (int(ratio * image.shape[1]), int(ratio * image.shape[0]))
image = cv2.resize(image, shrink_size, interpolation=cv2.INTER_CUBIC)
prepimg = _pre._pre_process(image)
prepimg = prepimg.transpose((0, 3, 1, 2)) #NHWC to NCHW
res = exec_net.infer(inputs={input_blob: prepimg})
result = _post._post_process(res["ArgMax/Squeeze"], image)[0]
outputimg = Image.fromarray(np.uint8(result), mode="P")
outputimg.putpalette(palette)
outputimg = outputimg.convert("RGB")
outputimg = np.asarray(outputimg)
outputimg = cv2.cvtColor(outputimg, cv2.COLOR_RGB2BGR)
outputimg = cv2.addWeighted(image, 1.0, outputimg, 0.9, 0)
outputimg = cv2.resize(outputimg, (camera_width, camera_height))
cv2.putText(outputimg, fps, (camera_width-180,15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (38,0,255), 1, cv2.LINE_AA)
cv2.imshow("Result", outputimg)
if cv2.waitKey(1)&0xFF == ord('q'):
break
elapsedTime = time.time() - t1
fps = "(Playback) {:.1f} FPS".format(1/elapsedTime)
# frame skip, video file only
#skip_frame = int((vidfps - int(1/elapsedTime)) / int(1/elapsedTime))
#framepos += skip_frame
cv2.destroyAllWindows()
del net
del exec_net
del plugin
if __name__ == '__main__':
sys.exit(main_IE_infer() or 0)
たったのこれだけ。
本当は、更にコレの5倍の性能が欲しい。
ただ、現時点では Core i7
とか第8世代以降の高火力CPUを使用するのは禁じ手。
パフォーマンスを確保したうえで、消費電力も抑えなければ意味が無い。
あくまで、モバイルやエッジコンピュータなどの非力な環境で、 スタンドアロン かつ 高速 に動かすことが目的なので。
Celeron などの超旧世代を使用する場合は、Neural Compute Stick 2 を使用することによるメリットがあることが、検証により明らかになってきた。
次は、シカゴのBobさんが $80 の Atom機 で検証してくれることになっている。
公式フォーラムでの議論はコチラ
今回は、OpenVINO非対応のレイヤー部をロジック内で明示的に Tensorflow 側へオフロードした。
この手法を使用すれば、セグメンテーションに限らず、既存のほとんどのモデルを高速化できると考える。
まぁ、実装上美しくはないかもしれないけど。
GithubのREADMEは少しずつ厚みを増す予定。
2018.12.03 一応追記。 Core i7 CPU単独
なら 11 - 12 FPS
のパフォーマンスが出る。
https://youtu.be/TjiH2dMltl4