TensorFlow2 + Keras で画像分類に挑戦 CNN編1 ～とりあえず動かす～

# はじめに
TensorFlow2 + Keras による画像分類の勉強メモ（**<font color='red'>CNN編</font>**の第1弾）です。MLP編（多層パーセプトロンモデル編）については、[こちら](https://qiita.com/code0327/items/7d3c7bd3327ff049243a)をご覧ください。

なお、題材はド定番である**手書き数字画像（MNIST）**の分類です。

今回は、ブラックボックスのまま、とりあえずCNNモデルを学習させて、それを使って予測（分類）をしてみます。

# MLP版のプログラム

**多層パーセプトロンモデル**による手書き数字画像（MNIST）分類は、TensorFlow2 + Keras を利用して、次のように書くことができました（[詳細](https://qiita.com/code0327/items/7d3c7bd3327ff049243a)）。

```py:TensorFlow2に切り替え（GoogleColab.環境のみ）
%tensorflow_version 2.x
```

```py:MLPによる画像分類
import tensorflow as tf

# (1) 手書き数字画像のデータセットをダウンロード・正規化
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# (2) MLPモデルを構築
model = tf.keras.models.Sequential()
model.add( tf.keras.layers.Flatten(input_shape=(28, 28)) )
model.add( tf.keras.layers.Dense(128, activation='relu') )
model.add( tf.keras.layers.Dropout(0.2) )
model.add( tf.keras.layers.Dense(10, activation='softmax') )

# (3) モデルのコンパイル・トレーニング
model.compile(optimizer='Adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5)

# (4) モデルの評価
model.evaluate(x_test,  y_test, verbose=2)
```

これを実行すると、<font color='red'>正解率 $97.7\%$ 前後の分類器</font>をつくることができました。

# CNN版のプログラム

**畳み込みニューラルネットワークモデル（CNN）**による手書き数字画像（MNIST）分類は、次のように書くことができます。多層パーセプトロンのモデルに、なんと3行追加するだけで畳み込みニューラルネットワークモデルに変えることができます。

```py:CNNによる画像分類
# (1) 手書き数字画像のデータセットをダウンロード・正規化
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# (2) CNNモデルを構築
model = tf.keras.models.Sequential()
model.add( tf.keras.layers.Reshape((28, 28, 1), input_shape=(28, 28)) ) # 追加
model.add( tf.keras.layers.Conv2D(32, (5, 5), activation='relu') )      # 追加
model.add( tf.keras.layers.MaxPooling2D(pool_size=(2,2)) )              # 追加
model.add( tf.keras.layers.Flatten() )                                  # 改変
model.add( tf.keras.layers.Dense(128, activation='relu') )
model.add( tf.keras.layers.Dropout(0.2) )
model.add( tf.keras.layers.Dense(10, activation='softmax') )

# (3) モデルのコンパイル・トレーニング
model.compile(optimizer='Adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5)

# (4) モデルの評価
model.evaluate(x_test,  y_test, verbose=2)
```

これを実行すると、<font color='red'>正解率 $98.7\%$ 前後の分類器</font>をつくることができます（上記のMLPよりも正解率が約$1\%$ほど高いモデルをつくることができます）。ただし、学習にかかる時間は長くなっています。

## 正しく予測できなかった事例

**分類（予測）に失敗している具体的なケース**を見てみます（これを出力するためのプログラムは「[～分類に失敗する画像を観察してみる～](https://qiita.com/code0327/items/5dfc1b2ed143c1f9bd2b)」を参照）。

各図の左上に表示している赤文字は、**誤って何の数字と予測したか**という情報です（括弧内数値は、誤った予測に対するsoftmax出力）。例えば <font color='red'>5(0.9)</font> は、「約 $90\%$ の確信をもって $5$ と予測した」ということです。また、<font color='blue'>青色の数値</font>は、テストデータ `test_x` のインデックス番号です。

### 正解値「0」について正しく予測（分類）できなかったケース 4/980件
![0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/e7b8f83d-1b74-66fe-0adb-bbe08213eaa3.png)

### 正解値「1」について正しく予測（分類）できなかったケース 4/1135件
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/2333cca0-9008-350a-f98e-3dde1f7bbdf1.png)

### 正解値「2」について正しく予測（分類）できなかったケース 8/1032件
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/4bc67344-08d7-a5a9-9479-ccfd9fb06e5b.png)

### 正解値「3」について正しく予測（分類）できなかったケース 12/1010件
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/c30ec8be-3dff-3987-cd91-b079d977ce9e.png)

### 正解値「4」について正しく予測（分類）できなかったケース 15/982件
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/9bb3ebaa-e574-0734-6c14-372660a90be4.png)

### 正解値「5」について正しく予測（分類）できなかったケース 6/892件
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/23659faf-d29a-5733-b2c7-a72f8d10c213.png)

### 正解値「6」について正しく予測（分類）できなかったケース 13/958件
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/a373b410-4837-6f16-8113-321e77ac0d96.png)

### 正解値「7」について正しく予測（分類）できなかったケース 15/1028件
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/5aaba0eb-1df0-0740-ea03-ff5db5730a1a.png)

### 正解値「8」について正しく予測（分類）できなかったケース 27/974件
![8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/f51a0ba3-fd06-7ac6-3d75-02c24de71ab7.png)

### 正解値「9」について正しく予測（分類）できなかったケース 26/1009件
![9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/77183307-2a7c-fa86-01b1-d7d0260b8856.png)


# 次回

**畳み込みニューラルネットワークモデル（CNN）**は、なんで画像分類・画像認識に適しているのか、そもそも畳み込み（フィルタ）とは？といった内容を取り上げていきたいと思います。