Tensorflowには、学習したモデルをマイコンで動作させる「Tensorflow lite for Microcontrollers」という実験的なプロジェクトがあります。
以前から興味があったので、チュートリアルに従ってサンプルを動かしてみました。
動かしてみたサンプルは「Yes/No」を音声認識するというもので、以下のTensorflow Dev Summitでも紹介されています。
ドキュメントはこちらにあります。
TensorFlow Lite for Microcontrollers | TensorFlow
Get started with microcontrollers | TensorFlow Lite
現在、サンプルとしては以下のものが用意されています。
・Hello World:θの値からsinθを予測
・Micro speech:音声のFFT結果の時系列データからYesとNoを認識
・Person detection:カメラ画像から人が写っているか否かを認識
・Magic wand:加速度センサのデータから3つの異なるジェスチャを認識
また、サンプルの動作対象となるハードウェアとプラットホームは以下のものです。
・Arduino Nano 33 BLE Sense (Arduino)
・ESP32-DevKitC、ESP-EYE (ESP-IDF4.0) — Hello worldのみ
・SparkFun Edge (プラットホームは使わない)
・STM32F746 Discovery kit (Mbed) — Hello worldとMicro speechのみ
・Adafruit EdgeBadge (Arduino)
・Adafruit TensorFlow Lite for Microcontrollers Kit (Arduino)
ソースツリーを見てみると、他にもBlue Pill(STM32ベースのArduino環境で使われているボード)やRISC-V 32bitなどの名前もありますので、将来はこれらにも移植されていくのかもしれません。
手持ちのデバイスに、3月に買ってからあまり活用していないSTM32F746 Discovery kitがありますので、今回はこれでMicro speechのサンプルを動かしてみました。
Mbed開発環境をインストール
プラットホームとしてMbedが使われていますので、まず開発環境を導入します。
Mbedにはオンライン版とオフライン版がありますが、今回使うのはオフライン版です。
私の使用したプラットホームはUbuntu16.04です。Mbed自体はWindowsでも利用できますが、Linuxのほうが何かとトラブルが少ないと思います。
環境構築はPythonスクリプト化されており、簡単です。
インストール手順書はこちらにあります。
Linux – Tools | Mbed OS 5 Documentation
Pythonとpipとgitはインストール済みだとして、mercurialというソースコード管理ツールと、Mbedの統合開発ツールmbed-cliをインストールします。
$ sudo apt-get install mercurial
$ sudo pip install mbed-cli
基本的にはこれで終わりですが、後で述べるように、他にMbed開発環境で利用されるPythonのパッケージのインストールが必要です。
MbedでLチカして開発環境を確認
いきなりTensorflowへ行く前に、まずLチカがビルドできることを確認して開発環境が正しくインストールできかたチェックしておきます。チュートリアルは以下のページにあります。
Compiling the code – Quick start | Mbed OS 5 Documentation
Lチカのプロジェクトファイルを以下のようにしてローカルにコピーしてきます。
$ mbed import https://github.com/ARMmbed/mbed-os-example-blinky
$ cd mbed-os-example-blinky/
Mbedのプロジェクトはハードウェアに依存しないように作られていますので、ビルド時にターゲットの指定が必要になります。
ターゲットの一覧は
$ mbed compile -S
で表示できます。今回はSTM32F746 Discovery kitを使いますので、このボードのターゲット名を調べます。
$ mbed compile -S | grep 746
[mbed] WARNING: Python 3 is not yet fully supported: Python errors may occur when compiling, testing and exporting
---
| DISCO_F746NG | Supported | Supported | Supported | Supported | Supported | Supported | - |
| NUCLEO_F746ZG | Supported | Supported | Supported | Supported | Supported | Supported | - |
ということでターゲット名はDISCO_F746NG
と分かりました。
ビルドは以下のようになります。
$ mbed compile --target DISCO_F746NG --toolchain GCC_ARM
ARM用GCCをインストールしていない場合は、以下からダウンロードしてパスを張っておいてください。
現在の推奨バージョンはGNU Arm Embedded version 6 (6-2017-q1-update)です。
(が、私は最新のgcc-arm-none-eabi-9-2019-q4-major-x86_64-linux.tar.bz2をインストールしちゃいました。)
GNU Toolchain | GNU-RM Downloads – Arm Developer
Pythonパッケージの不足というエラーメッセージが出る場合は、メッセージにもあるようにmbed-os/requirements.txt
を使って、以下のようにパッケージをインストールします。
$ cd mbed-os
$ sudo pip install -r requirements.txt
ビルドは1000個近いファイルをコンパイルするので、結構時間がかかります。
ビルドが完了するとBUILD/DISCO_F746NG/GCC_ARM/に
.bin
ファイルができます。
DiscoveryボードをUSB接続して、binファイルをストレージにドラッグ&ドロップすればインストール完了です。
正しくビルドできていればLEDが点滅するはずです。
Tensorflowサンプルのビルド
Mbed環境がちゃんと動作していたら、次にTensorflowサンプルをビルドしてみます。
ガイドのドキュメントは以下にあります。
まずtensorflowをクローンします。
$ git clone https://github.com/tensorflow/tensorflow/
$ cd tensorflow
最新版のtensorflowだとビルドがうまくいかなかった(mul.ccのコンパイル時にscoped_profiling_label_wrapper.h@38,39: profiling/instrumentation.h: No such file or directory
と怒られる)ので、最新リリースのv2.1.0をチェックアウトします。
$ git checkout r2.1
(実は、まだこれだけではビルドが失敗するのですが、修正方法は後述します。)
ではビルドです。
まず、Mbed環境に合わせて必要なフォルダを作成します。
これはTensorflowに付属のMakefileがやってくれます。
$ make -f tensorflow/lite/experimental/micro/tools/make/Makefile TARGET=mbed TAGS="CMSIS disco_f746ng" generate_micro_speech_mbed_project
これでフォルダが作られたので、フォルダへ移動してMbedプロジェクトとして初期化します。
$ ls -CFx tensorflow/lite/experimental/micro/tools/make/gen/mbed_cortex-m4/prj/micro_speech/mbed
AUDIO_DISCO_F746NG.lib BSP_DISCO_F746NG.lib LCD_DISCO_F746NG.lib
LICENSE README_MBED.md SDRAM_DISCO_F746NG.lib
mbed-os.lib mbed_app.json tensorflow/
third_party/
$ cd tensorflow/lite/experimental/micro/tools/make/gen/mbed_cortex-m4/prj/micro_speech/mbed
$ mbed config root .
次にMbed関連のソースコードをダウンロードします。
これには結構時間がかかります。
$ mbed deploy
ビルドする前に、ガイドのドキュメントにあるとおり、Mbedのコンパイラオプションを書き換えます。
ただ、現時点ではMbed側のファイルではこの部分の指定がgnu++98ではなく、gnu++14になっているので、この処理は結果的に何もしていないように思います。
$ python -c 'import fileinput, glob;
> for filename in glob.glob("mbed-os/tools/profiles/*.json"):
> for line in fileinput.input(filename, inplace=True):
> print line.replace("\"-std=gnu++98\"","\"-std=c++11\", \"-fpermissive\"")'
Lチカと同じようにmbedコマンドでビルドします。
$ mbed compile -m DISCO_F746NG -t GCC_ARM
私の場合、以下のようにarm_mult_q15.c
のコンパイルエラーで停止しました。
Compile [ 97.1%]: arm_mult_q15.c
[Error] arm_mult_q15.c@101,6: conflicting types for 'arm_mult_q15'
[ERROR] ./tensorflow/lite/experimental/micro/tools/make/downloads/cmsis/CMSIS/DSP/Source/BasicMathFunctions/arm_mult_q15.c:101:6: error: conflicting types for 'arm_mult_q15'
101 | void arm_mult_q15(
| ^~~~~~~~~~~~
In file included from ./tensorflow/lite/experimental/micro/tools/make/downloads/cmsis/CMSIS/DSP/Source/BasicMathFunctions/arm_mult_q15.c:29:
./mbed-os/cmsis/TARGET_CORTEX_M/arm_math.h:1924:8: note: previous declaration of 'arm_mult_q15' was here
1924 | void arm_mult_q15(
| ^~~~~~~~~~~~
このエラーですが、以下のIssuesにあるようにMbed側のファイルmbed/mbed-os/cmsis/TARGET_CORTEX_M/arm_math.h
でconst宣言をいくつかつけると出なくなりました。
ビルドが無事完了したら、.binファイルをドラッグ&ドロップでボードに書き込んで完了です。
DiscoveryボードはLCDの右側にMEMSマイクが付いていますので、そこへ「Yes」「No」を発音すれば認識されます。
認識結果はUSBシリアルポート(VCP)へも出力されます。
実際に認識させてみた様子です。
試してみたいけどビルドは面倒くさい、という方用にビルド済みバイナリを以下に置いておきます。
tflite-microspeech-DISCO_F746NG-mbed
zip形式ですので、解凍して中身のbinファイルをSTM32F746 Discovery kitにドラッグ&ドロップして下さい。(他の機種では使用できません。)
感想
この音声認識のデモは、オーディオ入力をFFTにかけ、その帯域ごとの強度の変動を使って音声認識をするものです。
認識タスクだけを見れば、機械学習を使わなくても実現できそうではありますが、Tensorflowで学習させたモデルをマイコンにまで持ってくることができる(かも)というコンセプトは魅力的ですね。
また、Mbedを使うのは約3年ぶりでしたが、以前に比べると大分安定した環境になっている印象は受けました。
ただ、全部入りのシステムなので、理解するには気合が必要そうな気もします。
コメント