概要
エッジでAIが流行っている昨今、ラズパイでdeeplearning
というフレーズに踊らされ、tensorflowもcaffeも触ったことないのに勢いで買ってしまったMovidius NCSで、ようやく自作モデルを動かせたのでまとめておきます。
Movidius™ Neural Compute Stickとは
- https://developer.movidius.com/
- DNNの推論をやってくれるUSB型VPU
- TensorFlow、Caffeのモデルを動かせる
- Raspberrypiでも動く
- 1万円くらい
使い方
ざっくりとこんな感じで動かします。
- PC
- tensorflowでモデル作成
- SDKでモデルをNCS用にコンパイル
- ラズパイ(+NCS)
- APIを叩いて、コンパイル済みモデルを読み込み、推論
コード
githubに置いておきます。
https://github.com/watanabeyyy/NCS_test
- train.py
- tensorflowで学習させたスクリプトです。
- MNISTベースで作ってますが、MS Pゴシックの数字を学習させてます。
- create_pred_model.py
- 学習済みモデルを、SDKでコンパイルできるように変換するスクリプトです。
- 学習した重みを読み込み、推論用モデルとして新たに保存します。
- prediction.py
- NCS用にコンパイルされたモデルを読み込み、推論を行うスクリプトです。
導入
環境は
- Ubuntu PC (VirtualBox on Windows)
- Raspberry Pi 3 Model B
PC
###1. SDKをインストール
Ubuntu 16.04にしか入らないみたいです。
$ git clone http://github.com/Movidius/ncsdk
$ cd ncsdk
$ make install
###2. 自作モデルをコンパイル
ここでだいぶ苦戦しました。サンプル動かす以上の情報がなかなか得られず・・・
とりあえず、サンプル通りmvNCCompileコマンドにtensorflowのmetaファイル渡してやって、このエラー
$ mvNCCompile -s 12 model.meta -in=input -on=softmax
.....
[Error 34] Setup Error: Values for input contain placeholder. Pass an absolute value.
tensorflowでinputがplaceholderなのは当たり前だろと思って、別の要因を探していたのですが、改めて難解なサンプルをよくよく見てみると
import numpy as np
import tensorflow as tf
from tensorflow.contrib.slim.nets import inception
slim = tf.contrib.slim
def run(name, image_size, num_classes):
with tf.Graph().as_default():
image = tf.placeholder("float", [1, image_size, image_size, 3], name="input")
with slim.arg_scope(inception.inception_v1_arg_scope()):
logits, _ = inception.inception_v1(image, num_classes, is_training=False, spatial_squeeze=False)
probabilities = tf.nn.softmax(logits)
init_fn = slim.assign_from_checkpoint_fn('inception_v1.ckpt', slim.get_model_variables('InceptionV1'))
with tf.Session() as sess:
init_fn(sess)
saver = tf.train.Saver(tf.global_variables())
saver.save(sess, "output/"+name)
run('inception-v1', 224, 1001)
- inputのtensor.shapeでNoneは使わず定数を指定してる(入力のテンソルサイズは固定)
- 学習済みモデルのckptファイルを読み込んで、推論用のsessを新たにsaveしてる
ていうのが大事そうです。
(確かにhttps://movidius.github.io/ncsdk/TensorFlow.html に、Save Session with Graph and Checkpoint Informationと記述があります)
ということで改めて
2.1 推論用モデルを作成
推論用のモデルを保存します。
import tensorflow as tf
def predict(x):
#
#計算グラフを書く
#
y = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2,name="output")
return y
def run(name):
with tf.Graph().as_default():
input = tf.placeholder("float", [1, 108, 108, 1], name="input")
output = predict(input)
with tf.Session() as sess:
saver = tf.train.Saver(tf.global_variables())
last_model = "./model/cnn-model-99"
saver.restore(sess, last_model)
saver.save(sess, name)
run('./model/pred_model')
入出力にnameを明示しておくのが無難です。
pred_model.meta
としてモデルが保存されます。
2.2 推論用モデルをコンパイル
pred_model.meta
に対してコマンドを叩けば、コンパイルが通りました。
$ mvNCCompile -s 12 pred_model.meta -in=input -on=output
NCS用モデルがgraph
として保存されます。
ラズパイ
1. APIをインストール
Debian 9 Stretchにしか入らないみたいです。
$ git clone http://github.com/Movidius/ncsdk
$ cd ncsdk
$ make install
2. 推論
https://github.com/movidius/ncappzoo/tree/master/apps/image-classifier を参考にこんな感じで作成。
import mvnc.mvncapi as mvnc
import numpy as np
def predict(input):
devices = mvnc.EnumerateDevices()
device = mvnc.Device(devices[0])
device.OpenDevice()
with open('./model/graph', 'rb') as f:
blob = f.read()
graph = device.AllocateGraph(blob)
for i in range(4):
graph.LoadTensor(input[i], 'user object')
output, userobj = graph.GetResult()
print(np.argmax(output))
graph.DeallocateGraph()
device.CloseDevice()
return output
if __name__ == "__main__":
input = np.load("test_data.npy")
predict(input.astype(np.float16))
- LoadTensor()にはfloat16で渡さないとダメっぽいです
3. 動作確認
ラズパイにNCSを挿して、スクリプトを実行してみます。
テストデータとして使ったのは下の4枚の画像です。
$ python prediction.py
7
1
9
5
うまく動いているみたいです。
NCSの性能については追々評価したいと思います。
まとめ
- raspi+NCS+webcamの格安画像認識システム、ありかも
- tensorflow、意外と楽しい