２クラス分類から多クラス分類への変更

[前回](https://qiita.com/yakisobamilk/items/686d6ad5ae3285aec639)、自分のデータセットで品と不良品の判別をやってみました。
前回は『PythonとKerasによるディープラーニング』のサンプルに忠実に2クラス分類でやりましたが、今回は出力に「良品」と「不良品」の2つを独立して設定し、どうなるのか試してみました。
実装上の違いは

- モデルの最終層のカテゴリ数が1 → 2
- モデルの最終層の活性化関数がsigmoid → softmax
- 損失関数がbinary_crossentropy → categorical_crossentropy
- ImageDataGeneratorのオプションclass_modeがbinary → categorical

です。

使用するデータセットは[前回](https://qiita.com/yakisobamilk/items/686d6ad5ae3285aec639)と同じで、モデル構成やハイパーパラメータも極力同じにしました。

## モデル定義

モデル定義の部分は下記のように変更しました。

```python
# モデルの定義
model = models.Sequential()
model.add(layers.Conv2D(16, (3, 3), activation='relu', input_shape=(120, 40, 1)))
model.add(layers.Conv2D(16, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(32, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Flatten())
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(256, activation='relu'))
#model.add(layers.Dense(1, activation='sigmoid'))        # ひとまず犬猫と同じ2クラス分類で
model.add(layers.Dense(2, activation='softmax'))         # 今回は多クラス分類で

# モデルのコンパイル
#model.compile(loss='binary_crossentropy',
model.compile(loss='categorical_crossentropy',
              optimizer=optimizers.RMSprop(lr=1e-4),
              metrics=['acc'])
```

`model.summary()`で確認すると次のようになります。

```
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 118, 38, 16)       160       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 116, 36, 16)       2320      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 58, 18, 16)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 56, 16, 32)        4640      
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 28, 8, 32)         0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 7168)              0         
_________________________________________________________________
dense_1 (Dense)              (None, 512)               3670528   
_________________________________________________________________
dense_2 (Dense)              (None, 256)               131328    
_________________________________________________________________
dense_3 (Dense)              (None, 2)                 514       
=================================================================
Total params: 3,809,490
Trainable params: 3,809,490
Non-trainable params: 0
_________________________________________________________________
```

[前回](https://qiita.com/yakisobamilk/items/686d6ad5ae3285aec639#%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AE%E5%AE%9A%E7%BE%A9)と比較すると、最終層のパラメータが増えていることが確認できます。

## ImageDataGeneratorの準備

多クラス分類では正解ラベルの与え方も変わるので変更が必要です。

```python
# すべての画像を1/255でスケーリング
train_datagen = ImageDataGenerator(rescale=1./255)
test_datagen = ImageDataGenerator(rescale=1./255)

# ImageDataGeneratorを使ってディレクトリから画像を読み込む（リスト5-7）
train_generator = train_datagen.flow_from_directory(
    train_dir,                      # ターゲットディレクトリ
    target_size=(120, 40),          # すべての画像サイズを120*40に変更
    color_mode='grayscale',
    batch_size=20,                  # バッチサイズ
#   class_mode='binary')            # binary_crossentropyを使用するため2値のラベルが必要
    class_mode='categorical')       # categoricalに変更
validation_generator = test_datagen.flow_from_directory(
    validation_dir,
    target_size=(120, 40),
    color_mode='grayscale',
    batch_size=20,
    class_mode='categorical')
```

## モデルの学習

前回からの変更点は以上です。
これで学習を実行したところ、次のような結果となりました。
前回同様、今回も高い精度が出て、うまくいったようです。

```python
 88/100 [=========================>....] - ETA: 0s - loss: 0.0222 - acc: 0.9966
 90/100 [==========================>...] - ETA: 0s - loss: 0.0219 - acc: 0.9967
 92/100 [==========================>...] - ETA: 0s - loss: 0.0235 - acc: 0.9962
 94/100 [===========================>..] - ETA: 0s - loss: 0.0266 - acc: 0.9952
 96/100 [===========================>..] - ETA: 0s - loss: 0.0262 - acc: 0.9953
 98/100 [============================>.] - ETA: 0s - loss: 0.0259 - acc: 0.9954
100/100 [==============================] - 4s 43ms/step - loss: 0.0271 - acc: 0.9950 - val_loss: 0.0270 - val_acc: 0.9970
```

![Figure_1.png](https://qiita-image-store.s3.amazonaws.com/0/280874/55f6dd7e-a4e8-d97e-2f6a-c3ce358ded29.png)
![Figure_2.png](https://qiita-image-store.s3.amazonaws.com/0/280874/13ba04f0-08b3-8790-8f30-a066508337c7.png)