コケッココケッコ

コケコッコー

お手持ちの画像で画像認識 by using TensorFlow (keras)

概要

手持ちの画像を使って画像認識したいニーズがあったので、Kerasを用いてDeep Learningすることにした。

とはいえ今回はDeep Learningとはいってもすべて全結合、隠れ層の活性化関数にsigmoid関数、出力層にsoftmax関数を用いた簡単なネットワークを作ってみた.

対象

わんこの画像を分類する.

tmp/train, tmp/test にそれぞれ学習画像、テスト画像が入っている。

各画像は以下のように犬 ${犬種}_{$id}.jpg といったファイル名で格納されている.

犬 チワワ1.jpg 犬 柴犬2.jpg

学習データは各犬種につき10枚程度。

ソース

# deep learningしてみるや〜つ
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from keras.optimizers import SGD
import os

from keras.preprocessing.image import img_to_array, load_img
from tensorflow.contrib.keras.python.keras.utils import to_categorical

from src.util.fileutil import FileUtil


class ModelFinder:
    @staticmethod
    def getSimpleModel(n_in, n_hidden, num_hidden, n_out):
        """
        全結合のモデル
        :param n_in: 入力の次元
        :param n_hidden: 隠れ層の次元数
        :param num_hidden: 隠れ層の数
        :param n_out: カテゴリ数
        :return:
        """
        model = Sequential()

        # 入力層 - 隠れ層
        model.add(Dense(n_hidden, input_dim=n_in, activation='sigmoid'))

        # 隠れ層 - 隠れ層
        for i in range(num_hidden-1):
            model.add(Dense(n_hidden, activation='sigmoid'))

        # 隠れ層 - 出力層
        model.add(Dense(n_out, activation='softmax'))

        return model

def loadImg(dir, pic_row, pic_col):
    X_train = []
    Y_cat = []
    for filepath in FileUtil.list_file(dir):
        # 画像を配列にぶち込む.
        filename = os.path.basename(filepath)
        catname = filename.replace('犬 ', '')[:filename.find('_')-len('犬 ')]
        X_train.append(img_to_array(load_img(filepath, target_size=(pic_row, pic_col))).reshape(-1))
        Y_cat.append(catname)

        print("%s %s" % (filepath, catname))
    return (np.array(X_train), Y_cat)

def createCatDic(cats):
    ret = {}
    for cat in cats:
        if cat not in ret:
            ret[cat] = len(ret)
    return ret

if __name__ == '__main__':
    train_dir = '../tmp/train'
    test_dir = '../tmp/test'

    # 隠れ層の次元数
    n_hidden = 128

    # 隠れ層の数 (>=1)
    num_hidden = 1

    # pic_row*pic_col サイズの画像を入力とする
    pic_row = 128
    pic_col = 128
    n_in = pic_row * pic_col * 3 # 3: color. 白黒画像で学習させたいならこいつを1にする

    X_train, Y_train_cat = loadImg(train_dir, pic_row, pic_col)
    cat_dic = createCatDic(Y_train_cat)
    Y_train = to_categorical([cat_dic[cat] for cat in Y_train_cat], len(cat_dic))
    X_test , Y_test_cat = loadImg(test_dir, pic_row, pic_col)
    Y_test = to_categorical([cat_dic[cat] for cat in Y_test_cat], len(cat_dic))

    # カテゴリ数
    n_out = len(cat_dic)

    model = ModelFinder.getSimpleModel(n_in, n_hidden, num_hidden, n_out)
    model.compile(loss='categorical_crossentropy',
                  optimizer=SGD(lr=0.01),
                  metrics=['accuracy'])

    # モデル学習
    epochs = 10000
    batch_size = min(100, len(X_train))

    model.fit(X_train, Y_train, epochs=epochs, batch_size=batch_size)

    # 予測精度の評価
    loss_and_metrics = model.evaluate(X_test, Y_test)
    print(loss_and_metrics) # 2番目にaccuracyが入っている.

結果

27/27 [==============================] - 0s - loss: 0.5093 - acc: 0.7778
Epoch 9999/10000
27/27 [==============================] - 0s - loss: 0.5093 - acc: 0.7778
Epoch 10000/10000
27/27 [==============================] - 0s - loss: 0.5093 - acc: 0.7778
14/14 [==============================] - 0s
[1.4256515502929688, 0.3571428656578064]

学習データだとaccuracy: 81.15% テストデータだと35.71%と辛い感じ。

隠れ層の次元を増やしていったときの精度を見る。 隠れ層の数n_dim = 2

27/27 [==============================] - 0s - loss: 0.3749 - acc: 0.8519
Epoch 10000/10000
27/27 [==============================] - 0s - loss: 0.3749 - acc: 0.8519
14/14 [==============================] - 0s
[1.4254211187362671, 0.5]

隠れ層を2つにしたら50%に上昇。

Epoch 9999/10000
27/27 [==============================] - 0s - loss: 0.0981 - acc: 1.0000
Epoch 10000/10000
27/27 [==============================] - 0s - loss: 0.0981 - acc: 1.0000
14/14 [==============================] - 0s
[2.0662350654602051, 0.42857146263122559]

隠れ層を3つにしたら過学習したっぽいwwつらい

Epoch 9998/10000
27/27 [==============================] - 0s - loss: 0.6240 - acc: 0.7407
Epoch 9999/10000
27/27 [==============================] - 0s - loss: 0.6239 - acc: 0.7407
Epoch 10000/10000
27/27 [==============================] - 0s - loss: 0.6238 - acc: 0.7407
14/14 [==============================] - 0s
[1.3305658102035522, 0.21428573131561279]

隠れ層を4つにしたらさらに精度が落ちた。

考察

学習データの数が足りなさすぎると思われるので、回転させたりして画像を水増ししてみよう。 各画像(X_train, X_test)は255で割って正規化したほうがいいらしい。 勾配消失問題への対処としてReLUを使ってみるか。 画像認識の十八番CNNも試してみるか〜。

正直テストデータで精度90%ぐらい出てもらわないと困るぞぅ。

参考書籍

詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~

詳解 ディープラーニング ~TensorFlow・Kerasによる時系列データ処理~