概要
AI流行っていますね。そんな中、IntelがUSBで動くDeep Learningスティック、Movidius Neural Compute Stickの販売を開始しました(以下、Movidius NCS)。このスティックは、Caffeのネットワークモデルの計算だけスティックで高速に実行するというものです。今年度のCVPR2017で先行販売されたので、早速購入してきました。ちなみに余談ですが、僕が先頭に並んでいたので、世界で最も最初にこの製品を手にしたというのが、ちょっとした自慢です。
追記:Movidiusは製品名ではなく開発している会社名で、製品名はNeural Compute Stickなんですね。ただ、NCSだとよくわからないので、Movidius NCSと記載することにします。
本記事では、取り敢えずMovidius NCSをRaspberrypi3で動かすまでの手順について紹介します。本当はRealTimePoseMachineとかで姿勢推定までやりたかったですが、時間が足りなかったので近々実施します。実はこの記事の前に、できればMacで動かしたいという気持ちでVirtualBoxで試したり色々動かなかったという作業を永遠とやっていたので、もし動いたら教えて欲しいです・・・!(未確認ですがVMWareでは動くっぽいという報告があるみたいです。)
Raspberrypi3へのUbuntuインストール
ラズパイで遊ぶといえば、OSは大抵Rasbianですが、Movidius NCSはUbuntuのみ対応ですので、Ubuntuをインストールします。今回はラズパイ3をターゲットにしていますが、仕様的にはZEROや2でも大丈夫に見えます。こちらも時間があったら調査したい気持ちは少しあります。
まずは、OSのインストールの手順。OSをここからダウンロードしてきます。なお、この作業はMac上で行うことを前提としておきます。
$ wget http://www.finnie.org/software/raspberrypi/ubuntu-rpi3/ubuntu-16.04-preinstalled-server-armhf+raspi3.img.xz
まず、OSを入れるmicroSDを用意ます。PCにmicroSDをセットし、
diskutil list
などでディレクトリを確認し、
diskutil umountDisk /dev/disk2
でアンマウントしておきましょう。
次に、先ほどダウンロードしたOSイメージを解凍してmicroSDに焼き込みます。Macの場合は、xzを扱うためにツールをインストールしておきます。
$ brew install xz
$ xzcat ubuntu-16.04-preinstalled-server-armhf+rasPi 3.img.xz | sudo dd of=/dev/disk2
1〜2時間ほど待つと焼き終わると思います。ここでの作業は、これで終了ですのでmicroSDを抜いてラズパイ側にセットしましょう。
Raspberrypi3の準備
大した作業ではないですが、リモートで作業できたほうが良いですので、簡単なセットアップをします。
sudo apt-get update
sudo apt-get install avahi-daemon
以降、別マシンからssh ubuntu@ubuntu.local
でログインできるようになります。
Movidius NCSのセットアップ
ここからが、Movidiusの NCS準備です。と言っても、一箇所を除き公式動画をそのまま動かすだけですが・・・。作業はラズパイにsshで入って、適当な場所で行います。僕はホーム直下でそのままやっちゃっています。
まずは、SDKをダウンロードおよび解凍します。
$ wget https://ncs-forum-uploads.s3.amazonaws.com/ncsdk/MvNC_SDK_01_07_07/MvNC_SDK_1.07.07.tgz
$ tar xvf MvNC_SDK_1.07.07.tgz
$ tar xvf MvNC_API-1.07.07.tgz
$ tar xvf MvNC_Toolkit-1.07.06.tgz
続いてインストール作業を行います。まずは、caffe環境をラズパイに入れます。これが結構長く、数時間待ちですので、気長に待ちます。
cd bin
./setup.sh
ここで、環境変数の再読込みなど色々あるので、一旦ログアウトし再度ログインします。その上で依存関係のチェックを行います。以下のコマンドで何も出なければOKです。
cd bin
make check
次に、諸々のモデルなどのインストールです。
cd ncapi
./setup.sh
すると、下記エラーが僕の環境では出ました。
Traceback (most recent call last):
File "/usr/local/lib/python3.5/dist-packages/mvnc/mvncapi.py", line 7, in <module>
f = CDLL("./libmvnc.so")
File "/usr/lib/python3.5/ctypes/__init__.py", line 347, in __init__
self._handle = _dlopen(self._name, mode)
OSError: ./libmvnc.so: cannot open shared object file: No such file or directory
これは、ラズパイ用にライブラリが正常にインストールされていないと起こるようです。ラズパイ用のライブラリのインストールは下記で行います。
$ cd ncapi/redist/pi_jessie
$ sudo dpkg -i *
再度、モデルの構築を行いますが、続きのみで良いので、
$ cd ncapi/tools
$ ./convert_models.sh
で実行します。今度はエラーが消えたと思います。ただし、最後に
[Error 28] Caffe Error: MemoryError. Potential Cause: Available RAM not sufficient for Network to be loaded into Caffe
と出ます。ラズパイだとAlexNetは大きすぎるっぽいですね(モデル構築についてはデフォルトのコマンドでは速度が出ないので、本記事最後の追記も確認ください)。
Movidius NCSの実行
さて、ここからはマニュアル通りに少しずつ確認していきます。最初は上記でcompileしてできたであろうgraphファイルをチェックします。
$ cd bin
$ python3 mvNCProfile.pyc ./data/lenet8.prototxt -w ./data/lenet8.caffemodel
出力は下記のようになります。
ubuntu@ubuntu:~/bin$ python3 mvNCProfile.pyc ./data/lenet8.prototxt -w ./data/lenet8.caffemodel
mvNCProfile v02.00, Copyright @ Movidius Ltd 2016
USB: Transferring Data...
Time to Execute : 7.54 ms
USB: Myriad Execution Finished
Time to Execute : 6.58 ms
USB: Myriad Execution Finished
USB: Myriad Connection Closing.
USB: Myriad Connection Closed.
Network Summary
Detailed Per Layer Profile
Layer Name MFLOPs Bandwidth MB/s time(ms)
========================================================================================
0 conv1 5.530 258.44 1.20
1 pool1 0.014 304.65 0.09
2 conv2 4.301 252.09 0.91
3 pool2 0.004 160.46 0.04
4 ip1 0.002 2083.80 0.41
5 ip2 0.001 481.20 0.02
6 softmax 0.000 0.61 0.03
----------------------------------------------------------------------------------------
Total inference time 2.70
----------------------------------------------------------------------------------------
Generating Profile Report 'output_report.html'...
これは、ネットワークを可視化するもので、output_report.html
に結果が出力されます。以下に途中までの図を記載します。
次に、ネットワークの動作チェックをします。
$ python3 ./mvNCCheck.pyc ./data/lenet8.prototxt -w ./data/lenet8.caffemodel -S 255 -M ./data/imagenet_mean.py
結果は下記となります。
ubuntu@ubuntu:~/bin$ python3 ./mvNCCheck.pyc ./data/lenet8.prototxt -w ./data/lenet8.caffemodel -S 255 -M ./data/imagenet_mean.py
mvNCCheck v02.00, Copyright @ Movidius Ltd 2016
USB: Transferring Data...
USB: Myriad Execution Finished
USB: Myriad Connection Closing.
USB: Myriad Connection Closed.
Result: (1, 10)
1) 8 0.48267
2) 2 0.34961
3) 4 0.09375
4) 6 0.029266
5) 3 0.015182
Expected: (10,)
1) 8 0.48413
2) 2 0.3479
3) 4 0.09436
4) 6 0.029251
5) 3 0.015228
------------------------------------------------------------
Obtained values
------------------------------------------------------------
Obtained Min Pixel Accuracy: 0.3530004993081093% (max allowed=2%), Pass
Obtained Average Pixel Accuracy: 0.08027215953916311% (max allowed=1%), Pass
Obtained Percentage of wrong values: 0.0% (max allowed=0%), Pass
Obtained Pixel-wise L2 error: 0.15237264986375257% (max allowed=1%), Pass
Obtained Global Sum Difference: 0.0038862228393554688
------------------------------------------------------------
さて、ここまで来たら、後は簡単な認識をやってみましょう。まずはプログラムをビルドします(2017/08時点でのサンプルにはバグがあり、本記事最後の追記も併せて確認ください)。
$ cd ncapi/c_examples/
$ make
そしたら、compileして作成したgraphを実行してみましょう。
./ncs-fullcheck -c1 ../networks/GoogLeNet ../images/cat.jpg
結果は下記となります。
ubuntu@ubuntu:~/ncapi/c_examples$ ./ncs-fullcheck -c1 ../networks/GoogLeNet ../images/cat.jpg
OpenDevice 1.5 succeeded
Graph allocated
Persian cat (46.17%) Egyptian cat (17.80%) tabby, tabby cat (7.54%) lynx, catamount (7.19%) Arctic fox, white fox, Alopex lagopus (5.78%)
Inference time: 569.193970 ms, total time 582.029392 ms
Deallocate graph, rc=0
Device closed, rc=0
速度は0.5秒とMovidius NCSが使えているか微妙に見える結果ですね、ラズパイにしては速いのだろうか。そして本当は(多分)tiger catかtabby catあたり(すみません、前回Egyptian catと書いていましたが間違いでした、猫わからん・・・)が1位に来るはずですが、うまくはいってない模様です。近々確認してみます。
まとめ
今回の記事では、一先ずラズパイでMovidius NCSが動くところまでを実施しました。精度・速度とともに未検証なので、まずは次回はその検証を行います。実用上好きなCaffeモデルを扱う所が重要ですが、それも次々回以降に試していこうと思います。その他ラズパイに載せたカメラで認識する、Dockerで動かすなど興味は付きないので、試した分だけこちらに書いていこうと思います。
[2017/08/10 追記]
上記で述べたように、精度と速度を検証しました。結論として、Movidius NCSのバグやサンプルの実行方法によって、大分改善される事がわかりました。
精度の改善
コメントでも報告いただいておりますが、ncs-fullcheck
についてはサンプルのバグが報告されているようです。具体的にはRGBとBGRが逆とのことです。これを修正すると精度が改善するようです。報告にあるように下記のように書き換えることで修正できます。
149,154c149,151
< float r = imgfp32[3*i+0];
< float g = imgfp32[3*i+1];
< float b = imgfp32[3*i+2];
< imgfp32[3*i+0] = (b-mean[0])*std[0];
< imgfp32[3*i+1] = (g-mean[1])*std[1];
< imgfp32[3*i+2] = (r-mean[2])*std[2];
---
> imgfp32[3*i] = (imgfp32[3*i]-mean[0])*std[0];
> imgfp32[3*i+1] = (imgfp32[3*i+1]-mean[1])*std[1];
> imgfp32[3*i+2] = (imgfp32[3*i+2]-mean[2])*std[2];
速度の改善
サンプル中で、convert_model.sh
でネットワークをコンパイルするのですが、その際にデフォルトでは何故かSHAVEコアを1個しか使わない設定になっているようです。これを12個使うようにオプションで指定することで速度が大幅に改善できます。コンパイルは下記のようにすることで実行できます。
cd data/GoogLeNet
python3 ../../bin/mvNCCompile.pyc ./deploy.prototxt -s 12 -w ./bvlc_googlenet.caffemodel -o graph
これは既に記事として報告されております。素晴らしい!
実験結果
GoogLeNetの実験の結果は下記のようになりました。速度が約100msと、nshaveが1の時と比べて5倍以上速くなっていますね。認識結果も問題ないように思います。
OpenDevice 1.5 succeeded
Graph allocated
tiger cat (44.21%) tabby, tabby cat (25.59%) Egyptian cat (21.39%) lynx, catamount (2.53%) Persian cat (1.04%)
Inference time: 108.022110 ms, total time 121.338250 ms
Deallocate graph, rc=0
Device closed, rc=0