RaspberryPi
TensorFlow
Movidius

Movidius NCS + Raspberrypi で自作DNNモデルを動かす

概要

エッジでAIが流行っている昨今、ラズパイでdeeplearningというフレーズに踊らされ、tensorflowもcaffeも触ったことないのに勢いで買ってしまったMovidius NCSで、ようやく自作モデルを動かせたのでまとめておきます。

Movidius™ Neural Compute Stickとは

  • https://developer.movidius.com/
    • DNNの推論をやってくれるUSB型VPU
    • TensorFlow、Caffeのモデルを動かせる
    • Raspberrypiでも動く
    • 1万円くらい

使い方

ざっくりとこんな感じで動かします。

  • PC
    1. tensorflowでモデル作成
    2. SDKでモデルをNCS用にコンパイル
  • ラズパイ(+NCS)
    1. 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なのは当たり前だろと思って、別の要因を探していたのですが、改めて難解なサンプルをよくよく見てみると

inception_v1.py
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 推論用モデルを作成

推論用のモデルを保存します。

create_pred_model.py
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 を参考にこんな感じで作成。

prediction.py
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枚の画像です。
Figure_1.png

$ python prediction.py
7
1
9
5

うまく動いているみたいです。
NCSの性能については追々評価したいと思います。

まとめ

  • raspi+NCS+webcamの格安画像認識システム、ありかも
  • tensorflow、意外と楽しい