Intel NCStick用TinyYOLOのソース読んでみた(その1)
Intel NCStick用TinyYOLOの解説記事を見かけた。
ソースを読んでみたが、
結構難解で(特にnumpy回り)、自分の鶏頭でも思い出せるように調べた結果をメモしてみた。
NCStick持ってないから実際に動かしてないけど。。。
リポジトリは https://github.com/movidius/ncappzoo だが、このソースはmasterブランチには存在しない。必ずncsdk2ブランチを選択すること。
git clone
する場合は要注意。
どっか行っちゃうといけないので、ソースのコピーをここにも置いておく。
特に難しいことはしてない。mvncがNCStickのドライバ。
from mvnc import mvncapi as mvnc
import sys
import numpy as np
import cv2
13行目
input_image_file
: ここに書かれたファイルを読み込んで認識する。
tiny_yolo_graph_file
: ニューラルネットのネットリスト(?) ニューロンの接続情報と重みが入っていると思われる。
input_image_file= '../../data/images/nps_chair.png'
tiny_yolo_graph_file= './graph'
17行目
ニューラルネットに入力する画像サイズ。任意のサイズの画像をこのサイズにリサイズしてから入力する。
このサイズはニューラルネット構築の際に決定された値。Graphファイルに紐づいた値と考えられる。
Grid分割数が7×7で、1Grid当たりの画像サイズが64pixelなので、7×64 = 448 でおのずと決まる。
NETWORK_IMAGE_WIDTH = 448
NETWORK_IMAGE_HEIGHT = 448
35行目
別ページ
109行目
別ページ
129行目
別ページ
163行目
別ページ
203行目
別ページ
255行目
def main():
print('Running NCS Caffe TinyYolo example')
258行目
# Set logging level to only log errors
mvnc.global_set_option(mvnc.GlobalOption.RW_LOG_LEVEL, 3)
260行目
なかったらエラー終了。
複数見つかった場合は最初のものをオープンする。
devices = mvnc.enumerate_devices()
if len(devices) == 0:
print('No devices found')
return 1
device = mvnc.Device(devices[0])
device.open()
267行目
14行目で設定したGraphファイルを読み込んで、NCStickドライバに設定する。
#Load graph from disk and allocate graph via API
with open(tiny_yolo_graph_file, mode='rb') as f:
graph_from_disk = f.read()
graph = mvnc.Graph("Tiny Yolo Graph")
fifo_in, fifo_out = graph.allocate_with_fifos(device, graph_from_disk)
276行目
input_image
)display_image
)input_image
)input_image
元データはint
)input_image
)input_image
) input_image = cv2.imread(input_image_file)
display_image = input_image
input_image = cv2.resize(input_image, (NETWORK_IMAGE_WIDTH, NETWORK_IMAGE_HEIGHT), cv2.INTER_LINEAR)
input_image = input_image.astype(np.float32)
input_image = np.divide(input_image, 255.0)
input_image = input_image[:, :, ::-1] # convert to RGB
284行目
NCStickに前処理した画像を入力し、計算結果を得る。
このとき、input_image
の各要素はfloat32型に変換して入力する。(既に変換済みな気もするが…)
ちなみに、input_image
そのものの型は numpy.ndarray
。
ニューラルネットの処理本体の処理は実質この2行だけ。
# Load tensor and get result. This executes the inference on the NCS
graph.queue_inference_with_fifo_elem(fifo_in, fifo_out, input_image.astype(np.float32), None)
output, userobj = fifo_out.read_elem()
288行目
filter_objects
(35行目)で NCStickの出力を整理する。
別ページを参照。
パラメータは
output.astype(np.float32)
: NCStickの出力をfloat32にキャストした配列(1次元)input_image.shape[1]
: 画像幅(448)input_image.shape[0]
: 画像高(448)得られるデータは
filtered_objs
: 整理された認識結果filtered_objs
は 最終認識結果数 × 6 の 2次元配列(list)
データ構成はこんな感じ。
filtered_objs[n][0]
: クラスのラベル(認識結果の名称; 文字列)filtered_objs[n][1]
: X座標(pixel単位)filtered_objs[n][2]
: Y座標(pixel単位)filtered_objs[n][3]
: 幅(pixel単位)filtered_objs[n][4]
: 高さ(pixel単位)filtered_objs[n][5]
: スコア filtered_objs = filter_objects(output.astype(np.float32), input_image.shape[1], input_image.shape[0])
290行目
display_objects_in_gui
(203行目)で 表示用イメージと整理された認識結果を表示。
別ページを参照。
パラメータは
display_image
: 表示用画像
filtered_objs
: 整理された認識結果
print('Displaying image with objects detected in GUI')
print('Click in the GUI window and hit any key to exit')
#display the filtered objects/boxes in a GUI window
display_objects_in_gui(display_image, filtered_objs)
295行目
各クローズ処理。
fifo_in.destroy()
fifo_out.destroy()
graph.destroy()
device.close()
device.destroy()
print('Finished')
お約束の処理
if __name__ == "__main__":
sys.exit(main())