【e-AI】Kerasで生成したAIモデルをマイコン（GR-PEACH）上で実行

（初めての投稿です:sweat:）
Kerasを使用して学習済みAIモデルを作成し、GR-PEACH（マイコン）上で推論実行させてみました。
e-AIは組み込みデバイス上でAIを動作可能にするツールである。e-AIソリューションはルネサスエレクトロニクスが提供し、~~Caffeや~~ PyTorchやKeras、Tensorflow（tf.keras API）といった一般的なフレームワークで生成したモデルを容易にマイコンに実装可能にする。
このe-AIが発表されてから暫く経つが、思ってたより活用例を見かけないのは残念なところだ。

久しぶり（2021.5時点）にサイトを見たらKerasに対応したようなので、今回はKerasでFashion-MNISTの学習済みAIモデルを生成しGR-PEACH上で動作させてみた。

GR-PEACH ↓
![gr-peach.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199130/1dab96f9-7c70-5579-f49c-7f63e511195c.jpeg)

記事を書いた/開発した動機：
・Kerasを使ったe-AIチュートリアルなくない？
・mbed OS対応のe-AIサンプルプログラム公開されてる？
・MNISTあきた。。。Fashion-MNIST面白そう。


※筆者はAIについて素人同然なので、この記事にて生じた損害に関し一切の責任を負いません。

#開発環境
~~- Keras(standalone) v2.2.4~~
~~- Tensorflow v1.15.0~~
- TensorFlow-backend 版 Keras v2.2.4-tf（TensorFlow v2.1.0同梱）
~~- e2studio v7.6.0~~
- e2stuio v2021-07
~~- e-AIトランスレータ v1.4.0~~
- e-AIトランスレータ v2.0.0
- GR-PEACH

#実装手順
1. Kerasを用いてFasion-MNISTを学習
2. e-AIトランスレータで学習済みモデルをCソースに変換
3. Fashion-MNISTデータセットからテスト用ファイルを作成
4. GR-PEACH用の推論実行プログラム作成

#Kerasとは
>Kerasは，Pythonで書かれた，TensorFlowまたはCNTK，Theano上で実行可能な高水準のニューラルネットワークライブラリです． Kerasは，迅速な実験を可能にすることに重点を置いて開発されました． アイデアから結果に到達するまでのリードタイムをできるだけ小さくすることが，良い研究をするための鍵になります．（引用元：https://keras.io/ja/ ）

2017年にTensorflowのコアライブラリにおいてKerasをサポートすることが決まったことから、完全にtfに取り込まれてしまった感がある。またTensorflowがv2.xになってから記述のしやすさが評価されているが、これはKerasのおかげと言ってもいいと思う。

Kerasは独立版とTensorflow-backend版がある。どちらを使用してもいいと思うが、以降で紹介するe-AIトランスレータにはバージョンの制約があるので注意したほうが良い。

#Fashion-MNISTとは
Fashion-MNISTは有名なMNISTと同じく28×28 グレースケール画像で60,000サンプルの訓練セットと10,000サンプルのテストセットから成るデータセットである。通常のMNISTは手書き数字画像だが、Fashion-MNISTはTシャツやズボン、靴といった画像で構成されている。クラス数は10である。
Fashio-MNISTが開発された理由として、開発者は「普通のMNISTは簡単すぎるし使われすぎるから真面目な研究者はFashion-MNISTを使うべきだ」と言っている。
詳しくは[こちら](https://github.com/zalandoresearch/fashion-mnist)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199130/7978ae06-f341-47d8-f73b-2add543c5c5d.png)
(引用元：https://github.com/zalandoresearch/fashion-mnist)

#Kerasを用いてFashion-MNISTを学習
**環境構築**
まずは作業環境を構築する必要がある。e-AIトランスレータにはバージョン制約があるので、ユーザーズマニュアル（R20UT4135）に従い構築する。
~~独立型のKerasを使用したくインストールを進めていたが、v2以降のTensorflowではうまく動作しなかった。最終的に筆者の環境では統合前のTensorflow v1.15.0とKeras v2.2.4を使用することでうまく動作した。Anacondaは未使用。~~
Python関連の環境構築は非常に複雑で、投げ出したくなる作業であると思う。今回はe-AIトランスレータのインストールで構築したTensorflow（Keras）環境を使用する。インストール手順はe-AIトランスレータ ユーザーズマニュアル（R20UT4135）の2章を参照し、順番に行って下さい。

学習環境もe-AIトランスレータもだが、うまく動作しないとエラーが出るのでググれば解決策を得ることができる（時間は犠牲になるが）。

**モデル構造**
今回は以下の構造/層で構築した。主に畳み込み層を用いた構成である。
入力層(28*28) → 畳み込み層+Relu → 畳み込み層+Relu → プーリング層 → 畳み込み層+Relu → 全結合層 → 全結合層 → 出力層(10)

※e-AIトランスレータは全ての関数をサポートしているわけではないので、ドキュメントを見ながら対応したモジュールを選択肢して書く必要がある。

**ソースコード**
以下にKerasのソースコードを添付する。
（本ソースコードは下記の文献を参考に作成した。）

``` fashion_mnist_train.py
from tensorflow import keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Flatten
from tensorflow.keras.layers import Conv2D, MaxPooling2D
from tensorflow.keras import backend as K

#kerasのバージョン確認
print(keras.__version__)

#データセット読み込み
fashion_mnist = keras.datasets.fashion_mnist
(train_imgs, train_labels), (test_imgs, test_labels) = fashion_mnist.load_data()

#前処理
train_imgs = train_imgs.reshape(60000, 28, 28, 1)
test_imgs = test_imgs.reshape(10000, 28, 28, 1)
input_shape = (28, 28, 1)
train_imgs = train_imgs.astype('float32')
test_imgs = test_imgs.astype('float32')
train_imgs /= 255
test_imgs /= 255
train_labels = keras.utils.to_categorical(train_labels, 10)
test_labels = keras.utils.to_categorical(test_labels, 10)

#モデルの構築
model = Sequential()
model.add(Conv2D(filters=32, kernel_size=(3, 3), activation='relu', padding='same',　input_shape=input_shape))
model.add(Conv2D(filters=64, kernel_size=(3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D((2,2)))
model.add(Conv2D(filters=32, kernel_size=(3, 3), activation='relu', padding='same'))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(10, activation='softmax'))

#モデルのコンパイル
model.compile(loss='categorical_crossentropy', optimizer=keras.optimizers.Adam(), metrics=['accuracy'])

#モデルの訓練
epochs = 10
batch_size = 128
history = model.fit(train_imgs, train_labels, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(test_imgs, test_labels))

#正解率の評価
scores = model.evaluate(test_imgs, test_labels, verbose=0)
print()
print('Test loss:', scores[0])
print('Test accuracy:', scores[1])

#結果の出力
model.save('./tf_LearnedModel/fashion_MNIST_model.h5')
```

また、以下のコマンドをコマンドプロンプトで実行することでe-AIトランスレータのイントール時に構築した環境を使用し、NN学習を実行することができる。

```
py -3.7 study_mnist.py
```

**学習結果（参考）**
参考までに筆者の環境での学習結果（Loss、Accuracy）を示す。
Test loss: 0.32364662846457215
Test accuracy: 0.9237

#e-AIトランスレータで学習済みモデルをCソースに変換
出力した学習済みAIモデルのファイル（h5ファイル）の選択及び出力場所の選択、各種設定を行う。
（出力先をする必要があるので事前にターゲットボード用プロジェクトを用意しておいた方が良い。）
Translateボタンをタップすると変換される。

最新バーション（v2.0.0）
![fashion_mnist_e-ai_v200.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199130/72c83104-6f10-8e08-a472-d1e6fd04588a.png)
旧バージョン（v1.4.0）
![fashion_mnist_e-ai.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199130/e2e5a82a-5c5b-b149-4356-1e79a576d53f.png)

#Fashion-MNISTデータセットからテスト用ファイルを作成
学習済みAIモデルをCソースに変換できたら推論実行プログラムを作成することになるが、GR-PEACHでカメラ入力は大変そうなので、今回はFashion-MNISTのデータセット（抜粋版）を作成した。
Fashion-MNISTの素の状態はプロテクトされているので、自ら書き出す必要がある。
今回はlabel 0,2,3,5,7,9のデータを適当に1枚づつ引っ張り出し、Cの配列記述に変換した。

作成したファイルを公開しておく。-> [ファイルリンク](https://github.com/omuraisu49/fashion-mnist_dataset_for_e-AI)

#GR-PEACH用の推論実行プログラム作成
最後にGR-PEACH用の推論実行プログラムを作成する。
筆者はmbed OSに慣れているので、mbedに対応したプログラムを作成した。

特に特殊なことはしていないが、GR-PEACHサイトからe2studio用のサンプルプログラムをダウンロード・インポートしAIの処理を付け加えた。

処理内容はシリアルでHelloし、推論を実行、終了したら結果出力、Lチカの流れである。

**ソースコード**
以下にGE-PEACH用のコードを添付する。

``` main.cpp
#include "mbed.h"
#ifdef __cplusplus
extern "C"{
#endif
#include "Typedef.h"
#include "layer_graph.h"
TPrecision* dnn_compute(TPrecision* input_img);
#include "input_data_fashion_mnist.h"
#ifdef __cplusplus
}
#endif

#宣言
DigitalOut led1(LED1);
TPrecision *prediction;
TPrecision *input_img;

int main() {
    printf("fashion-MNIST prediction\r\n");
    
    # label 0 のデータでテスト
    printf("No. 0\r\n");
    input_img = data_fmnist_0;
    t.reset();                // timer reset
    t.start();                // timer start
    prediction = (TPrecision *) dnn_compute(input_img);
    t.stop();                 //timer stop
    printf("time: %f ms\r\n", t.read_ms());      // time printout
    for(int i=0; i<10; i++){
    	printf("%d : %f\r\n", i, prediction[i]);
    }

    # label 3 のデータでテスト
    printf("No. 3\r\n");
    input_img = data_fmnist_3;
    t.reset();                // timer reset
    t.start();                // timer start
    prediction = (TPrecision *) dnn_compute(input_img);
    t.stop();                 // timer stop
    printf("time: %f ms\r\n", t.read_ms());      // time printout
    for(int i=0; i<10; i++){
    	printf("%d : %f\r\n", i, prediction[i]);
    }

    #推論実行後の処理
    wait(0.1);
    while(1) {
        led1 = !led1;
        wait(1);
    }
}
```

作成したらビルドしUSB経由でロードする（数十秒かかるのでひたすら待つ）。
完了したらResetボタンを押し、シリアル出力・LEDを確認する。

#実行結果 on teraterm
参考までにResetボタン操作後のシリアル出力を以下に示す。
（筆者はteratermを使用しているが、好きなターミナルソフトを使うと良い。）
<img width="566" alt="fashion_mnist_result_teraterm.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199130/79d09e68-6407-d277-3389-74b5f0b202a2.png">

思っていたより高速かつ高精度。

ちなみに、Convert OptionはSpeed Priorityに設定しています。RAM Size Priorityの場合、1738msくらいでした。RAMの空き容量と相談して、選択する必要があります。

#感想
今回はKerasで生成したAIモデルをGR-PEACH上で実行した。
作業内容は特に難しいものではないが、Kerasとe-AI要求のバージョン違いで非常に多くの時間を使ってしまった。インストールが済んでしまえばあとはそれを使えばいいので、今後はより迅速に開発できると思う。

易実装性なKerasでモデル作成/学習できるようになったので、今後容易にAIを試せるだろう。

#参考文献
- 「はじめてのニューラルネットワーク：分類問題の初歩」[URL](https://www.tensorflow.org/tutorials/keras/classification?hl=ja)
- 「mnist_cnn.py」[URL](https://github.com/keras-team/keras/blob/master/examples/mnist_cnn.py)
- 「e-AIトランスレータ チュートリアル：GRボードで実行してみよう！」[URL](https://www.renesas.com/jp/ja/products/gadget-renesas/boards/e-ai-translator-tutorial.html)

#更新履歴
2021.09.11 e-AIトラインシュレータ V2.0.0用に内容を更新。過去の内容は取り消し線で残しています。