NeuroWhAI의 잡블로그

[Keras] CNN으로 MNIST 이미지 분류하기 본문

개발 및 공부/라이브러리&프레임워크

[Keras] CNN으로 MNIST 이미지 분류하기

NeuroWhAI 2018. 3. 4. 16:01


※ 이 글은 '코딩셰프의 3분 딥러닝 케라스맛'이라는 책을 보고 실습한걸 기록한 글입니다.


코드:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#-*- coding: utf-8 -*-
 
import numpy as np
import keras
from keras import layers, models, datasets, backend
from keras.utils import np_utils
import matplotlib.pyplot as plt
 
class CNN(models.Sequential):
    def __init__(self, input_shape, num_classes):
        super().__init__()
 
        self.add(layers.Conv2D(32, kernel_size=(33),
            activation='relu', input_shape=input_shape))
        self.add(layers.Conv2D(64, (33), activation='relu'))
        self.add(layers.MaxPooling2D(pool_size=(22)))
        self.add(layers.Dropout(0.25))
        self.add(layers.Flatten())
        self.add(layers.Dense(128, activation='relu'))
        self.add(layers.Dropout(0.5))
        self.add(layers.Dense(num_classes, activation='softmax'))
 
        self.compile(loss=keras.losses.categorical_crossentropy,
            optimizer='rmsprop', metrics=['accuracy'])
 
class DataML():
    def __init__(self):
        (x_train, y_train), (x_test, y_test) = datasets.mnist.load_data()
 
        y_train = np_utils.to_categorical(y_train)
        y_test = np_utils.to_categorical(y_test)
 
        img_rows, img_cols = x_train.shape[1:]
 
        if backend.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.0
        x_test /= 255.0
 
        self.input_shape = input_shape
        self.num_classes = 10
        self.x_train, self.y_train = x_train, y_train
        self.x_test, self.y_test = x_test, y_test
 
def plot_loss(history):
    plt.plot(history.history['loss'])
    plt.plot(history.history['val_loss'])
    plt.title('Model Loss')
    plt.ylabel('Loss')
    plt.xlabel('Epoch')
    plt.legend(['Train''Test'], loc=0)
 
def plot_acc(history):
    plt.plot(history.history['acc'])
    plt.plot(history.history['val_acc'])
    plt.title('Model accuracy')
    plt.ylabel('Accuracy')
    plt.xlabel('Epoch')
    plt.legend(['Train''Test'], loc=0)
 
def main():
    batch_size = 100
    epochs = 10
 
    data = DataML()
    model = CNN(data.input_shape, data.num_classes)
 
    history = model.fit(data.x_train, data.y_train, epochs=epochs,
        batch_size=batch_size, validation_split=0.2, verbose=2)
 
    performance_test = model.evaluate(data.x_test, data.y_test, batch_size=100,
        verbose=0)
    print('\nTest Result ->', performance_test)
 
    plot_acc(history)
    plt.show()
    plot_loss(history)
    plt.show()
 
if __name__ == '__main__':
    main()
cs

결과:
Train on 48000 samples, validate on 12000 samples
Epoch 1/10
 - 269s - loss: 0.2463 - acc: 0.9250 - val_loss: 0.0692 - val_acc: 0.9806
Epoch 2/10
 - 263s - loss: 0.0958 - acc: 0.9719 - val_loss: 0.0610 - val_acc: 0.9826
(중략)
Epoch 9/10
 - 268s - loss: 0.0724 - acc: 0.9798 - val_loss: 0.0534 - val_acc: 0.9868
Epoch 10/10
 - 265s - loss: 0.0778 - acc: 0.9795 - val_loss: 0.0655 - val_acc: 0.9856
Test Result -> [0.058471008204469398, 0.9862000066041946]


제 구린 서버에서 10 에포크 돌리는데 1시간이나 걸려서 너무 슬픕니다 ㅠㅠ
나중에 Paperspace 서버 구매하면 GPU 버전을 꼭 돌려보고 말겁니다 ㅂㄷㅂㄷ

결과에서 눈에 띄는건 드롭아웃을 적용해서 그런건진 몰라도 학습할때의 정확도보다 검증시의 정확도가 더 높게 나왔다는 점?

아래는 간략한 설명입니다.

layers.Conv2D로 컨볼루션 계층을 만듭니다.
커널 개수, 커널 크기 정도가 눈에 띄네요.
기본 스트라이드는 (1, 1)이고 패딩은 valid(패딩 없음) 입니다.

layers.MaxPooling2D로 풀링 계층을 만듭니다.
기본적으로 2x2 크기 입니다.

Dropout을 적용해서 과적합에서 벗어나도록 했습니다.

layers.Flatten으로 출력 데이터를 펴준뒤 FC 레이어(Dense)에 넣습니다.

Optimizer는 rmsprop을 사용했는데 왜 이걸 사용했는진 잘 모르겠습니다.
이것저것 바꿔보면서 나온 결과겠죠.

그 외에 자잘한건 넘어가고 마지막으로 눈에 띄는건
keras.backend의 사용입니다.
backend.image_data_format() 함수로 케라스의 기반 라이브러리가 어떤 이미지 데이터 포맷을 사용하는지 알 수 있답니다.
그러니까 채널이 먼저 나오는지 마지막에 나오는지를 알 수 있죠.
그걸 가지고 MNIST 데이터를 다른 Shape으로 reshape하고 있습니다.

이거 외엔 딱히 별거 없네요.

다음은 또 CNN인데 CIFAR-10 데이터로 한다고 합니다.
글을 쓸지 안쓸지는 얼마나 코드가 달라지느냐에 달렸습니다 ㅋㅋ...





Comments