kerasを使って手書き数字画像の予測(mnist)

前回、kerasとmnistを使ってディープラーニングを試しました。前回は結果予測にmnistのテストデータを用いましたが、今回は更に発展して、画像ファイルを読み込んで予測してみます。

前回

前回の内容は以下のページに記載しています。

準備

今回は画像ファイルの操作のためにOpenCVとPillow(PIL)という画像を扱うライブラリを使います。まずは、そのインストールをしておきます。

(venv) $ pip install opencv-python
Collecting opencv-python
  Downloading opencv_python-4.3.0.36-cp37-cp37m-macosx_10_9_x86_64.whl (52.6 MB)
     |████████████████████████████████| 52.6 MB 12.2 MB/s
Requirement already satisfied: numpy>=1.14.5 in /usr/local/lib/python3.7/site-packages (from opencv-python) (1.18.4)
Installing collected packages: opencv-python
Successfully installed opencv-python-4.3.0.36
WARNING: You are using pip version 20.1; however, version 20.1.1 is available.
You should consider upgrading via the '/usr/local/opt/python/bin/python3.7 -m pip install --upgrade pip' command.
(venv) $
(venv) $ pip install Pillow
Collecting Pillow
  Downloading Pillow-7.2.0-cp37-cp37m-macosx_10_10_x86_64.whl (2.2 MB)
     |████████████████████████████████| 2.2 MB 552 kB/s
Installing collected packages: Pillow
Successfully installed Pillow-7.2.0
WARNING: You are using pip version 20.1; however, version 20.1.1 is available.
You should consider upgrading via the '/usr/local/opt/python/bin/python3.7 -m pip install --upgrade pip' command.
(venv) $

なお、前提として以下の後の話になるので、上記だけで足りない場合は以下も参考にその他のライブラリなどのインストールをしてもらえればと思います。

作成ソース

今回は以下のようなソースを作成しました。

import numpy as np
from PIL import Image, ImageOps
from keras.models import load_model

# メソッド定義(指定したファイルを予測)
def predict_classes(im_file):
    # 画像ファイル読み込み
    im = Image.open(im_file)

    # 画像ファイル変換
    im = im.resize((28, 28)) # サイズ調整
    im = im.convert('L')     # 白黒変換
    im = ImageOps.invert(im) # 値反転

    # 画像データから検証データ作成
    x = np.array(im)        # NumPy配列に
    x = x.reshape(1, 784)   # 28*28 -> 784
    x = x.astype('float32') # intからfloatに
    x /= 255                # 0-1の範囲のfloatに

    # 訓練済みモデル読み込み
    model_file = 'my_model.h5'
    model = load_model(model_file)

    # 予測
    predict_y = model.predict_classes(x)
    print('--------')
    print('テスト対象', im_file)
    print('予測ラベル', predict_y)

# 実行
predict_classes('images/image_0.jpg')
predict_classes('images/image_1.jpg')
predict_classes('images/image_2.jpg')
predict_classes('images/image_3.jpg')
predict_classes('images/image_4.jpg')
predict_classes('images/image_5.jpg')
predict_classes('images/image_6.jpg')
predict_classes('images/image_7.jpg')
predict_classes('images/image_8.jpg')
predict_classes('images/image_9.jpg')

「images」フォルダ配下に「image_0.jpg」のような名前で画像ファイルを配置しています。添字の数値がそれぞれの数値の画像データになっています。

2020/08/30 追記:最新環境で実行してみたところ、警告が出るようになっていました。「predict_classes」は非推奨になっているので注意してください。また「load_model」についても、以下のようにメソッドの外側で読み込むように変更した方が良いようです。モジュールの読み込みが何度も実行されるため負荷がかかるようです。

model_file = 'my_model.h5'
model = load_model(model_file)
predict_classes(model, 'images/image_0.jpg')
predict_classes(model, 'images/image_1.jpg')

解説

画像ファイル読み込み

最初の部分は画像ファイルの読み込みです。PILを使ってファイルを読み込んでいます。ファイル名(パス)の「im_file」は関数の呼び出し元から受け取るようにしています。

    im = Image.open(im_file)

画像ファイル変換

次に読み込んだ画像ファイルをモデルで検証するために変換しています。

    im = im.resize((28, 28)) # サイズ調整

上記で行なっているのはサイズ調整です。mnistで訓練したモデルは28×28の画像ファイルを対象に作成しているので、サイズを合わせています。

    im = im.convert('L')     # 白黒変換

上記では白黒に変換(グレースケール)しています。そのままだとRGBになるので、mnistに合わせて白黒にしています。

    im = ImageOps.invert(im) # 値反転

上記は値を反転しています。mnistの画像データは白が0で黒が255になっていますが、読み込んだ画像ファイルだと逆に白が255で黒が0になっているようなので、値を反転させています。

なお、ここの処理の順序は精度に影響があると思いますが詳細は未検証です。私の感覚でこの順序(サイズ→白黒→反転)にしていますが、他の順序の方が良いかもしれません。

検証データ作成

次に訓練済みモデルに適用できるように検証データを作成します。

まず、以下でNumPyの配列として読み込み、reshapeで28×28の行列から要素784のベクトルに変換しています。

    x = np.array(im)        # NumPy配列に
    x = x.reshape(1, 784)   # 28*28 -> 784

次に以下で0-255の整数値から0-1の小数に変換しています。

    x = x.astype('float32') # intからfloatに
    x /= 255                # 0-1の範囲のfloatに

訓練済みモデルの読み込み

次に訓練済みのモデルを読み込みます。

    model_file = 'my_model.h5'
    model = load_model(model_file)

これは前回実施した訓練後のモデルに対して

model.save('my_model.h5')

のように実行して保存したファイルを読み込んでいます。

予測

最後に結果のラベルを予測します。

    predict_y = model.predict_classes(x)
    print('--------')
    print('テスト対象', im_file)
    print('予測ラベル', predict_y)

前回は「predict」で結果を見ていたのですが「predict_classes」というより適切なメソッドがあったので、そちらを使っています。「predict」だと10要素のベクトルで結果が表示されますが、「predict_classes」だと結果のラベルが表示されます。

実行結果

今回のプログラム(ソース)を実行した結果が以下となります。

(venv) $ python main.py
Using TensorFlow backend.
--------
テスト対象 images/image_0.jpg
予測ラベル [0]
--------
テスト対象 images/image_1.jpg
予測ラベル [1]
--------
テスト対象 images/image_2.jpg
予測ラベル [2]
--------
テスト対象 images/image_3.jpg
予測ラベル [3]
--------
テスト対象 images/image_4.jpg
予測ラベル [4]
--------
テスト対象 images/image_5.jpg
予測ラベル [5]
--------
テスト対象 images/image_6.jpg
予測ラベル [6]
--------
テスト対象 images/image_7.jpg
予測ラベル [7]
--------
テスト対象 images/image_8.jpg
予測ラベル [8]
--------
テスト対象 images/image_9.jpg
予測ラベル [9]
(venv) $

一通り予想通りの結果になりました。ただ、これは画像にもよるので、どのような画像で予測をしたかは最後に作成物のリンクを張っているので、そちらで確認してください。

作成物

作成物は以下に置いています。なお、訓練済みモデルのファイルは更新するかもしれないので、テンプレート形式にしています。実際に試してみたい場合はファイル名をリネームしてから実行してください。

https://github.com/masaki-code/python/tree/master/public/mnist_predict_file

追記(2020/09/01)

その後、Webブラウザ上でマウスなどで描いた画像を予測することをしてみました。以下にまとめています。

コメント

タイトルとURLをコピーしました