ＥＳＰ３２は深い学習の夢を見るか？[２](ESP32でMNISTデータの画像認識)

#目的
　DeepLearningやるのだったら、やっぱりMNISTデータですよね。
　実は「アヤメの分類」はDeepLearningとは言えないとの噂が。
　(ネットワークが4段以上無いと言わないとか)
　◆◆◆　そうだ、ＥＳＰ３２でMNISTデータの画像認識をやるぜ　◆◆◆
　うーむ、ESP32でメモリが足りるだろうか

#経緯
　(1)[前回] (https://qiita.com/hi631/items/7192421626308d521be0) の「アヤメの分類」でneural_network_consoleの使い方は多少分かった。
　(2)neural_network_console吐き出したc_sourceを、ESP32,vs2017で走らせEVALUATIONが実行できた。
　(3)次に10_deep_mlpで同様にしたが、問題点が....。
　　1)結果の数値が出力されていない。
　　2)画像の入力のやり方が良く判らない。
　　3)メモリ不足でコンパイルできない(学習データがでかい！)
　(4)色々やって問題点を潰したら、いい感じで結果らしきものが表示された。

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


#neural_network_consoleでの操作(deep_mlp)
　例題とした「10_deep_mlp」は判定の確度しか表示せず、判定の元になる数値を出力していない。
　そこで、数値を出力するように変更する。
　(1)neural_network_console samples sample_project tutorial basics に在る10_deep_mlp.sdcproj(filesも)を何処かにコピーする。
　(2)プロジェクト画面でコピーしたプロジェクトを選択する。
　(3)EDIT画面で最下段をSoftMaxに変更。
　(4)Affine_4(5),Tanh_4(5)のOutShapeを10に変更。
　(5)TRAINING,EVALUATIONを実行。
　(6)EVALUATION画面で、y'_0 - Y'_9が表示されていることを確認。
　(7)c_sourceの内容をコンパイルする各フォルダにコピーする
　(8)上記を設定したものを下記に格納しているので参考にされたい。(但しコピー(移動)して動くかどうかは未調査)
　　 [10出力deep_mlp] (https://github.com/hi631/esp32-nnc/tree/master/deep_mlp_s)
　10出力deep_mlp設定例　　　　　　　　　　　　　　　　　　入力画像変換画面
![Image4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159764/ba9758f4-4950-8ba5-64aa-a92bcd112ea9.jpeg)

#neural_network_consoleでの入力画像変換
　c_sourceのMainRuntime_example.cは独自形式の画像入力にのみ対応している。
　テストデーター(2個)は存在しているが、作り方の説明が何処にあるのかは判らなかった。
　そこでテストデーターを解析し、次のように新たなデータを作成した。
　(1)見た感じでテストデータは28x28(784個)のfloatの並びと想定。
　(2)上記想定に基づく変換、表示ソフト(VB)を作成して検証。
　　※変換データ(0,1,2,3を追加、既成分と合わせて計8件)をdataフォルダに格納しています。
　　※変換プログラム(VB)は下記に格納しています。
　　　 [入力画像変換] (https://github.com/hi631/esp32-nnc/tree/master/floatconv)
　　　プログラムはVB(2017)で新規プロジェクトを設定し、floatconv内の各ファイルと差し替えれば使える(はずですが、一応EXEも入れときました)。
　　　データ作成方は、入力画面(上図)で上段に変換元(**.png)、下段に変換先(**.bin)を入れ、「変換」を押す。
　　　※追記　一括変換を追加しました。

#画像の与え方

　<ESP32への格納>
　 [前回] (https://qiita.com/hi631/items/7192421626308d521be0) 記載の「ESP32による「アヤメの分類」のEVALUATION(データーファイル使用バージョン)」と同様に行います。

　<データーの読み込み>
  入力バッファに784個のfloatデータをべた書きする。
　　float *idbf = nnablart_mainruntime_input_buffer(context, 0); // Input.Data.Buffer
　　fread(idbf, sizeof(float), NNABLART_MAINRUNTIME_INPUT0_SIZE, input0);

#ESP32へのプログラム(主に学習データ)の格納
　c_sourceをESP32でコンパイルすると悲しい事に、「region `dram0_0_seg' overflowed by ****** bytes」が発生します。
　これはMainRuntime_parameters.c内の配列も含めた変数を、100KB程度に収めないとRAMがパンクするからです。
　しかしこの作業は、学習データを小さくすることであり、極端な性能低下を招く可能性が高いと思われます。
　そこで、色々調べたが解決策が見当たらず、暗礁に乗り上げてしまい深い学習の夢は立たれるかと思われました。
　しかし、意外に簡単な方法で解決することが分かって、事なきを得ました。
　学習データはMainRuntime_parameters.cに配列の形で格納しています。
　ESP32では配列は変数であり、起動時にDRAM領域にコピーされる事により(推測)、貴重なRAMが食いつぶされます。
　そこで配列を定数とする事により、配列はプログラム領域に留まり、貴重なRAMが生き残ります。
　具体的には、MainRuntime_parameters.c内の配列の先頭にconstを追記してconst floatとする事により、これを実現します。
　これにより、下記に示すようなメモリ使用量となりました。
　プログラムエリアはpartitions_example.csvにより約3MB確保しており、あと3倍程度に学習強化が可能でしよう。

		$ make size
		Total sizes:
		 DRAM .data size:    8592 bytes
		 DRAM .bss  size:    2008 bytes
		Used static DRAM:   10600 bytes ( 170136 available, 5.9% used)　　←　配列を変数にするとここが使われる
		Used static IRAM:   34560 bytes (  96512 available, 26.4% used)
		      Flash code:   99064 bytes
		    Flash rodata: 1001396 bytes
		Total image size:~1143612 bytes (.bin may be padded larger)

#ESP32によるdeep_mlpのEVALUATION
　ESP32のesp-idfでコンパイル可能な形で下記に格納しています。
　　 [ESP32によるdeep_mlp] (https://github.com/hi631/esp32-nnc/tree/master/esp-nnc)
　前回プログラムとの共用を図っているため、プログラムの移動が必要となっています。
　(1)esp-nnc main 内のcomponent.mk以外をすべて削除
　(2)eps-nnc main_mnistのプログラムを esp-nnc main に全てコピー
　(3)make cleanを実行後、make flash monitorを実行する。
　(4)下記が表示されれば成功

		Start
		Spiffs.Dir.Info
		 0_1.bin
		 1_1.bin
		 2_1.bin
		 3_1.bin
		 4_1.bin
		 4_2.bin
		 9_1.bin
		 9_2.bin
		　:
		　:
		Partition size: total: 956561, used: 210589
		
		0_1.bin  +1.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 ( 0 )
		1_1.bin  +0.000 +1.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 ( 1 )
		2_1.bin  +0.000 +0.000 +1.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 ( 2 )
		3_1.bin  +0.000 +0.000 +0.000 +1.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 ( 3 )
		4_1.bin  +0.000 +0.000 +0.000 +0.000 +1.000 +0.000 +0.000 +0.000 +0.000 +0.000 ( 4 )
		4_2.bin  +0.000 +0.000 +0.000 +0.000 +1.000 +0.000 +0.000 +0.000 +0.000 +0.000 ( 4 )
		9_1.bin  +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +1.000 ( 9 )
		9_2.bin  +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +0.000 +1.000 ( 9 )
		Stop

　※0_1.binでは最初の数値が+1.000(他は+0.000)となっており、「0」である確率が高いことを示している。
　　()内は各ファイルにおいての、一番確率の高い数値を示しています。


　ESP32もNeuralNetworkConsoleもDeepLearningも、深く理解していないので、 考え違いをしているかもしれませんよ。　
　でも、次はカメラを繋いだESP32でDeepLearningをやってみたいかな。(Please expect the next work?)
　上記記載内容は無保証であり、各自の責任においてご利用願います。