kmodelの作成手順を説明したサイトは数少なく、今回は以下のサイトを参考にしました。
DockerHubのtakepwave/maixpyenvイメージを使ってmaixpyenvを起動します。
$ docker run -v `pwd`/workspace:/home/maix/workspace -i --name maixpyenv -t takepwave/maixpyenv
上記の処理で、maixpyenvは実行しますが、一度Docker環境から抜けた場合には、以下のようにして再開します。
$ docker start maixpyenv
$ docker exec -it maixpyenv /bin/bash
準備が整ったので、Maix-TF-workspaceを使ってKmodelを作成してみましょう。
GithubからMaix-TF-workspaceをクローンします。Dockerのシェル環境には、(maix) $をつけて区別します。
(maix) $ cd ~/workspace
(maix) $ git clone https://github.com/sipeed/Maix-TF-workspace.git
(maix) $ cd Maix-TF-workspace/mnist
(maix) $ python mnist.py
次にMaix-TF-workspaceのmnist例題を実行します。maixpyenvには、あらかじめTensorflowをインストールしていますので、すぐに例題を実行できます。mnist.pyの例題が完了するまで、私のMacbook Airで5分程度でした。
(maix) $ cd Maix-TF-workspace/mnist
(maix) $ python mnist.py
途中省略
step 4800, train_accuracy 0.86
step 4900, train_accuracy 0.94
WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow/python/training/saver.py:1276: checkpoint_exists (from tensorflow.python.training.checkpoint_management) is deprecated and will be removed in a future version.
ワーニングが続きます
mnist.pyの例題が完了するとmnist.pbファイルが作成されます。
(maix) $ ls
MNIST_data logs mnist.pb mnist.py model
次にMaix_Toolboxを使って、mnist.pbをkmodelに変換します。
最初にmnist.pbを~/Maix_Toolbox/workspaceにコピーします。
(maix) $ cp mnist.pb ~/Maix_Toolbox/workspace/
~/Maix_Toolbox/に移動して、pb2tflite.shを使って.pbファイルから.tflite形式に変換します。 pb2tflite.shを実行すると以下の項目を入力します。
(maix) $ cd ~/Maix_Toolbox
(maix) $ ./pb2tflite.sh workspace/mnist.pb
This script help you generate cmd to convert *.pb to *.tflite
Please put your pb into workspace dir
1. pb file name: (don't include workspace)
mnist.pb
2. input_arrays name:
inputs
3. output_arrays name:
output
4. input width:
28
5. input height:
28
6. input channel:
1
-----------------------------------
The command you need is:
-----------------------------------
toco --graph_def_file=workspace/mnist.pb --input_format=TENSORFLOW_GRAPHDEF --output_format=TFLITE --output_file=workspace/mnist.tflite --inference_type=FLOAT --input_type=FLOAT --input_arrays=inputs --output_arrays=output --input_shapes=1,28,28,1
以下省略
次にtflite2kmodel.shを使ってtflite形式からkmodelに変換します。
tflite2kmodel.shは、変換を確認するためにテスト用の画像をimagesに入れる必要があります。 このページのgithubのdata/32-dataに10個の画像ファイルがありますので、そちらをimages ディレクトリにコピーします。
以下のコマンドを実行して、kmodelを作成します。途中ワーニングがでますが、workspaceにmnist.kmodelが作成されます。
(maix) $ ./tflite2kmodel.sh workspace/mnist.tflite
uasge: ./tflite2kmodel.sh xxx.tflite
2019-09-07 07:40:18.267350: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA
0: InputLayer -> 1x1x28x28
1: K210Conv2d 1x1x28x28 -> 1x16x14x14
2: K210Conv2d 1x16x14x14 -> 1x32x7x7
3: Dequantize 1x32x7x7 -> 1x32x7x7
4: TensorflowFlatten 1x32x7x7 -> 1x1568
5: FullyConnected 1x1568 -> 1x32
6: Quantize 1x32 -> 1x32
7: K210AddPadding 1x32 -> 1x32x4x4
8: K210Conv2d 1x32x4x4 -> 1x10x4x4
9: K210RemovePadding 1x10x4x4 -> 1x10
10: Dequantize 1x10 -> 1x10
11: Softmax 1x10 -> 1x10
12: OutputLayer 1x10
KPU memory usage: 2097152 B
Main memory usage: 14112 B
(maix) $ ls workspace/
mnist.kmodel mnist.pb mnist.tflite
出来上がったmnist.kmodelを使って、数字の認識を試してみます。
テストには、M5StickVのmaixpyを使います。 SDカードにmnist.kmodelをmn.kmodelというファイル名でコピーし、M5StickVにSDカードを挿入します。
以下のスクリプトを実行します。
import sensor,lcd,image
import KPU as kpu
lcd.init()
lcd.rotation(2)
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((224, 224)) #set to 224x224 input
sensor.set_hmirror(0) #flip camera
task = kpu.load("/sd/mn.kmodel")
sensor.run(1)
def detect():
img = sensor.snapshot()
img0=img.resize(112,112)
lcd.display(img0,oft=(0,0)) #display half picture
img1=img.to_grayscale(1) #convert to gray
img2=img1.resize(28,28) #resize to mnist input 28x28
a=img2.invert() #invert picture as mnist need
a=img2.strech_char(1) #preprocessing pictures, eliminate dark corner
lcd.display(img2,oft=(112,32)) #display small 28x28 picture
a=img2.pix_to_ai(); #generate data for ai
fmap=kpu.forward(task,img2) #run neural network model
plist=fmap[:] #get result (10 digit's probability)
pmax=max(plist) #get max probability
max_index=plist.index(pmax) #get the digit
lcd.draw_string(112,0,"%d: %.3f"%(max_index,pmax),lcd.WHITE,lcd.BLACK) #show result
while True:
detect()
M5StickVを起動すると、以下のようにカメラ画像とそれを28x28の白黒反転させた画像、および認識結果を表示する 画面がでます。
私の手書きした数字を認識させてみました。あまり認識率はよくありませんが、数字は取れているみたいです。
GithubからDocker環境を構築する手順を説明します。
$ git clone https://github.com/take-pwave/maixpy_docker.git
$ cd maixpy_docker
$ docker build -t test/maixpyenv .
無事イメージが作成されたら、以下のコマンドを実行します。
$ mkdir workspace
$ docker run -v `pwd`/workspace:/home/maix/workspace -i --name maixpyenv -t test/maixpyenv