LeNet CNN (Convolution Neural Network) 케라스 파이썬 치트코드

기본적인 딥러닝 모델을 케라스로 쉽게 구현할수 있습니다. 몇개의 파라미터를 고쳐가면서 해보면, 99%이상의 정확도를 얻을 수 있습니다.

LeNet CNN

LeNet을 이용한 기본적인 CNN (Deep Convolution Neural Network) 구축하기

  • 케라스를 이용하면 단 몇가지 코드로 신경망을 구축할 수 있다.
In [1]:
from keras import backend
from keras.models import Sequential
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.layers.core import Activation, Flatten, Dense
from keras.utils import np_utils
from keras.optimizers import SGD, RMSprop, Adam
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
Using TensorFlow backend.
  • dataset은 mnist를 이용한 데이터셋이다.
In [2]:
from keras.datasets import mnist
  • ordering 은 tf의 경우 채널이 나중에 넣는다. 예를들어 이미지가 2828이라면, 2828*1로 넣으면 되고, th는 반대다.
In [3]:
backend.set_image_dim_ordering("tf")

데이터셋 로드

In [4]:
(train_x_ori, train_y_ori), (test_x_ori, test_y_ori) = mnist.load_data()
In [5]:
plt.imshow(train_x_ori[1], cmap='Greys')
Out[5]:
<matplotlib.image.AxesImage at 0x276b75a3048>
In [6]:
plt.imshow(train_x_ori[5], cmap='Greys')
Out[6]:
<matplotlib.image.AxesImage at 0x276b763c240>
In [7]:
train_x_ori = train_x_ori.astype('float32')
test_x_ori = test_x_ori.astype('float32')

스케일을 조정하고, 채널정보를 추가

  • 그림이 3차원이 아닌 이유는, 채널정보가 있기 때문이다. 채널정보는 그레이스케일의 경우 1, RGB일 경우 3으로 조정하면 된다.
In [8]:
train_x = train_x_ori / 255
test_x = test_x_ori / 255
train_x = train_x[:, :, :,np.newaxis,]
test_x = test_x[:, :, :, np.newaxis]
  • 1차원이 늘어난것을 알수있다.
In [9]:
train_x.shape
Out[9]:
(60000, 28, 28, 1)

y 라벨의 경우도 교체

  • 각각 y라벨의 경우도 원핫 인코딩 형식으로 변환해 주어야 한다. 0~9정수는 못읽음
In [11]:
train_y = np_utils.to_categorical(train_y_ori, 10)
test_y = np_utils.to_categorical(test_y_ori, 10)
In [12]:
train_y.shape
Out[12]:
(60000, 10)

LeNet 모델 만들기

  • 딥러닝은 피처를 추출하는것이 관건이며, feature를 추출하기위해 Conv2D를 이용해 컨볼루션 필터를 적용한다.
  • 그리고 특정한 신경이 활성화된다면 (relu), 이에 대해서 중요한 정보만 추출하게 되는 MaxPooling2D를 이용한다.
  • 최종적으로는 골라내야하는 손글씨 종류가 10개기 때문에 softmax로 확률값을 총 10개를 추출한다.
In [13]:
class LeNet : 
    @staticmethod
    def build(input_shape, classes):
        model = Sequential()
        model.add(Conv2D(20, kernel_size = 5, padding="same", input_shape=input_shape))
        model.add(Activation("relu"))
        model.add(MaxPooling2D(pool_size = (2,2), strides = (2,2)))
        model.add(Conv2D(50, kernel_size = 5, padding="same"))
        model.add(Activation("relu"))
        model.add(MaxPooling2D(pool_size = (2,2), strides = (2,2)))
        model.add(Flatten())
        model.add(Dense(500))
        model.add(Activation("relu"))
        model.add(Dense(10))
        model.add(Activation("softmax"))
        return model
In [14]:
model = LeNet.build(input_shape = (28, 28, 1), classes = 10)
WARNING:tensorflow:From C:\Users\kohry\anaconda3\lib\site-packages\tensorflow\python\framework\op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Colocations handled automatically by placer.
In [15]:
model.compile(loss = "categorical_crossentropy", optimizer=Adam(), metrics=["accuracy"])
In [16]:
history = model.fit(train_x, train_y, batch_size=256, epochs=10, verbose=1, validation_split=0.2)
WARNING:tensorflow:From C:\Users\kohry\anaconda3\lib\site-packages\tensorflow\python\ops\math_ops.py:3066: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use tf.cast instead.
Train on 48000 samples, validate on 12000 samples
Epoch 1/10
48000/48000 [==============================] - 8s 169us/step - loss: 0.2501 - acc: 0.9253 - val_loss: 0.0797 - val_acc: 0.9766
Epoch 2/10
48000/48000 [==============================] - 2s 51us/step - loss: 0.0594 - acc: 0.9822 - val_loss: 0.0524 - val_acc: 0.9844
Epoch 3/10
48000/48000 [==============================] - 3s 54us/step - loss: 0.0383 - acc: 0.9880 - val_loss: 0.0400 - val_acc: 0.9883
Epoch 4/10
48000/48000 [==============================] - 3s 55us/step - loss: 0.0296 - acc: 0.9907 - val_loss: 0.0434 - val_acc: 0.9859
Epoch 5/10
48000/48000 [==============================] - 3s 56us/step - loss: 0.0231 - acc: 0.9925 - val_loss: 0.0393 - val_acc: 0.9888
Epoch 6/10
48000/48000 [==============================] - 3s 55us/step - loss: 0.0180 - acc: 0.9940 - val_loss: 0.0390 - val_acc: 0.9888
Epoch 7/10
48000/48000 [==============================] - 3s 54us/step - loss: 0.0131 - acc: 0.9957 - val_loss: 0.0365 - val_acc: 0.9906
Epoch 8/10
48000/48000 [==============================] - 3s 56us/step - loss: 0.0118 - acc: 0.9966 - val_loss: 0.0389 - val_acc: 0.9903
Epoch 9/10
48000/48000 [==============================] - 3s 56us/step - loss: 0.0082 - acc: 0.9976 - val_loss: 0.0357 - val_acc: 0.9903
Epoch 10/10
48000/48000 [==============================] - 3s 55us/step - loss: 0.0076 - acc: 0.9975 - val_loss: 0.0393 - val_acc: 0.9895
In [17]:
score = model.evaluate(test_x, test_y, verbose=1)
10000/10000 [==============================] - 1s 78us/step

최종 정확도

In [18]:
print("최종 정확도 : " + str( score[1] * 100 ) + " %" )
최종 정확도 : 99.1 %
  • 최종정확도는 epoch가 거듭될수록 좋아지는것을 확인가능하다.
In [19]:
plt.plot(history.history['acc'])
Out[19]:
[<matplotlib.lines.Line2D at 0x276b74e61d0>]
  • 중요한건 validation셋에 대한 정확도가 더 중요하다.
In [20]:
plt.plot(history.history['val_acc'])
Out[20]:
[<matplotlib.lines.Line2D at 0x276b7546470>]

다른방법으로, 프로세스 이해하기

  • 우리가 지금까지 진행했던건 너무 당연하게 여겨지는 노말라이제이션과 relu를 이용했는데, 다른 방법을 이용해서 나온 결과는 어떨지 확인해보자
  • 스케일을 조정하지 않으면 어떨까? 1로 나누면, 아무 스케일링이 없다.
In [21]:
train_x = train_x_ori / 1
test_x = test_x_ori / 1
train_x = train_x[:, :, :,np.newaxis,]
test_x = test_x[:, :, :, np.newaxis]
In [22]:
history = model.fit(train_x, train_y, batch_size=256, epochs=10, verbose=1, validation_split=0.2)
Train on 48000 samples, validate on 12000 samples
Epoch 1/10
48000/48000 [==============================] - 2s 52us/step - loss: 12.5458 - acc: 0.2215 - val_loss: 14.5143 - val_acc: 0.0995
Epoch 2/10
48000/48000 [==============================] - 3s 56us/step - loss: 14.5301 - acc: 0.0985 - val_loss: 14.5143 - val_acc: 0.0995
Epoch 3/10
48000/48000 [==============================] - 3s 54us/step - loss: 14.5301 - acc: 0.0985 - val_loss: 14.5143 - val_acc: 0.0995
Epoch 4/10
48000/48000 [==============================] - 3s 56us/step - loss: 14.5301 - acc: 0.0985 - val_loss: 14.5143 - val_acc: 0.0995
Epoch 5/10
48000/48000 [==============================] - 3s 57us/step - loss: 14.5301 - acc: 0.0985 - val_loss: 14.5143 - val_acc: 0.0995
Epoch 6/10
48000/48000 [==============================] - 3s 56us/step - loss: 14.5301 - acc: 0.0985 - val_loss: 14.5143 - val_acc: 0.0995
Epoch 7/10
48000/48000 [==============================] - 3s 56us/step - loss: 14.5301 - acc: 0.0985 - val_loss: 14.5143 - val_acc: 0.0995
Epoch 8/10
48000/48000 [==============================] - 3s 55us/step - loss: 14.5301 - acc: 0.0985 - val_loss: 14.5143 - val_acc: 0.0995
Epoch 9/10
48000/48000 [==============================] - 3s 56us/step - loss: 14.5301 - acc: 0.0985 - val_loss: 14.5143 - val_acc: 0.0995
Epoch 10/10
48000/48000 [==============================] - 3s 57us/step - loss: 14.5301 - acc: 0.0985 - val_loss: 14.5143 - val_acc: 0.0995
In [23]:
score = model.evaluate(test_x, test_y, verbose=1)
10000/10000 [==============================] - 1s 89us/step
  • 스케일이 제대로 조정되지 않으면 최종정확도는 당연히 모델이 제대로 훈련되지 않아 똥인것을 알수있습니다.
In [25]:
print("최종 정확도 : " + str( score[1] * 100 ) + " %" )
최종 정확도 : 9.8 %
In [49]:
train_x = train_x_ori / 255
test_x = test_x_ori / 255
train_x = train_x[:, :, :,np.newaxis,]
test_x = test_x[:, :, :, np.newaxis]

여러가지 파라미터 교체

  • optimizer를 RMSprop
  • activation function tanh로 모델교체
  • convolution layer를 한층으로,
  • dense layer 50개
  • pool과 stride를 교체
In [65]:
class LeNet : 
    @staticmethod
    def build(input_shape, classes):
        model = Sequential()
        model.add(Conv2D(10, kernel_size = 5, padding="same", input_shape=input_shape))
        model.add(Activation("tanh"))
        model.add(MaxPooling2D(pool_size = (3,3), strides = (3,3)))
        model.add(Flatten())
        model.add(Dense(50))
        model.add(Activation("tanh"))
        model.add(Dense(10))
        model.add(Activation("softmax"))
        return model
In [66]:
model = LeNet.build(input_shape = (28, 28, 1), classes = 10)
In [67]:
model.compile(loss = "categorical_crossentropy", optimizer=RMSprop(), metrics=["accuracy"])
In [68]:
history = model.fit(train_x, train_y, batch_size=256, epochs=10, verbose=1, validation_split=0.2)
Train on 48000 samples, validate on 12000 samples
Epoch 1/10
48000/48000 [==============================] - 2s 50us/step - loss: 0.5478 - acc: 0.8603 - val_loss: 0.2327 - val_acc: 0.9311
Epoch 2/10
48000/48000 [==============================] - 2s 37us/step - loss: 0.1821 - acc: 0.9476 - val_loss: 0.1370 - val_acc: 0.9605
Epoch 3/10
48000/48000 [==============================] - 2s 34us/step - loss: 0.1179 - acc: 0.9664 - val_loss: 0.0999 - val_acc: 0.9718
Epoch 4/10
48000/48000 [==============================] - 2s 32us/step - loss: 0.0885 - acc: 0.9748 - val_loss: 0.0856 - val_acc: 0.9759
Epoch 5/10
48000/48000 [==============================] - 2s 35us/step - loss: 0.0710 - acc: 0.9803 - val_loss: 0.0742 - val_acc: 0.9790
Epoch 6/10
48000/48000 [==============================] - 2s 37us/step - loss: 0.0594 - acc: 0.9825 - val_loss: 0.0689 - val_acc: 0.9799
Epoch 7/10
48000/48000 [==============================] - 2s 36us/step - loss: 0.0514 - acc: 0.9852 - val_loss: 0.0653 - val_acc: 0.9809
Epoch 8/10
48000/48000 [==============================] - 2s 34us/step - loss: 0.0448 - acc: 0.9876 - val_loss: 0.0587 - val_acc: 0.9826
Epoch 9/10
48000/48000 [==============================] - 2s 35us/step - loss: 0.0398 - acc: 0.9889 - val_loss: 0.0558 - val_acc: 0.9841
Epoch 10/10
48000/48000 [==============================] - 2s 34us/step - loss: 0.0352 - acc: 0.9901 - val_loss: 0.0539 - val_acc: 0.9842
In [69]:
score = model.evaluate(test_x, test_y, verbose=1)
print("최종 정확도 : " + str( score[1] * 100 ) + " %" )
10000/10000 [==============================] - 1s 98us/step
최종 정확도 : 98.28 %

그래도 훈련이 가능함을 알수 있었습니다.

답글 남기기