keras による fashion MNIST の3層ニューラルネットワークとCNN(畳み込みニューラルネットワーク)解析

# はじめに
本記事は Udemy の [【4日で体験しよう！】 TensorFlow, Keras, Python 3 で学ぶディープラーニング体験講座](https://www.udemy.com/tensorflow/) の内容を参考に同様の内容をAmazon SageMakerで実行する記事となります。

環境準備 : [SageMaker での環境構築と keras による MNIST の3層ニューラルネットワーク解析](https://qiita.com/NendaiHiroki/items/e5d78e5a0c7903bc41e1)
分析実行 : keras による fashion MNIST の3層ニューラルネットワークとCNN(畳み込みニューラルネットワーク)解析　←(本稿)

# fashion MNIST
衣料品画像60,000枚と、テスト画像10,000枚を集めた、画像データセットです。
衣料品ラベルは整数の配列で、0から9です。これらは画像が表わす衣料品のクラスに対応します。
<img width="305" alt="01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390035/76f8b3ad-9893-8294-e14a-2d7e813abb14.png">

# 3層のニューラルネットワーク解析
新しくノートブックを作成して、コードを書きます。
その1の手順と同じように new から conda_tensorflow_p36 を選択して、名前を付けましょう。
私はfusion_MNIST_3layersと名前を付けました。

処理内容は MNIST とほとんど変わらないので、簡単に記述します。

#### モジュールのインポートと設定

```Python
from tensorflow import keras
import matplotlib.pyplot as plt
%matplotlib inline
```

#### fashion MNISTデータのダウンロード

```Python
(x_train,y_train),(x_test,y_test) = keras.datasets.fashion_mnist.load_data()
```

#### データの確認
- fashion MNISTの画像も28x28の二次元配列になっています。
- 各要素は0~255の値を取っていて、色が黒に近いほうが数が大きくなります。

```Python
x_train[0]
```

実行結果

```
array([[  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,
          0,   0,  13,  73,   0,   0,   1,   4,   0,   0,   0,   0,   1,
          1,   0],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   3,
          0,  36, 136, 127,  62,  54,   0,   0,   0,   1,   3,   4,   0,
          0,   3],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   6,
          0, 102, 204, 176, 134, 144, 123,  23,   0,   0,   0,   0,  12,
         10,   0],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0, 155, 236, 207, 178, 107, 156, 161, 109,  64,  23,  77, 130,
         72,  15],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   0,
         69, 207, 223, 218, 216, 216, 163, 127, 121, 122, 146, 141,  88,
        172,  66],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   0,
        200, 232, 232, 233, 229, 223, 223, 215, 213, 164, 127, 123, 196,
        229,   0],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        183, 225, 216, 223, 228, 235, 227, 224, 222, 224, 221, 223, 245,
        173,   0],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
        193, 228, 218, 213, 198, 180, 212, 210, 211, 213, 223, 220, 243,
        202,   0],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   3,   0,  12,
        219, 220, 212, 218, 192, 169, 227, 208, 218, 224, 212, 226, 197,
        209,  52],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   6,   0,  99,
        244, 222, 220, 218, 203, 198, 221, 215, 213, 222, 220, 245, 119,
        167,  56],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   4,   0,   0,  55,
        236, 228, 230, 228, 240, 232, 213, 218, 223, 234, 217, 217, 209,
         92,   0],
       [  0,   0,   1,   4,   6,   7,   2,   0,   0,   0,   0,   0, 237,
        226, 217, 223, 222, 219, 222, 221, 216, 223, 229, 215, 218, 255,
         77,   0],
       [  0,   3,   0,   0,   0,   0,   0,   0,   0,  62, 145, 204, 228,
        207, 213, 221, 218, 208, 211, 218, 224, 223, 219, 215, 224, 244,
        159,   0],
       [  0,   0,   0,   0,  18,  44,  82, 107, 189, 228, 220, 222, 217,
        226, 200, 205, 211, 230, 224, 234, 176, 188, 250, 248, 233, 238,
        215,   0],
       [  0,  57, 187, 208, 224, 221, 224, 208, 204, 214, 208, 209, 200,
        159, 245, 193, 206, 223, 255, 255, 221, 234, 221, 211, 220, 232,
        246,   0],
       [  3, 202, 228, 224, 221, 211, 211, 214, 205, 205, 205, 220, 240,
         80, 150, 255, 229, 221, 188, 154, 191, 210, 204, 209, 222, 228,
        225,   0],
       [ 98, 233, 198, 210, 222, 229, 229, 234, 249, 220, 194, 215, 217,
        241,  65,  73, 106, 117, 168, 219, 221, 215, 217, 223, 223, 224,
        229,  29],
       [ 75, 204, 212, 204, 193, 205, 211, 225, 216, 185, 197, 206, 198,
        213, 240, 195, 227, 245, 239, 223, 218, 212, 209, 222, 220, 221,
        230,  67],
       [ 48, 203, 183, 194, 213, 197, 185, 190, 194, 192, 202, 214, 219,
        221, 220, 236, 225, 216, 199, 206, 186, 181, 177, 172, 181, 205,
        206, 115],
       [  0, 122, 219, 193, 179, 171, 183, 196, 204, 210, 213, 207, 211,
        210, 200, 196, 194, 191, 195, 191, 198, 192, 176, 156, 167, 177,
        210,  92],
       [  0,   0,  74, 189, 212, 191, 175, 172, 175, 181, 185, 188, 189,
        188, 193, 198, 204, 209, 210, 210, 211, 188, 188, 194, 192, 216,
        170,   0],
       [  2,   0,   0,   0,  66, 200, 222, 237, 239, 242, 246, 243, 244,
        221, 220, 193, 191, 179, 182, 182, 181, 176, 166, 168,  99,  58,
          0,   0],
       [  0,   0,   0,   0,   0,   0,   0,  40,  61,  44,  72,  41,  35,
          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0],
       [  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
          0,   0]], dtype=uint8)
```

- x_train に60000個の画像データがあることを確認します。

```Python
x_train.shape
```

実行結果

```
(60000, 28, 28)
```

- 試しに画像を10個表示します。

```Python
for i in range(10):
    plt.subplot(2,5,i+1)
    plt.title("Label :"+ str(y_train[i]))
    plt.imshow(x_train[i].reshape(28,28))
```

実行結果
<img width="232" alt="02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390035/ae8f5587-8663-efef-b9e7-523ee1616b41.png">


#### データの加工
- 0~255の数を訓練向けに0～1の値に変換するために、各要素を255で割ります。

```Python
x_train, x_test = x_train/255.0, x_test/255.0
```

#### ニューラルネットワークの層を定義

```Python
model = keras.models.Sequential([
    keras.layers.Flatten(),
    keras.layers.Dense(512,activation = "relu"),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(10,activation = "softmax")    
])
```

#### ニューラルネットワークの訓練課程の設定

```Python
model.compile(optimizer="adam",loss="sparse_categorical_crossentropy",metrics=["accracy"])
```

#### モデルの作成
- train データを使用して、モデルの作成を行います。

```Python
model.fit(x_train,y_train,epochs = 10)
```

実行経過

```
Epoch 1/10
60000/60000 [==============================] - 11s 185us/sample - loss: 0.4997 - acc: 0.8197
Epoch 2/10
60000/60000 [==============================] - 11s 180us/sample - loss: 0.3826 - acc: 0.8606
Epoch 3/10
60000/60000 [==============================] - 11s 183us/sample - loss: 0.3524 - acc: 0.8716
Epoch 4/10
60000/60000 [==============================] - 11s 184us/sample - loss: 0.3277 - acc: 0.8788
Epoch 5/10
60000/60000 [==============================] - 11s 184us/sample - loss: 0.3137 - acc: 0.8837
Epoch 6/10
60000/60000 [==============================] - 11s 180us/sample - loss: 0.3007 - acc: 0.8876
Epoch 7/10
60000/60000 [==============================] - 11s 187us/sample - loss: 0.2906 - acc: 0.8914
Epoch 8/10
60000/60000 [==============================] - 11s 186us/sample - loss: 0.2787 - acc: 0.8963
Epoch 9/10
60000/60000 [==============================] - 11s 183us/sample - loss: 0.2689 - acc: 0.8988
Epoch 10/10
60000/60000 [==============================] - 11s 186us/sample - loss: 0.2635 - acc: 0.9008
```

#### 精度の確認
- test データを使用して、モデルの精度を確認します。


```Python
model.evaluate(x_test,y_test)
```

実行結果

```
10000/10000 [==============================] - 1s 54us/sample - loss: 0.3342 - acc: 0.8829

[0.33415236022472383, 0.8829]
```

- MNIST では98.1％という精度でしたが、fashion MNIST では88.3%に留まりました。
- 精度を上げるために、CNN(畳み込みニューラルネットワーク) という手法を試してみます。


# CNN(畳み込みニューラルネットワーク)
新しくノートブックを作成して、コードを書きます。
その1の手順と同じように new から conda_tensorflow_p36 を選択して、名前を付けましょう。
私はfusion_MNIST_CNNと名前を付けました。

#### モジュールのインポートと設定

```Python
import tensorflow
from tensorflow import keras
import matplotlib.pyplot as plt
%matplotlib inline
```

#### データのダウンロード

```Python
(x_train,y_train),(x_test,y_test) = keras.datasets.fashion_mnist.load_data()
```

#### データの変換

- 変換のためにデータのカラーチャネルの位置を取得します。

```Python
keras.backend.image_data_format()
```

実行結果

```
'channels_last'
```

- カラーチャネルの情報は最後にあることがわかったので、それに合わせてデータを変換します。

```Python
x_train = x_train.reshape(x_train.shape[0],28,28,1)
x_test= x_test.reshape(x_test.shape[0],28,28,1)
```

- データを0～255の値から、学習用に0～1の値に変換する。

```Python
x_train, x_test = x_train/255.0, x_test/255.0
```

#### CNN の層を定義
- 3*3のフィルタを32種使用して、28*28*1の入力データを26*26*32にします。活性化関数には relu を使用します。
- 3*3のフィルタを64種使用して、26*26*32の入力データを24*24*64にします。活性化関数には relu を使用します。
- 24*24*64の入力データを12*12*64にします。
- 入力を25%Dropout(無視)します。
- 2次元の入力データを1次元にします。
- 128個のノードに全結合します。活性化関数には relu を使用します。
- 入力を50%Dropout(無視)します。
- 10個のノードに全結合します。活性化関数には softmax を使用します。

```Python
model = keras.models.Sequential([
  keras.layers.Conv2D(32,kernel_size = (3,3),
                        activation = "relu",
                        input_shape = (28,28,1)),
  keras.layers.Conv2D(64,(3,3),activation = "relu"),
  keras.layers.MaxPooling2D(pool_size=(2,2)),
  keras.layers.Dropout(0.25),
  keras.layers.Flatten(),
  keras.layers.Dense(128,activation="relu"),
  keras.layers.Dropout(0.5),
  keras.layers.Dense(10,activation = "softmax")
])
```

#### CNN の訓練課程の設定
- 最適化手法は Adam を使用。
- 損失関数は sparse_categorical_crossentropy を使用。
- metrics に accuracy を設定することで、評価を記録するようにします。

```Python
model.compile(optimizer="adam",loss="sparse_categorical_crossentropy",metrics=["accracy"])
```

#### モデルの作成
- train データを使用して、モデルの作成を行います。
- epoch は訓練データを繰り返し学習する回数を指定します。
- バッチサイズは未設定で32となります。

```Python
model.fit(x_train,y_train,epochs = 10)
```

#### 備考
- メモリが32GB以上のインスタンスサイズに変更しないと処理が完了しません。
- インスタンスタイプを今まで使用していたml.t2.mediumからml.t2.2xlargeにアップデートすることで処理を完了できます。
- またml.t2.2xlargeからGPUインスタンスのml.p2.xlargeを使用することで処理速度が向上します。
- ml.t2.meidum を利用した場合は以下のエラーが表示されます。
- <img width="416" alt="03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390035/5b0e0b94-5de8-bf23-b583-5193a22a741a.png">

モデル作成の実行結果

```
Epoch 1/10
60000/60000 [==============================] - 37s 617us/sample - loss: 0.4796 - acc: 0.8298
Epoch 2/10
60000/60000 [==============================] - 14s 235us/sample - loss: 0.3222 - acc: 0.8842
Epoch 3/10
60000/60000 [==============================] - 14s 233us/sample - loss: 0.2750 - acc: 0.9001
Epoch 4/10
60000/60000 [==============================] - 14s 234us/sample - loss: 0.2448 - acc: 0.9106
Epoch 5/10
60000/60000 [==============================] - 14s 234us/sample - loss: 0.2215 - acc: 0.9178
Epoch 6/10
60000/60000 [==============================] - 14s 234us/sample - loss: 0.2005 - acc: 0.9261
Epoch 7/10
60000/60000 [==============================] - 14s 234us/sample - loss: 0.1887 - acc: 0.9304
Epoch 8/10
60000/60000 [==============================] - 14s 233us/sample - loss: 0.1763 - acc: 0.9346
Epoch 9/10
60000/60000 [==============================] - 14s 234us/sample - loss: 0.1620 - acc: 0.9388
Epoch 10/10
60000/60000 [==============================] - 14s 235us/sample - loss: 0.1549 - acc: 0.9424
```


#### 精度の確認
- test データを使用して、モデルの精度を確認します。


```Python
model.evaluate(x_test,y_test)
```

実行結果

- 今回、精度は92.5%ほどでした。  
- 先ほどの3層ニューラルネットワークでは、精度が88.3％ほどだったので、うまく精度を上げることができました。

```
10000/10000 [==============================] - 1s 101us/sample - loss: 0.2280 - acc: 0.9258

[0.22800267367660998, 0.9258]
```

# おわりに
今回は、kerasを使って、fashion MNIST データを2つの手法で解析しました。

この記事はここまでとさせていただきます。
今後も、引き続き学習ログなど上げていきますので、よろしくお願いいたします。