画像分類のためのCNN(1)(初心者向け)

実務では取り扱えていないが、学習として記録に残す。
今回は、畳み込みニューラルネットワーク(CNN)
画像認識の解析に有効らしい...

## CNN
通常のニューラルネットワークに加え、畳み込みの層とプーリング層があることがポイント。

#畳み込み
画像から特徴をデータ化する部分で一番の肝。
画像データは、5×5×1のデータ。
３×3×3のカーネルで重みづけを設定し、全てのパターンの計算をする。以下の図では9パターン。
その結果を特徴マップという。
<img width="602" alt="スクリーンショット 2020-01-31 8.35.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351494/25e6c41e-ca15-10e6-ea46-6225e795587d.png">



#プーリング
プーリングとは、大きな画像を重要な情報を残しつつ縮小する方法。
これによって、データの次元を減らして、計算速度を抑え学習を進めることができる。
<img width="599" alt="スクリーンショット 2020-01-31 8.56.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351494/e7f4b2fa-b647-c7c2-4eef-9ac42460b250.png">
2つ種類がある
・maxプーリング
　→カーネル中の最大値をさいようする
・avgプーリング
　→カーネル中の全ての数字の平均値をさいようする
##具体的データ次元削減(=圧縮方法)
畳みこみにより、画像データはカーネルの大きさの中で計算を行い特徴量を新たに取り出すことで次元数が削減される(=圧縮される)
式だと、以下。
<img width="374" alt="スクリーンショット 2020-03-08 16.15.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351494/b480cd29-64f5-025e-924c-beb6fb8b8039.png">
プーリングにより、特徴をより強調しつつデータを圧縮していく。方法は、カーネル中の最大値をさいようするか、平均値をさいようするか

##サンプルを動かす
MNISTデータセットを使う。

```python
%matplotlib inline
import keras
from keras.datasets import mnist
import matplotlib.pyplot as plt

#データの読み込み。学習データと訓練データに分割
(x_train, y_train), (x_test, y_test) = mnist.load_data()

#MNISTデータの表示
fig = plt.figure(figsize=(9, 9))
fig.subplots_adjust(left=0, right=1, bottom=0, top=0.5, hspace=0.05, wspace=0.05)
for i in range(81):
    ax = fig.add_subplot(9, 9, i + 1, xticks=[], yticks=[])
    ax.imshow(x_train[i].reshape((28, 28)), cmap='gray')
```
こんな感じで出る。
<img width="607" alt="スクリーンショット 2020-04-16 8.29.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351494/ef2527c2-9db2-fe61-89a8-1f2293222a2e.png">



```python

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
img_rows, img_cols = 28, 28

(x_train, y_train), (x_test, y_test) = mnist.load_data()

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)

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')

y_train = y_train.astype('int32')
y_test = y_test.astype('int32')
y_train = keras.utils.np_utils.to_categorical(y_train, num_classes)
y_test =  keras.utils.np_utils.to_categorical(y_test, num_classes)

#畳みこみからプーリングに通している部分
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'))

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))
```

##まとめ
概念的イメージは整理できた。

## 参考
[畳み込みニューラルネットワークの仕組み]
(https://postd.cc/how-do-convolutional-neural-networks-work/)
[画像処理でよく使われる畳み込みニューラルネットワークとは]
(https://kenyu-life.com/2019/03/07/convolutional_neural_network/)