MNIST vs 俺 (俺の手書き文字を正しく認識できるか)

[2018/9/2更新]

* ソースをGitHubにプッシュしました。 https://github.com/moritalous/mnist_vs_me
* 予測のコードが動かないみたいだったので更新しました。

---

俺とか言ってごめんなさい。

MNISTを元に学習したモデルを使って、私の文字を認識させました。
全部ちゃんと認識できるんですよね？

# ルール

* 正しく認識する  
  →MNISTの勝ち
* 正しく認識しない  
  →私の勝ち（字がヘタって言われている気もしますが。。）

## 学習モデルの生成

kerasにサンプルコードがあったのでそのまま利用。

mnist_cnn.py
https://github.com/keras-team/keras/blob/master/examples/mnist_cnn.py

生成したモデルを保存する1行だけ追加しました。

```python
model.save('mnist_model.h5')
```


学習結果はこちら。見方はよくわかりません。99%正解するってことでしょうか。
詳しい人ヘルプ！

```console
  from ._conv import register_converters as _register_converters
Using TensorFlow backend.
x_train shape: (60000, 28, 28, 1)
60000 train samples
10000 test samples
Train on 60000 samples, validate on 10000 samples
Epoch 1/12
60000/60000 [==============================] - 513s 9ms/step - loss: 0.2750 - acc: 0.9163 - val_loss: 0.0586 - val_acc: 0.9806
Epoch 2/12
60000/60000 [==============================] - 559s 9ms/step - loss: 0.0894 - acc: 0.9734 - val_loss: 0.0464 - val_acc: 0.9850
Epoch 3/12
60000/60000 [==============================] - 688s 11ms/step - loss: 0.0658 - acc: 0.9803 - val_loss: 0.0370 - val_acc: 0.9880
Epoch 4/12
60000/60000 [==============================] - 688s 11ms/step - loss: 0.0542 - acc: 0.9834 - val_loss: 0.0309 - val_acc: 0.9895
Epoch 5/12
60000/60000 [==============================] - 693s 12ms/step - loss: 0.0464 - acc: 0.9858 - val_loss: 0.0318 - val_acc: 0.9889
Epoch 6/12
60000/60000 [==============================] - 674s 11ms/step - loss: 0.0417 - acc: 0.9874 - val_loss: 0.0294 - val_acc: 0.9903
Epoch 7/12
60000/60000 [==============================] - 654s 11ms/step - loss: 0.0365 - acc: 0.9889 - val_loss: 0.0292 - val_acc: 0.9900
Epoch 8/12
60000/60000 [==============================] - 665s 11ms/step - loss: 0.0345 - acc: 0.9893 - val_loss: 0.0287 - val_acc: 0.9908
Epoch 9/12
60000/60000 [==============================] - 772s 13ms/step - loss: 0.0322 - acc: 0.9902 - val_loss: 0.0270 - val_acc: 0.9910
Epoch 10/12
60000/60000 [==============================] - 684s 11ms/step - loss: 0.0306 - acc: 0.9907 - val_loss: 0.0295 - val_acc: 0.9908
Epoch 11/12
60000/60000 [==============================] - 748s 12ms/step - loss: 0.0282 - acc: 0.9912 - val_loss: 0.0272 - val_acc: 0.9911
Epoch 12/12
60000/60000 [==============================] - 657s 11ms/step - loss: 0.0259 - acc: 0.9918 - val_loss: 0.0252 - val_acc: 0.9916
Test loss: 0.025242764521988738
Test accuracy: 0.9916
```




## 予測

以下のコードにて、予測させました。`features.argmax()`を予測した文字としてます。

```python
# coding:utf-8

import keras
import numpy as np
from keras.models import load_model
from keras.preprocessing.image import array_to_img, img_to_array,load_img
import os
import re

model = load_model('mnist_model.h5')

def list_pictures(directory, ext='jpg|jpeg|bmp|png|ppm'):
    return [os.path.join(root, f)
            for root, _, files in os.walk(directory) for f in files
            if re.match(r'([\w]+\.(?:' + ext + '))', f.lower())]

for picture in list_pictures('./tegaki/'):
    X = []
    img = img_to_array(
        load_img(picture, target_size=(28, 28), grayscale=True))
    X.append(img)

    X = np.asarray(X)
    X = X.astype('float32')
    X = X / 255.0

    features = model.predict(X)

    print('----------')
    print(picture)
    print(features.argmax())
    print('----------')
```

## 手書き文字の作成

iPadのGoogle Keepアプリで手書きのメモを作成。pngになったファイルを取得。こんな感じ。

![スクリーンショット (304).png](https://qiita-image-store.s3.amazonaws.com/0/41574/c24086c5-c9e2-ee7a-543b-6400ef35a7c9.png)

MNISTの画像は黒背景に白文字のようなので、ペイントで加工しました。

Windows 7のペイントで画像の色を反転させる方法
https://121ware.com/qasearch/1007/app/servlet/relatedqa?QID=013654

画像のサイズは1694x2048ですが`load_img`のときに画像サイズを変更しているので、そのまま利用しました。

# 試合開始

| 手書き画像 | 予測結果 | 勝敗 |
|---|---|---|
| ![1.png](https://qiita-image-store.s3.amazonaws.com/0/41574/5214c136-ab35-e42e-9123-ec00e4b81857.png) | 1 | MNISTの勝ち |
| ![2.png](https://qiita-image-store.s3.amazonaws.com/0/41574/b635a1bb-62ff-6167-a71a-4b1a8068698f.png) | 2 | MNISTの勝ち |
| ![3.png](https://qiita-image-store.s3.amazonaws.com/0/41574/33aa585a-1f60-1e55-1cfa-f6f087145bdc.png) | 3 | MNISTの勝ち |
| ![4.png](https://qiita-image-store.s3.amazonaws.com/0/41574/a4cdb153-87b2-54e0-781c-3fd5c3563d6c.png) | 4 | MNISTの勝ち |
| ![5.png](https://qiita-image-store.s3.amazonaws.com/0/41574/14a802c5-3f09-3c6c-0dcd-e084153acd89.png) | 5 | MNISTの勝ち |
| ![6.png](https://qiita-image-store.s3.amazonaws.com/0/41574/6f440d4a-8e25-9bd1-2aa4-711a4557323e.png) | 6 | MNISTの勝ち |
| ![7.png](https://qiita-image-store.s3.amazonaws.com/0/41574/da34db01-c5f5-c5a4-a367-6376470c4deb.png) | 1 | 私の勝ち |
| ![8.png](https://qiita-image-store.s3.amazonaws.com/0/41574/12f0e418-872c-85ff-7101-f1936d1a78c4.png) | 5 | 私の勝ち |
| ![9.png](https://qiita-image-store.s3.amazonaws.com/0/41574/d5ce123b-11b7-363c-c1fa-101257111d09.png) | 4 | 私の勝ち |

# 試合結果
6勝3敗でMNISTの勝ち～
でも、3勝もしちゃった。。。
（7と1、8と5、9と4が似てると言われれば似てるような気もしますが。）

試しに画像を予めペイントで28x28にして試しても結果は同じでした。ちゃんと読めますよね？

![スクリーンショット (307).png](https://qiita-image-store.s3.amazonaws.com/0/41574/7027e0f4-acd2-53e2-4c95-5ea54c11dcbb.png)

モデル生成のソースコードに`(there is still a lot of margin for parameter tuning).`とあるので、もっとすごいモデルを使わないといけないのかな？

# 終わりに
あれ、こんなもん？
「ディープラーニングで行うペン習字講座」を期待したのですが先は遠そうです。
まずは「MNISTに勝たせる7の書き方講座」からですね。