マイコン版Tensorflow liteで音声認識を試してみた


Tensorflowには、学習したモデルをマイコンで動作させる「Tensorflow lite for Microcontrollers」という実験的なプロジェクトがあります。
以前から興味があったので、チュートリアルに従ってサンプルを動かしてみました。

動かしてみたサンプルは「Yes/No」を音声認識するというもので、以下のTensorflow Dev Summitでも紹介されています。

TensorFlow Lite (TF Dev Summit ‘19)

ドキュメントはこちらにあります。

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/tensorflow/lite/experimental/micro/examples/micro_speech at master · tensorflow/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宣言をいくつかつけると出なくなりました。

when i follow the guide to create a mbed folder,i get this error,this is the first time i use TFlite ,can any one help me please · Issue #32037 · tensorflow/tensorflow

ビルドが無事完了したら、.binファイルをドラッグ&ドロップでボードに書き込んで完了です。
DiscoveryボードはLCDの右側にMEMSマイクが付いていますので、そこへ「Yes」「No」を発音すれば認識されます。
認識結果はUSBシリアルポート(VCP)へも出力されます。

実際に認識させてみた様子です。

試してみたいけどビルドは面倒くさい、という方用にビルド済みバイナリを以下に置いておきます。

tflite-microspeech-DISCO_F746NG-mbed

zip形式ですので、解凍して中身のbinファイルをSTM32F746 Discovery kitにドラッグ&ドロップして下さい。(他の機種では使用できません。)

感想

この音声認識のデモは、オーディオ入力をFFTにかけ、その帯域ごとの強度の変動を使って音声認識をするものです。
認識タスクだけを見れば、機械学習を使わなくても実現できそうではありますが、Tensorflowで学習させたモデルをマイコンにまで持ってくることができる(かも)というコンセプトは魅力的ですね。

また、Mbedを使うのは約3年ぶりでしたが、以前に比べると大分安定した環境になっている印象は受けました。
ただ、全部入りのシステムなので、理解するには気合が必要そうな気もします。

コメント