합성곱 신경망을 사용한 이미지 분류

패션 MNIST 데이터 불러오기

In [1]:
from tensorflow import keras
from sklearn.model_selection import train_test_split

(train_input, train_target), (test_input, test_target) = \
    keras.datasets.fashion_mnist.load_data()

train_scaled = train_input.reshape(-1, 28, 28, 1) / 255.0

train_scaled, val_scaled, train_target, val_target = train_test_split(
    train_scaled, train_target, test_size=0.2, random_state=42)
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
32768/29515 [=================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26427392/26421880 [==============================] - 1s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
8192/5148 [===============================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4423680/4422102 [==============================] - 0s 0us/step

합성곱 신경망 만들기

In [2]:
model = keras.Sequential()
In [3]:
model.add(keras.layers.Conv2D(32, kernel_size=3, activation='relu', 
                              padding='same', input_shape=(28,28,1)))
In [4]:
model.add(keras.layers.MaxPooling2D(2))
In [5]:
model.add(keras.layers.Conv2D(64, kernel_size=(3,3), activation='relu', 
                              padding='same'))
model.add(keras.layers.MaxPooling2D(2))
In [6]:
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(100, activation='relu'))
model.add(keras.layers.Dropout(0.4))
model.add(keras.layers.Dense(10, activation='softmax'))
In [7]:
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 28, 28, 32)        320       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 14, 14, 32)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 14, 14, 64)        18496     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 7, 7, 64)          0         
_________________________________________________________________
flatten (Flatten)            (None, 3136)              0         
_________________________________________________________________
dense (Dense)                (None, 100)               313700    
_________________________________________________________________
dropout (Dropout)            (None, 100)               0         
_________________________________________________________________
dense_1 (Dense)              (None, 10)                1010      
=================================================================
Total params: 333,526
Trainable params: 333,526
Non-trainable params: 0
_________________________________________________________________
In [8]:
keras.utils.plot_model(model)
Out[8]:
In [9]:
keras.utils.plot_model(model, show_shapes=True, to_file='cnn-architecture.png', dpi=300)
Out[9]:

모델 컴파일과 훈련

In [10]:
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', 
              metrics='accuracy')

checkpoint_cb = keras.callbacks.ModelCheckpoint('best-cnn-model.h5', 
                                                save_best_only=True)
early_stopping_cb = keras.callbacks.EarlyStopping(patience=2,
                                                  restore_best_weights=True)

history = model.fit(train_scaled, train_target, epochs=20,
                    validation_data=(val_scaled, val_target),
                    callbacks=[checkpoint_cb, early_stopping_cb])
Epoch 1/20
1500/1500 [==============================] - 36s 3ms/step - loss: 0.5223 - accuracy: 0.8119 - val_loss: 0.3308 - val_accuracy: 0.8744
Epoch 2/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.3400 - accuracy: 0.8781 - val_loss: 0.2821 - val_accuracy: 0.8956
Epoch 3/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.2915 - accuracy: 0.8939 - val_loss: 0.2502 - val_accuracy: 0.9061
Epoch 4/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.2586 - accuracy: 0.9057 - val_loss: 0.2412 - val_accuracy: 0.9090
Epoch 5/20
1500/1500 [==============================] - 5s 3ms/step - loss: 0.2358 - accuracy: 0.9143 - val_loss: 0.2195 - val_accuracy: 0.9179
Epoch 6/20
1500/1500 [==============================] - 5s 3ms/step - loss: 0.2154 - accuracy: 0.9202 - val_loss: 0.2275 - val_accuracy: 0.9165
Epoch 7/20
1500/1500 [==============================] - 4s 3ms/step - loss: 0.1961 - accuracy: 0.9268 - val_loss: 0.2292 - val_accuracy: 0.9170
In [11]:
import matplotlib.pyplot as plt
In [12]:
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['train', 'val'])
plt.show()
In [13]:
model.evaluate(val_scaled, val_target)
375/375 [==============================] - 1s 2ms/step - loss: 0.2195 - accuracy: 0.9179
Out[13]:
[0.2194737195968628, 0.9179166555404663]
In [14]:
plt.imshow(val_scaled[0].reshape(28, 28), cmap='gray_r')
plt.show()
In [15]:
preds = model.predict(val_scaled[0:1])
print(preds)
[[1.8246358e-13 8.6280835e-21 8.9756789e-16 1.5351074e-15 7.8192093e-15
  1.3402502e-11 2.1972722e-14 2.4236521e-10 1.0000000e+00 1.5653938e-11]]
In [16]:
plt.bar(range(1, 11), preds[0])
plt.xlabel('class')
plt.ylabel('prob.')
plt.show()
In [17]:
classes = ['티셔츠', '바지', '스웨터', '드레스', '코트',
           '샌달', '셔츠', '스니커즈', '가방', '앵클 부츠']
In [18]:
import numpy as np
print(classes[np.argmax(preds)])
가방
In [19]:
test_scaled = test_input.reshape(-1, 28, 28, 1) / 255.0
In [20]:
model.evaluate(test_scaled, test_target)
313/313 [==============================] - 1s 3ms/step - loss: 0.2404 - accuracy: 0.9124
Out[20]:
[0.2403760552406311, 0.9124000072479248]