いよいよDeep Learning の初手であるCNNを見ていきます。

今回対象のコードは下記です。
https://github.com/fchollet/keras/blob/master/examples/mnist_cnn.py

このCNN(Convolutional Neural Network)の登場が今現在のディープラーニングの発展のきっかけになったと考えられます。CNN では、写っている画像の認識(何が写っているのか)を行うことができます。詳細については、下記のリンクを参照してもらえればと思いますが、簡単に言うと、昔は職人技であった画像認識手法やアルゴリズムをニューラルネットワークが大量のデータで学習することで職人技を超えた技術です。
(参考リンク)
http://qiita.com/icoxfog417/items/5fd55fad152231d706c2

CNNでは、以下の処理を行って学習を進めます。

・畳み込み
あらかじめ大量のフィルタを用意。
画像を数ピクセル×数ピクセルの小さな画像に分けて、フィルタと掛け合わせてフィルタ済みの画像を生成します。

・プーリング
フィルタされた画像を圧縮。
良くある手法としては、数ピクセル×数ピクセルで得られたフィルタ済みの画像の中のもっとも大きな画素値を残す処理があります。

この手法によって、様々なフィルタ済みの特徴量を半ば自動的に生成し、ニューラルネットの学習により、どのフィルタがより画像の識別に役に立つフィルタか学習することで、識別率を向上させることができます。

さて、このCNN をKeras ではどのように実装するのか見ていきます。

まずは、データを取得します。MNISTデータを題材に学習するので、画像のサイズは28×28ピクセルです。

<Code>
from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K

batch_size = 128
num_classes = 10
epochs = 12

# input image dimensions
img_rows, img_cols = 28, 28

# the data, shuffled and split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()
</Code>

つぎに、取得したデータをイメージ(N番目)×行×列×チャンネルの配列に整形します。畳み込みニューラルベットワークでは、行列(縦横)の関係を使って、より効率的に学習するので、整形が大事です。

<Code>
if K.image_data_format() == ‘channels_first’:
x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
input_shape = (1, img_rows, img_cols)
else:
x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
input_shape = (img_rows, img_cols, 1)
</Code>

画素値が0から255になっているので、これを0から1に正規化します。また、目的変数をone hot vector に変換します。この処理は、第三回と同様です。

<Code>
x_train = x_train.astype(‘float32’)
x_test = x_test.astype(‘float32’)
x_train /= 255
x_test /= 255
print(‘x_train shape:’, x_train.shape)
print(x_train.shape[0], ‘train samples’)
print(x_test.shape[0], ‘test samples’)

# convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)
</Code>

いよいよ、ネットワークの作成部分です。まずは、畳み込みを行う。3×3ピクセルのフィルタを32枚用意します。さらに、そのフィルタ後の画像をもとに、3×3ピクセルのフィルタを64枚用意します。プーリング処理として、2×2ピクセルのうち、最大値のみ残すMaxPoolingを行います。これでデータを1/4に減らすことができます。あとは、ドロップアウトをしていますが、これは第三回と同じです。Flattenという処理で、多次元の行列を一次元の配列に整形(整形後は9216入力となる)して、128出力のニューラルネットを構成します。最後に128入力、10出力のニューラルネットワークを構成します。10クラス分類問題なのでソフトマックスを行います。

<Code>
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
activation=’relu’,
input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation=’relu’))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation=’relu’))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation=’softmax’))
</Code>

ちょっと入出力がわかりづらいと感じた時は、model.supmmary()を記述することで、入出力の次元を確認できるので便利です。細かい話ではありますが、最初のConv2Dによって、28×28ピクセルは、3×3を確保するために後ろ2ピクセルを無視して、26×26ピクセルで学習を進める様子を確認できます。(次のConv2Dで24×24ピクセルになります。)

最後に学習を行います。ここは第三回と全く同じです。コンパイル関数に、損失関数と最適化手法を選択し、フィット関数で学習データ、検証データを指定し、何回学習させるか指定します。

<Code>
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.Adadelta(),
metrics=[‘accuracy’])

model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
print(‘Test loss:’, score[0])
print(‘Test accuracy:’, score[1])
</Code>

CPUのみで学習すると小一時間は学習時間がかかる処理の重さとなります。これで出来上がったモデルは、99.2%を超える精度を出すことができます。さすがディープラーニングの力ということでしょう。SHIFT特徴量とか過去のものになってしまったんですね。きっと畳み込みフィルタ技術の中に生きているのだと思います。(Sho.)