今回はTensorFlowとKerasを使って、畳み込みニューラルネットワーク(CNN)を実装し、画像をカテゴライズする分類器を作る方法を紹介する。
コンテンツ
畳み込みニューラルネットワークとは
CNN(Convolutional Neural Network)はディープラーニングで最もよく使われているもので、主に画像認識のために使われるが、応用として株価などの時系列データを画像と同じように扱うこともできる。
CNNはまず、特徴量の抽出を行う部分と、抽出された特徴量を元に分類を行う部分と大きく二つに分けることができる。
特徴量の抽出を行う部分は、画像に対しフィルタをずらしながらスキャンしていく「畳み込み層」と、畳み込み層で得られた特徴マップを縮小する「プーリング層」で構成され、分類を行う部分は多層パーセプトロンにより処理される。
CNNの特徴量抽出と分類を行う層が隠れ層となり、この層が深く重なり構成されていることがディープラーニングと呼ばれる所以でもある。
データセットの読み込み
今回使用するデータセットは「CIFAR10」と呼ばれるもので、32×32ピクセルの256色カラー画像が60,000枚提供されている。
まずはこのデータセットを読み込もう。
from keras.datasets import cifar10
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
データセットのサイズがとても大きいので、データのダウンロードは少々時間がかかるはずだ。
読み込みが完了したら、Matplotlibを使って画像データを確認してみる。
%matplotlib notebook
from matplotlib import pyplot as plt
print(y_train[49999])
# [1]
plt.imshow(x_train[49999])
plt.show()
CIFAR10で提供されている画像は以下のカテゴリに分かれている。
0 | 飛行機 |
1 | 車 |
2 | 鳥 |
3 | 猫 |
4 | 鹿 |
5 | 犬 |
6 | カエル |
7 | 馬 |
8 | 船 |
9 | トラック |
4行目のプリント分で目的変数の値を出力しており、今回は「1」となっているので、この画像は車の画像だということが分かる。
データの前処理
まず、目的変数となる正解ラベルをOne-Hot形式に変換する。
from keras.utils import np_utils
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
y_train
# array([[0., 0., 0., ..., 0., 0., 0.],
# [0., 0., 0., ..., 0., 0., 1.],
# [0., 0., 0., ..., 0., 0., 1.],
# ...,
# [0., 0., 0., ..., 0., 0., 1.],
# [0., 1., 0., ..., 0., 0., 0.],
# [0., 1., 0., ..., 0., 0., 0.]], dtype=float32)
次に説明変数(色情報)について、RGBそれぞれ256段階の値で構成されているので、これを0〜1の値に変換するため、以下の処理を行う。
x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train = x_train / 255
x_test = x_test / 255
モデルの作成と学習
今回作成するモデルは、畳み込みを行うConv2D関数と、プーリングを行うMaxPooling関数を2回繰り返す。
そして最後の全結合層では、Dense関数を使って多層パーセプトロンを行う。
from keras.models import Sequential
from keras.layers import Dense, Activation, Flatten
from keras.layers import Conv2D, MaxPooling2D
# モデルの作成
model = Sequential()
# 畳み込み・プーリング 1回目
model.add(Conv2D(16, (3, 3),
padding='same',
input_shape=x_train.shape[1:]))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
# 畳み込み・プーリング 2回目
model.add(Conv2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
# 全結合層
model.add(Flatten())
model.add(Dense(300))
model.add(Activation('relu'))
model.add(Dense(10))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='adam', metrics=['accuracy'])
# 学習実行
model.fit(x_train, y_train, batch_size=32, epochs=10, verbose=1)
今回はfit関数のepochsに10を指定した。
本来の画像認識ではこの値を100程度にすることが多いようだが、ディープラーニングには、かなりの時間がかかるのでとりあえずここでは10とする。
コードを実行すると学習の過程が出力される。
モデルの精度を評価する
最後にモデルの精度を評価してみよう。
loss, accuracy = model.evaluate(x_test, y_test, verbose=0)
print('Accuracy', '{:.2f}'.format(accuracy))
# Accuracy 0.70
精度は70%と、まずまずの結果と言える。
最後に一つ、テストデータを予測させてみよう。
適当に11番目のテストデータを予測させてみた。
%matplotlib inline
num = 11
# 0: 飛行機, 1: 自動車, 2: 鳥, 3: 猫, 4: 鹿, 5: 犬, 6: カエル, 7: 馬, 8: 船, 9: トラック
print(model.predict_classes(x_test[num-1:num]))
# [0]
plt.imshow(x_test[num-1])
plt.show()
print分で結果を出力させたところ、「0」と出たので分類は正しく行われている。
まとめ
今回はCNNによる画像認識を実装してみたが、ざっくりとした処理の流れは把握できたはずだ。
ここからは、より高い精度を求めるため、epochsの回数を増やしてみたり、活性化関数を変更したりとチューニングを行う。
また、学習用の画像データに対しても、特徴の捉えやすいデータを使ってみたりと、様々なアプローチをとることで、より高い精度のモデルに仕上げていく。