DesignSpark Electrical Logolinkedin
Menu 検索
フォーラムで質問

人工知能 画像認識システム「Pidentifier」を、ラズパイとMovidius でサクッと作ってみた

Piカメラで撮影した画像を、Pi 3BとIntel Movidius NCSで画像認識させ、DesignSpark Pmod HATに繋いだDigilent OLED Pmodに認識結果を表示させている。

人工知能や深層ニューラルネットワーク(DNN)を、技術者や専門家のためだけの特別保護区のように考えてはいないだろうか?たしかにニューラルネットワークの作成はとても困難で、さらにそのトレーニングには非常に多くの時間と資源が必要だ。

しかし最近では、既にトレーニング済みの画像セットネットワークが公開されていたり、さらに Movidius NCSとそのSDKを使えば、比較的簡単にそのネットワークが使用できるようになってきた。全くのAI 門外漢の私であっても、Raspberry Piなどのコンパクトで低電力なプラットフォームからこれらのネットワークを使うような アプリケーションの開発が手軽に行えるようになったのである。

この記事では、カメラとコンパクトなOLEDモジュールを使った、自己完結型画像認識システム「Pidenfifier (訳者注:Piとidenfifier(認識機) を組み合わせた造語)」を素早く組み立てていく様子をまとめてみた。この自己完結型システムは、画像をキャプチャ及びオフロードし、NCS上で動作するGoogLeNetで処理してから、OLEDモジュールに上位の結果を表示する。

Hardware

このプロジェクトでは、Raspbian Stretchを実行するRaspberry Pi 3モデルBと、公式のRaspberry Piカメラを使用します。これとIntel Movidius NCSに加え、DesignSpark Pmod HATと結果を表示するためのDigilent PmodOLEDrgbも使用する。

Raspbianをインストールし、Piを起動したら、最初にパッケージソフトウェアの最新版にアップグレードすることをお勧めする。

pi@pidentifier:~$ sudo apt-get update
pi@pidentifier:~$ sudo apt-get dist-upgrade

カメラのインターフェイスとOLEDモジュール用SPIの有効化も必要だ。

pi@pidentifier:~$ sudo raspi-config
  • Option 5 - Interfacing
  • P1 - Camera
  • Enable → YES
  • Option 5 - Interfacing
  • P4 - SPI
  • Enable → YES

 ソフトウェアの依存関係

ソフトウェアの依存関係の大部分は、O/Sパッケージ管理システムを介して取得できる。

pi@pidentifier:~$ sudo apt-get install -y build-essential git libusb-1.0-0-dev libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-dev protobuf-compiler libatlas-base-dev git automake byacc lsb-release cmake libgflags-dev libgoogle-glog-dev liblmdb-dev swig3.0 graphviz libxslt-dev libxml2-dev gfortran python3-dev python3-pip python3-setuptools python3-markdown python3-pillow python3-yaml python3-pygraphviz python3-h5py python3-nose python3-lxml python3-matplotlib python3-numpy python3-protobuf python3-dateutil python3-skimage python3-scipy python3-six python3-networkx libfreetype6-dev libjpeg-dev python3-gst-1.0 python3-picamera

次にPythonパッケージマネージャを使用して、OpenCVのサポートをインストールする。

pi@pidentifier:~$ sudo pip3 install opencv-python

Movidius NC SDKのAPIコンポーネントのみをインストールする。Raspberry PiにすべてのSDKをインストールすることもできるが、お勧めはしない。PCで必要なコンパイルを実行してから、バイナリグラフファイルをコピーする方が、はるかに処理が早いからだ。

pi@pidentifier:~$ mkdir workspace
pi@pidentifier:~$ cd workspace
pi@pidentifier:~$ git clone https://github.com/movidius/ncsdk
pi@pidentifier:~$ cd ncsdk/api/src
pi@pidentifier:~$ make
pi@pidentifier:~$ sudo make install

DesignSpark Pmod HATサポートライブラリは、1つのコマンドでインストール可能だ。

pi@pidentifier:~$ sudo pip3 install designspark.pmod

最後に、Movidius NC SDKを、Ubuntuを実行している別のコンピュータにすべてインストールする必要がある。これにより、Raspberry Piで使用するモデルをコンパイルできる。

user@laptop:~$ mkdir workspace
user@laptop:~$ cd workspace
user@laptop:~$ git clone https://github.com/movidius/ncsdk 
user@laptop:~$ cd
user@laptop:~$ sudo make install

ハードウェアのテスト

まず、Piカメラが期待通り機能するかどうかをテストする。

pi@pidentifier:~$ raspivid -d

これにより、画面にビデオが表示されるはずだ。

次に、NCSに対してHello Worldを実行して、その動作を確認する。

pi@pidentifier:~$ cd ~/workspace
pi@pidentifier:~$ git clone https://github.com/movidius/ncappzoo
pi@pidentifier:~$ python3 ncappzoo/apps/hello_ncs_py/hello_ncs.py

PmodOLEDrgbをテストするために、以下の内容を含むhelloOLED.pyというファイルを作成する。

from DesignSpark.Pmod.HAT import createPmod
from luma.core.render import canvas
from luma.oled.device import ssd1331

if __name__ == '__main__':
    try:
        oled = createPmod('OLEDrgb','JA')
        device = oled.getDevice()
        
        with canvas(device) as draw:
            draw.rectangle(device.bounding_box, outline="white", fill="black")
            draw.text((16,20), "Hello, World!", fill="white")
    
        while True:
            pass
    except KeyboardInterrupt:
        pass
    finally:
        oled.cleanup()

次に、これを実行する。

pi@pidentifier:~$ python3 helloOLED.py

Pmodモジュールのドキュメントとその他の例は、ReadTheDocsにある。

モデルのコンパイル

私たちは、GoogLeNetの論文に記載されたモデルの複製、トレーニング済みのモデルを使用する。しかし最初に、NC SDKをすべてインストールしたUbuntuマシンで、このモデルをコンパイルする必要がある。それと同時に、SDKに付属のサンプルをすべてコンパイルする。コンパイル中は、このコンピュータにNCを接続する必要があることに注意。

user@laptop:~$ cd workspace/ncsdk
user@laptop:~$ make examples

アプリケーション

次にアプリケーションを作成する。

GoogLeNetモデル用に新しくコンパイルされたバイナリグラフを、UbuntuコンピュータからRaspberry Piにコピーする必要がある。

user@laptop:~$ scp workspace/ncsdk/examples/caffe/GoogLeNet/graph \
user@laptop:~$ pi@pidentifier.local:workspace/ncappzoo/caffe/GoogLeNet/

次にテキストエディタを使用して、Raspberry Piでpidentifyという新しいファイルを作成します(「vi」をお気に入りのエディタに変更すること)。

pi@pidentifier:~$ vi pidentify

そして以下を入力して、必要なPythonライブラリをインポートする。

#!/usr/bin/python3
import os
import sys
import time
import numpy

import picamera

import mvnc.mvncapi as mvnc
import skimage
from skimage import io, transform

from DesignSpark.Pmod.HAT import createPmod
from luma.core.render import canvas
from luma.oled.device import ssd1331

次に、いくつかのNCS入力パラメータを定義する必要がある。

NCAPPZOO_PATH           = os.path.expanduser( '~/workspace/ncappzoo' )
GRAPH_PATH              = NCAPPZOO_PATH + '/caffe/GoogLeNet/graph'
IMAGE_PATH              = '/tmp/i-spy.jpg'
IMAGE_MEAN              = [ 104.00698793, 116.66876762, 122.67891434]
IMAGE_STDDEV            = 1
IMAGE_DIM               = ( 224, 224 )

NETWORK_STAT_TXT = NCAPPZOO_PATH + '/apps/stream_infer/googlenet_stat.txt'
NETWORK_CATEGORIES_TXT = NCAPPZOO_PATH + '/apps/stream_infer/googlenet_categories.txt'

別のニューラルネットワークを使用したい場合は、ここで変更する。

以下の2行で、私たちのニューラルネットワークに適した解像度で構成された、Raspberry Piカメラインスタンスが作成される。

camera = picamera.PiCamera()
camera.resolution = IMAGE_DIM

次にNCSを開き、デバイスハンドルを取得する。

ncsdevices = mvnc.EnumerateDevices()
if len( ncsdevices ) == 0:
        print( 'No NCS devices found' )
        quit()

ncs = mvnc.Device( ncsdevices[0] )
ncs.OpenDevice()

さらに、DesignSpark Pmod OLEDrgbインスタンスも作成する必要がある。

pmoddev = createPmod('OLEDrgb','JA')
oled = pmoddev.getDevice()

最初のデバイス設定が終わったので、グラフファイルをNCSにロードできるようになる。

with open( GRAPH_PATH, mode='rb' ) as f:
        blob = f.read()

graph = ncs.AllocateGraph( blob )

そして、ネットワークカテゴリをロードできる。

with open(NETWORK_CATEGORIES_TXT, 'r') as f:
    for line in f:
        cat = line.split('\n')[0]
        if cat != 'classes':
            gNetworkCategories.append(cat)
    f.close()

last = len(gNetworkCategories)-1

画像をNCSにオフロードし、推論を実行し、上位の結果を返す関数を作成する。

def getTopInference(img):
    img = print_img = skimage.io.imread( IMAGE_PATH )
    img = skimage.transform.resize( img, IMAGE_DIM, preserve_range=True )

    img = img[:, :, ::-1]

    img = img.astype( numpy.float32 )
    img = ( img - IMAGE_MEAN ) * IMAGE_STDDEV

    graph.LoadTensor( img.astype( numpy.float16 ), 'user object' )

    output, userobj = graph.GetResult()
    order = output.argsort()
    top = gNetworkCategories[order[last-0]]

    return top

これはテキストをPmodOLEDrgbモジュール画面に書き込むシンプルな関数だ。

def display(message):
    with canvas(oled) as draw:
        draw.text((16,20), message, fill="white")

最後はメインループだ。

try:
    while True:
        camera.capture(IMAGE_PATH)
        thing = getTopInference(IMAGE_PATH)
        display(thing)
        time.sleep(2)

except KeyboardInterrupt:
        pass

finally:
        graph.DeallocateGraph()
        ncs.CloseDevice()
        oled.cleanup()

これは画像をキャプチャし、上位の推論を表示してから、2秒停止し、処理を繰り返す。 

ファイルを保存して、実行可能にする。

pi@pidentifier:~$ chmod +x pidentify

テスト

最後に緊張しながら動作させてみる。

pi@pidentifier:~$ ./pidentify

少し時間が経ったら、上位の推論が表示されるはずだ。表示は数秒ごとに更新される。この時点で、ネットワークは1,000のカテゴリの1つにある画像でトレーニングされているため、分類できるものに限度があることに注意する必要がある。上位1の推論の精度(上位の結果のみを表示)は67.8%であったが、トップ5でこれらは88.9%に上昇する。

改善の可能性

Pythonのサポートと提供されたサンプルを利用できたおかげで、Raspberry Piカメラ・Intel Movidius NCS・Pmod HATをOLEDrgbディスプレイと統合するシンプルなアプリケーションをすばやく作成することができた。改善の余地は確かに残されており、さらなる実験を楽しむことができる。例えば、次のことを試すことが可能だ。

  • さまざまなネットワークを試す。コンパイルされたバイナリグラフファイルをコピーし、それに応じてNCS入力パラメータを更新するだけではあるが。
  • 静止画キャプチャではなくビデオストリームを使用する。NC App Zooには、これのベースとして使用できるstream_inferアプリのサンプルが含まれている。
  • 複数のNCSを使用します。NC App Zooにはサンプルコードが含まれている。
  • カメラのキャプチャパラメータを最適化する。
  • 表示されるテキストの書式を改善する。

もっと冒険したい場合は、自分のデータ/画像セットでモデルのトレーニングをやってみよう。

Andrew Back

Open source (hardware and software!) advocate, Treasurer and Director of the Free and Open Source Silicon Foundation, organiser of Wuthering Bytes technology festival and founder of the Open Source Hardware User Group.

22 Jan 2018, 11:16