【Python/Keras】CNNとCIFAR-10で画像認識・分類

Pythonの機械学習モジュール「Keras」でCNN(畳み込みニューラルネットワーク)を実装し、CIFAR-10を学習して画像認識・分類する方法をソースコード付きでまとめました。

CNNとCIFAR-10で画像認識・分類

CIFAR-10とは、画像分類用のデータセットです。
詳細は以下の通り。

説明
画像サイズ 32×32[px]
形式 カラー画像(24bitカラー)
クラスラベル airplane(飛行機), automobile(自動車), bird(鳥), cat(猫), deer(鹿), dog(犬), frog(蛙), horse(馬), ship(船), truck(トラック)の10種類
データ量 訓練用データ5万枚、テスト用データ1万枚
関連ページ CIFAR-10公式サイト【Python/Keras】CIFAR-10のデータセットをダウンロード【CNN】畳み込みニューラルネットワークの原理・仕組み

今回は、Python3 + KerasでCNN(畳み込みニューラルネットワーク)を構築し、データセット「CIFAR-10」を学習させてみました。

サンプルコード

サンプルプログラムのソースコードです。

①学習

CIFAR-10のデータセットを使って学習を行い、学習結果を保存します。

# -*- coding: utf-8 -*-
from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPool2D
from keras.layers.core import Dense,Activation,Dropout,Flatten
from keras.datasets import cifar10
from keras.utils import np_utils

# モデル構築
def build_model():
    # CNNのモデル構築
    model = Sequential()
    model.add(Conv2D(32,(3,3), padding='same', input_shape=(32,32,3)))
    model.add(Activation('relu'))
    model.add(Conv2D(32,(3,3),padding='same'))
    model.add(Activation('relu'))
    model.add(MaxPool2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Conv2D(64,(3,3),padding='same'))
    model.add(Activation('relu'))
    model.add(Conv2D(64,(3,3),padding='same'))
    model.add(Activation('relu'))
    model.add(MaxPool2D(pool_size=(2,2)))
    model.add(Dropout(0.25))

    model.add(Flatten())
    model.add(Dense(512))
    model.add(Activation('relu'))
    model.add(Dropout(0.5))
    model.add(Dense(10, activation='softmax'))

    return model

def main():
    # CIFAR-10のデータセットを取得
    (x_train, y_train),(x_test,y_test) = cifar10.load_data()
    
    # 画像データの正規化
    x_train = x_train.astype('float32')/255.0
    x_test = x_test.astype('float32')/255.0

    # 教師データ, テストデータ(正解ラベル)をクラスベクトルに変換
    y_train = np_utils.to_categorical(y_train, 10)
    y_test = np_utils.to_categorical(y_test, 10)

    # CNNのモデル構築
    model = build_model()

    # モデルをコンパイル
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

    # 学習
    history = model.fit(x_train,y_train, batch_size=128, nb_epoch=20, verbose=1, validation_split=0.1)

    # モデルと重みを保存
    open('cifar10.json',"w").write(model.to_json())
    model.save_weights('cifar10.h5')

    # モデルの詳細表示
    model.summary()

    # モデルの性能評価
    score = model.evaluate(x_test, y_test, verbose=0)
    print('Test loss:', score[0]) # Test loss: 0.683512847137
    print('Test accuracy:', score[1]) # Test accuracy: 0.7871
    plot(model, show_shapes=True, show_layer_names=True, to_file='model.png')

    # 学習履歴を保存
    json.dump(history.history, open("history.json", "w"))

if __name__ == '__main__':
    main()
生成したファイル
1 cifar10.json
2 cifar.h5
3 history.json

②予測

①で保存した学習データを使って、10枚の画像を分類してみます。

# -*- coding: utf-8 -*-
import numpy as np
from keras.models import Sequential, model_from_json
from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPool2D
from keras.layers.core import Dense,Activation,Dropout,Flatten
from keras.datasets import cifar10
from keras.utils import np_utils
from keras.layers.core import Dense
from keras.optimizers import RMSprop

def main():
    # CIFAR-10のデータセットを取得
    (x_train, y_train),(x_test,y_test) = cifar10.load_data()
    
    # 画像データの正規化
    x_test = x_test.astype('float32')/255.0

    # 教師データ, テストデータ(正解ラベル)をクラスベクトルに変換
    y_test = np_utils.to_categorical(y_test, 10)

    # モデルの読み込み
    model = model_from_json(open('cifar10.json', 'r').read())

    # 重みの読み込み
    model.load_weights('cifar10.h5')

    # コンパイル
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

    # 10枚(0~9番目)のテスト画像を入力し、予測結果を出力
    y_pred = model.predict(x_test[0:10])

    # 出力をベクトルから整数値に変換
    y_pred = np.argmax(y_pred, axis=1)
    y_test = np.argmax(y_test[0:10], axis=1)

    # 予測結果と実際の答えを比較(入力画像10枚分)
    print('予測:', y_pred) # 予測: [3 8 8 0 6 6 1 2 3 1]
    print('正解:', y_test) # 正解: [3 8 8 0 6 6 1 6 3 1]


if __name__ == '__main__':
    main()

8枚目以外の画像は正しく分類できました。

③外部画像を入力

試しに、データセットにない画像をネットから拾って画像認識を試してみます。
※下記の飛行機画像を与えてみました

# -*- coding: utf-8 -*-
import numpy as np
from keras.models import Sequential, model_from_json
from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPool2D
from keras.layers.core import Dense,Activation,Dropout,Flatten
from keras.datasets import cifar10
from keras.utils import np_utils
from keras.layers.core import Dense
from keras.optimizers import RMSprop
from keras.preprocessing.image import load_img
from keras.preprocessing.image import load_img, img_to_array

def main():
    # ラベル
    label =['飛行機', '自動車', '鳥', '猫', '鹿', '犬', '蛙', '馬', '船', 'トラック']

    # 画像の読み込み(32×32にリサイズ)
    img = load_img("input.jpg", target_size=(32, 32))
    img = img_to_array(img) 

    # 画像データの正規化
    img = img.astype('float32')/255.0
    img = np.array([img]) # 4次元配列にしないと入力できない

    # モデルの読み込み
    model = model_from_json(open('cifar10.json', 'r').read())

    # 重みの読み込み
    model.load_weights('cifar10.h5')

    # コンパイル
    model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

    # 10枚(0~9番目)のテスト画像を入力し、予測結果を出力
    y_pred = model.predict(img)

    # 出力をクラスベクトルから整数値に変換
    y_pred = np.argmax(y_pred, axis=1)

    # 予測結果の表示
    print('予測結果:', label[int(y_pred)]) # 飛行機


if __name__ == '__main__':
    main()

無事、飛行機と認識できました。

関連記事
1 Python入門 基本文法
2 【Python/Keras】ディープラーニング入門・使い方
関連記事