見出し画像

Maixduinoを動かしてみる

PARTYで画像処理・機械学習のリサーチエンジニアをしている宮本です。

最近Deep Learningの認識アルゴリズムをマイコンで行うためのデバイスが続々出てきています。その中でもカメラ+ディスプレイ付きで3000円ちょっとで買えてしまうMaixduinoというマイコンを衝動買いしてしまったので、今回はこのデバイスを動かしてみたいと思います。Macを使いました。

Maixduinoとは

Arduino IDEとライブラリを利用可能な、K210搭載のMaixシリーズのAI開発ボードです。 豊富なオープンソースのライブラリを使うことで、高速なプロトタイピングや開発が可能です。2.4インチLCDとカメラモジュールがセットになっています。 またArduinoの他、K210用のMicroPython環境であるMaixPyでの開発も可能です。」(Switch Scienceより

SiPEEDという深センにある会社が開発したボードで、他のDeepLeaning用ボードと比べて安価です。ArduinoのIDEでも開発できるようですがMaixpyの方が安定しているという噂だったのでこちらを使いました。(実際はそんなに変わらないかもというくらいハマりました…)

●K210とは

SiPEEDのサイトによると ” K210 (a 64-bit dual-core RISC-V CPU with hardware FPU and convolution accelerator) ”ということで通常の処理を行うCPUとDeep Learning用の計算を行うチップが載っています。他にこのK210を搭載したマイコンとして ・Sipeed Maix M1 DockSipeed Maix BiTM5stickV などがあります。

RISC-Vとは

ざっくりいうとオープンソースのCPUです→wikipedia
RISC-V、流行ってきているみたいです


ハンズオンのながれ

・基板への書き込みのためのセットアップ
・顔検出モデルを動かしてみる
・一般物体認識モデルを動かしてみる

●まずは基板のセットアップ

ひとまずMaixduinoに顔検出をさせるのを目標にセットアップをしていきます。 こちらのページを参考にしました。 

(細かいですがこのページで「顔認識」としているのは「顔検出」の間違い)

必要なもの

・Sipeed Maixduino(+カメラ、ディスプレイが付いてきます) https://www.switch-science.com/catalog/5707/ 

僕は秋葉原のラジオデパートにあるShigezoneさんで購入したので¥3600くらいだった気がします。 今だともう少し安く買えるみたいです。 https://twitter.com/ShigezoneAkiba/status/1170532297000439809?s=20

・ USB Type-Cと自分のPCをつなぐケーブル
(普段Macbook proを使っているのですが、たまたま手元にType-C-Type-CのケーブルがなかったのでUSBハブ経由でUSB3.0-Type-Cのケーブルで接続しました。しかし後日Type-C-Type-Cのケーブルで電源が入らなかったので規格とかの相性があるのかもしれません…)


●セットアップ

・USB Type-Cドライバーのインストール http://www.wch.cn/download/CH341SER_MAC_ZIP.html

・kflash_guiのインストール
https://github.com/sipeed/kflash_gui/releases
※2019/11/22の時点で安定版がv1.3.2だったのでそれを使っています。

・Firmwareの準備
https://github.com/sipeed/MaixPy/releases
※v0.4.0の maixpy_v0.4.0_50_gcafae9d.binを使いました。

・Firmwareの書き込み kflash_guiを使ってFirmwareを書き込みます
中国語表記になっている場合は左上の「文|A」ボタンを押してkflash_guiを再起動すると英語表記になります。

画像5

Open Fileのボタンを押して、先ほどダウンロードしたFirmwareファイルを選択します。
Port でcu.usbserial-xel_sipeed0を指定してDownloadボタンを押すと書き込みが始まります。


顔検出を動かす

1. MaixPy IDE(Sipeed製品ファミリーの専用統合開発環境)をインストールする
http://dl.sipeed.com/MAIX/MaixPy/ide/v0.2.3/

2. モデルをダウンロードしてくる
http://dl.sipeed.com/MAIX/MaixPy/release/maixpy_v0.3.2/

3. kfpkgファイルをkflash_guiを使って書き込む

画像5

4. 動かすためのプログラムをMaixPy IDEで書いて実行

MaixPy IDEを開いて下記のコードをコピペします。

import sensor
import image
import lcd
import KPU as kpu

lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.run(1)
task = kpu.load(0x300000) # you need put model(face.kfpkg) in flash at address 0x300000
# task = kpu.load("/sd/face.kmodel")
anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025)
a = kpu.init_yolo2(task, 0.5, 0.3, 5, anchor)
while(True):
   img = sensor.snapshot()
   code = kpu.run_yolo2(task, img)
   if code:
       for i in code:
           print(i)
           a = img.draw_rectangle(i.rect())
   a = lcd.display(img)
a = kpu.deinit(task)

メニューバーからツール→Select BoardからSipeed Maixduinoを選択します。
左下の緑のマークをクリックして出てきたダイアログボックスでusbserial-xel_sipeed0を選択しOKを押します。接続したらその下の再生マークをクリックするとプログラムが動きます。処理画像はMaixduinoのディスプレイにも表示されますが、IDEの方にも表示されるので便利です。

画像3


一般物体認識モデルを動かす場合

顔検出はモデルが用意されていたので、次はKerasモデルからMaixduino用のモデルへ変換するところをやってみたいと思います。

Sipeedが用意してくれている解説ページを参考に一般物体検出(1000クラス)をやります。(参考にしましたがちょっとややこしかったので簡単にできる方法でやっています)


ここにあるファイルを使うのでダウンロードしてきます。
https://github.com/sipeed/Maix-Keras-workspace



0. paddingの変更

今回はMaix-Keras-workspaceにある学習済みのKerasモデル使ったのでこの操作は不要ですが、自分で最初から学習を行う場合はpadding操作の部分でK210の方法とKerasの方法で違いがあるため、Kerasのコードを書き換えて学習する必要があるようです。
Maix-Keras-workspaceに入っているmobilenet.pyをKerasが参照しているmobilenet.pyと入れ替えるか学習時に読み込むように設定してください。(詳しくはMaix-Keras-workspace/mbnet/README.mdを参照ください)


1.既存のTFmodelをTFLite用に変換

一般物体認識のためにimagenetの100万枚の画像で学習をしようと思うと何日もかかってしまうため、今回はMaix-Keras-workspaceにあった学習済みモデル(mbnet75.h5)を使って一連の変換の流れの雰囲気を掴むことを目標としたいと思います。まず、TFLite用のモデルに変換します。用意してくれているのがKerasモデルなので変換も簡単です
Kerasモデルで以下の操作を行うとmodel.tfileというファイルが出力されます。

import tensorflow as tf

converter = tf.lite.TFLiteConverter.from_keras_model_file('mbnet75.h5') 
tfmodel = converter.convert() 
open ("model.tflite" , "wb") .write(tfmodel) 



2.TFLiteモデルをK210Modelに変換

次にTFLiteのモデルをK210で使うモデルに変換します。これにはSipeedが用意してくれているツールを使います。

ただ、ここだけはLinuxでしか対応してないみたいなのでUbuntuでやりました。もしかするとDockerでもできるかもしれませんが試していません。

こちらのリンクにあるファイルをgithubから取ってきます。
https://github.com/sipeed/Maix_Toolbox

最初にget_nncase.shを使って変換のためのプログラムをダウンロードします。(がなぜかスクリプトが間違っていてダウンロードした圧縮ファイルの解凍に失敗するので手動で解凍しました。プルリクみたら何件もきてるけど直ってなくて謎)

変換の際に画像を通さないといけないので以下のリンクにある画像をダウンロードしてget_nncase.shを実行した時に作られたimagesフォルダに入れます。
https://github.com/kendryte/nncase/tree/master/examples/20classes_yolo/images

先ほど変換したmodel.tfileをMaix_Toolboxのフォルダに持ってきて

$ ./tflite2kmodel.sh model.tflite

をやるとmodel.kmodelというファイルができます。


3.Maixduinoにモデルをダウンロードする

このモデルは顔認識のモデルより重く、必要最低限のライブラリを残した軽量版のファームウェアを使う必要があるそうなのでダンロードしてきます。

最初に紹介したチュートリアルページにあるmaixpy_mbnet.zipを落としてきます。
https://bbs.sipeed.com/uploads/default/original/1X/8c0575593642b838031ec2e1129c0fe075932ef2.zip
↑このファイルを解凍して入っているmaixpy_mbnet.binをkflash_guiを使ってMaixduinoに入れます。

もしくはSipeedのMaixpyレポジトリにあるmaixpy_v0.4.0_50_gcafae9d_minimum.binでも動くと思います。

https://github.com/sipeed/MaixPy/releases/download/v0.4.0/maixpy_v0.4.0_50_gcafae9d_minimum.bin


次にmodel.kmodelをMaixduinoに書き込む場所のアドレスを指定してkfpkg形式のファイルを作ります。
kflash_guiでmodel.kmodelを選択し、アドレスを0x200000に書き換え、「Pack to kfpkg」のボタンを押し、適当な名前で保存します。

画像5

再度Open Fileを押し、今作ったkfpkgファイルを選択してDownloadを押します。

物体認識のクラス一覧が書かれたファイルを下記より落としてきて解凍します。
https://bbs.sipeed.com/uploads/default/original/1X/d41ad9dfbe01f228abe726986fbf1baf4e288f2e.zip
↑このtxtファイルをampy(Adafruit が提供しているMicroPython用のツール)使ってMaixduinoに入れます

まずターミナルでpipを使ってインストールします。

$ pip install adafruit-ampy


ファイルをコピーします。

$ ampy --port=/dev/cu.usbserial-xel_sipeed0 put labels.txt


ちゃんとコピーされたか確認したい場合は

$ ampy --port=/dev/cu.usbserial-xel_sipeed0 ls /flash

とやるとファイルの一覧が見れます。

最後に認識のためのプログラムを用意します。
また、誌面の都合上消していますが、下から3行目のlcd.draw_stringで%sの後ろにスペースを25個ほど足すと表示が見やすくなります

import sensor, image, lcd, time
import KPU as kpu
lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((224, 224))
sensor.set_vflip(1)
sensor.run(1)
lcd.clear()
lcd.draw_string(100,96,"MobileNet Demo")
lcd.draw_string(100,112,"Loading labels...")
f=open('labels.txt','r')
labels=f.readlines()
f.close()
task = kpu.load(0x200000) 
clock = time.clock()
while(True):
   img = sensor.snapshot()
   clock.tick()
   fmap = kpu.forward(task, img)
   fps=clock.fps()
   plist=fmap[:]
   pmax=max(plist)	
   max_index=plist.index(pmax)	
   a = lcd.display(img, oft=(0,0))
   lcd.draw_string(0, 224, "%.2f:%s   "%(pmax, labels[max_index].strip()))
   print(fps)
a = kpu.deinit(task)

MaixPyのIDEは今回の最小限のファームウェアでは動かないのでこれもampyを使って実行します。プログラムをmobilenet.pyなどとして保存したら

$ ampy --port=/dev/cu.usbserial-xel_sipeed0 run mobilenet.py 


とコマンドを入力すると…動くはずです!

画像5

車でも認識させてみるかと思ってwikipediaにあったフォードT型の画像を見せたら、T-modelと表示されました。とはいえちゃんと学習したモデルではないみたいで精度は低めな気がします。
(上の画像だとカメラとディスプレイの位置関係的に画像が反転して表示されてしまっているのですがサンプルプログラムのsensor.set_vflip(1)をコメントアウトすると正位置で表示されます)

Maixduinoで動かすためのモデルの変換を何回かやらないといけないのがややこしいですが、作業的には比較的簡単に動かせると思います。
(とはいえまとまった資料がなくていろんなところでものすごくハマりましたが…)

何よりこんな小さいデバイスで物体認識がリアルタイムで動くのが意外と楽しかったりします。

次回はもうちょっとややこしい顔認証に挑戦したいと思います。(すごいハマりそう)

______________________________________
PARTYでは未来の体験を社会にインストールすべく、好奇心旺盛なエンジニアを募集してます!


この記事が気に入ったらサポートをしてみませんか?