ＥＳＰ３２は深い学習の夢を見るか？[１](ESP32で軽量DeepLearning)

#目的
　現在の生活では家電品の操作にはリモコンが必要であり、我が家でもそこら中に氾濫している。
　近未来では、見つめるだけでエアコンの電源が入る、テレビのチャンネルが変えられるようになる(かも知れない)。
　これを取り合えず実現するには次のような技術が必要だ。
　　　■操作対象の認識　→　■動作の選択　→　■対象へのアクション
　　　(カメラ＋画像認識)　　(加速度センサー)　　(赤外線信号)
　うむ、現状技術でも到達可能な気がする。でも体に付けたいから小さくないとね。
　◆◆◆　そうだ、ＥＳＰ３２へDeepLearningを実装したら実現出来るかも。　◆◆◆
　まずは手始めに「アヤメの分類」からでも手を付けてみるか。(今回は画像処理まで行きついていません)
![ayame.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159764/e3d519f6-54bf-c670-5715-cdf8fbc6647f.jpeg)

#経緯
　(1)ＥＳＰ３２のカメラ接続に技術的な問題が無いので、画像認識方法を考えたい。
　(2)ど定番のTensorFlowを乗せるのは、ESP32ではメモリ容量的に無理なのは明らか。
　(3)Ｃで書かれたライブラリを見つけたが、コンパイル結果は16MB程度になったのでちょっと無理と判断。
　(4)neural_network_consoleのマイコンへの応用事例が見つかった。小容量でも使えるみたい。
　(5)CQ出版 Interface 2019年 1月号及びQiita等の事例では、インプリメント部分の説明不十分(私的には)。
　(6)ESP32の事例も有ったが、前提とする条件が複雑であり、うまく追試をやれる自信なし。
　(7)仕方が無いので、事例から情報を読み取り、いろいろ試してみたら、「アヤメ」は案外うまくいった。

#neural_network_consoleとは
　天下のＳＯＮＹが無償で公開している(よ、太っ腹)、ＧＵＩで操作できる機械学習用ソフト。
　今までは、Pythonを入れ手間をかけて環境を整えてやる必要があり、設定同士がぶつかり動作しないことも。
　おっとびっくり、これを入れればあっという間に動くものが出来上がり。
　　[Neural Network Console - Sony] (https://dl.sony.com/ja/)
　※処理速度が遅いという噂も有るが、構築のお手軽さを評価すべきで、本質的な部分により力を注げる。
　※ＧＰＵを搭載しているほうが幸せになれる。
　おまけなのか、evaluation(評価)用のＣのソースプロクラムを吐き出してくれる。
　(マイコン化への貴重なインターフェースだが、説明が少なくＳＯＮＹとしては力を入れてないのかな)

#前提条件
　以下のソフトを予め導入の事。
　(1)neural_network_console　(当たり前、for Windows 8.1/10_64bit 1.4.0にて検証)
　(2)ESP-IDF　　　　　　　　 (ESP32の開発環境)
　(3)VisualStudio(2017)　　　(パソコン上で動作確認したい場合に必要、無くても可)


#neural_network_consoleでの操作(アヤメの分類)
　(1)下記を実施し、正しくEVALUATIONが行えることを確認する。
　　[SonnyのNNC（Neural Network Console）でのアヤメの分類の実装] (https://newtechnologylifestyle.net/sonny_nnc_irisdata_junnbi/)
　(2)EVALUATION画面で、ACTION → Export → NNB と選択していく。
　(3)c_source(マイコン用プログラム)が存在する画面が表示されるので、必要なフォルダにコピーする。
　※c_source内のプログラムの機能について(推測)
　　MainRuntime_example.c 　　mainプログラム、入力、評価、出力を実施。
　　MainRuntime_inference.c 　ＧＵＩで設定した構成を反映、下位モジュールでDeepLearning処理を行う。
　　MainRuntime_parameters.c　学習結果を配列として保持。

#neural_network_consoleでのデータ入出力について
　c_sourceのMainRuntime_example.cは独自形式の画像入力にのみ対応している。
　特定の例題(10_deep_mlp)以外では、別途プログラムによる対応が必要となる。
　この部分はかなり曖昧に書かれており、詳細は不明。(説明書が何処かにあるのかも知れないが)
　下記のような考えを想定してプログラムしたらうまく動作した。
　(1)入出力は単精度実数(float)
  　※neural_network_consoleではcsvで入力しているが、MainRuntime_example.cではfloatに変換して与える必要有り。
　(2)入力する値はinput_bufferがポインタする位置に数値を必要数書込む。
　　float *idbf = nnablart_mainruntime_input_buffer(context, 0); // Input.Data.Buffer
　　sscanf(buf, "%f,%f,%f,%f,%f", &idbf[0], &idbf[1], &idbf[2], &idbf[3], &label);
　　※neural_network_consoleのEVALUATION画面での、x_0,X_1,X_2,X_3に対応するデータを与える。
　(3)出力された値はoutput_bufferがポインタする位置に書き込まれている。
　　float *odbf = nnablart_mainruntime_output_buffer(context, 0); // Output>data.buffer
　　for (int j = 0; j < 3; j++) printf(" %+.3f", odbf[j]);
　　※neural_network_consoleのEVALUATION画面での、y_0,y_1,y_2に対応するデータを読みだす。
　　　EDITで、出力に必要とするy_0,y_1,y_2等がEVALUATION画面に表示されるように構成する必要有り。

#ESP32による「アヤメの分類」のEVALUATION(データーファイル不使用バージョン)
　※esp32はファイルシステムを使用可能だが、登録処理に多少手間が必要。
  　そこでデーターをプログラム(**.h)に埋め込み入力データとする。
　(1)ライブラリ(nnabla-c-runtime)を取得する。
  　　 [nnabla-c-runtime] (https://github.com/sony/nnabla-c-runtime)
　(2)ESP32でコンパイル可能なエリアにフォルダ(例:esp-nnc)を作成。
　(3)必要なライブラリ(src functions下のimplementsとutilities)をesp-nnc(のcomponents下)に格納
　(4)c_sourceの内容をフォルダにコピーする(例ではmain下)。
　(5)esp-idfがコンパイルしてくれるように、各フォルダにcomponent.mkを作成、配置。
　　※esp-idfをバージョンアップしたらコンパイルが通らなくなりました。
　　　component.mkの適用範囲が変わったと思われるので、(バグだと思うが)
　　　component以下のディレクトリをすべて書き込みました。(前のはimplements utilitiesのみ記載)
　(6)MainRuntime_example.cを処理内容に合わせて書き換え。
　　※MainRuntime_example.cの19行目「//#define FINP」はコメント(//)に設定の事。
　(7)ESP32メイン(app_main)からMainRuntime_example.cのmain()を呼びだすようにプログラムを作成。
　※上記説明だけでは判り難いとおもわれるので、説明も兼ねて(1)-(7)を実施した結果を下記にアップしている。
　　ダウンロードすればesp32開発環境下でコンパイル可能(なはず)。
　　 [ESP32による「アヤメの分類」] (https://github.com/hi631/esp32-nnc/tree/master/esp-nnc)
　(7)make flash monitor を実行。(ctrl+]で終了)
　　下記が表示されるので、neural_network_consoleの表示と比較する。
　　※シリアルをCOM6に設定しているので、異なる場合はmake menuconfigで変更するか、COM番号を変更の事。

		* Start *
		 5.0 3.5 1.3 0.3 ( 0 )  +6.443 +2.331 -7.357 ( 0 )
		 4.5 2.3 1.3 0.3 ( 0 )  +5.065 +2.398 -6.332 ( 0 )
		 　 :
		 6.2 3.4 5.4 2.3 ( 2 )  -4.329 +1.268 +2.976 ( 2 )
		 5.9 3.0 5.1 1.8 ( 2 )  -3.711 +1.436 +2.227 ( 2 )
		* Stop  *
    

#ESP32による「アヤメの分類」のEVALUATION(データーファイル使用バージョン)
　ESP32でデーターファイルを使用する場合、spiffsライブラリを使用することになる。
　また、予めデータを用意する場合は、エリアの確保、データイメージの作成とアップロード機能が必要となる。
　なお、データー格納エリアはpartitions_example.csvに書いており、flashの0x300000から0x3fffff(1MB)を使用している。

　<データファイルの作成と格納>
　(1)下記をダウンロードし、ESP32でコンパイル可能なフォルダに配置する。
　　　[ESP32_spiffs_example] (https://github.com/loboris/ESP32_spiffs_example)
　(2)esp-nnc内のpartitions_example.csvをESP32_spiffs_exampleにコピー。
　(2)mingwを起動し、配置したフォルダ内で ./build_mkspiffs を実行。
　　components mkspiffs 内に mkspiffs.exe が生成される。
　　※当方の環境では424行でエラーとなったので、「\_mkdir」を「mkdir」に変更することで回避。
　(3)components spiffs_image image にアップロードするデータファイルを格納。
　　※samples sample_dataset iris_flower_dataset iris_flower_dataset_validation_delo.csv は iris_flower.csv としている。
　(4)make makefsの実行で、イメージファイル(1MB)が作成される。
　　 make flashfsの実行では、イメージファイルの作成後にESP32への転送が行われる。
　(5)make flash の実行で、テストプログラムのコンパイルと実行が行われるので、ESP32への格納の確認が可能。
　　※上記を実施したものを下記に圧縮して格納しているので、必要なら利用の事。
　　　[データファイルの作成と格納用プログラム] (https://github.com/hi631/esp32-nnc/blob/master/spiffs_example.zip)

　<実行>
　「データーファイル不要バージョン」と操作は同一。
　但し、MainRuntime_example.cの19行目「//#define FINP」のコメント(//)は取っておく。
　実行時に下記(格納ファイル情報)が追加表示される。
　「iris_flower.csv」が表示されない場合は、データファイルの作成と格納に失敗している。


		Spiffs.Dir.Info
		  :
		 iris_flower.csv
		  :
		Partition size: total: 956561, used: 211091


#VisualStudio(2017)による「アヤメの分類」のEVALUATION
　neural_network_consoleで表示されるものをVisualStudioで表示してもあまりメリットを感じないが、、
　パソコン上でのプログラムのデバッグには非常に役に立った。
　※入出力の確認などは全てVisualStudio上で行った。これをESP32上で行ったら多大の時間を要したはず。
　(1)ライブラリ(nnabla-c-runtime)を持ってくる。
  　　 [nnabla-c-runtime] (https://github.com/sony/nnabla-c-runtime)
　(2)nnabla-c-runtimeフォルダで cmake CMakeLists.txt を実行。
　　※当方の環境ではesp-idf用に構築したmingw上にcmakeを登録して実行。
　　　複数の前提ソフトが必要となったがなかなか登録できず、一寸大変であった。
　(3)nnabla-c-runtime src functions に c_source をフォルダごとコピー
　(4)MainRuntime_example.cの書き換えを行う。
　(5)nnabla-c-runtime src functions に dataフォルダを作成し、必要とされるデータを入れておく。
　(6)nnabla-c-runtime src functions に nnablart_functions.sln が出来ているので起動する。
　　※visualstudio2017が登録されていたら起動する。(ない場合はどうなるだろう)
　(7)nnablart_functions 以外のソリューションは(とりあえず)要らないので削除しておく。
　(8)nnablart_functions を右クリック、プロパティ 全般 構成の種類 で アプリケーション (.exe)に変更する。
　(9)nnablart_functions を右クリック、スタートアッププロジェクトに設定する。
　　※上記を実施したものを下記に圧縮して格納しているので、必要なら利用の事。
　　　[visualstudioによる「アヤメの分類」] (https://github.com/hi631/esp32-nnc/blob/master/nnabla-c-runtime.zip)
    　解凍後は「C:\」に設置し、c:\nnabla-c-runtime src functions の nnablart_functions.sln を起動する。
　　　(visualstudioのslnは絶対ディレクトリとなるため、必ず存在するディレクトリで作成した)
　(10)デバッグを開始すればESP32の時と同様な表示が出る。(はず)

　なるたけ再現性を確保したつもりですが、ごてごて書くのも何なんで、説明が不十分だと思います。
　後はアップロードしているプログラムで内容を確認願います。
　次はMNIST(画像による数字認識)に迫りたいと思っている。
　上記記載内容は無保証であり、各自の責任においてご利用願います。