합성곱 신경망(CNN : Convolution Neral Network)

김우빈·2022년 5월 29일
0

JUST BUILD DEEP_LEARNING

목록 보기
6/9
post-thumbnail

합성곱 신경망(CNN : Convolution Neral Network)이란?

- 개요

이번 게시글에서 다룰 합성곱 신경망(CNN : Convolution Neral Network/ 이하 CNN)은 인간의 시신경 구조를 인공적으로 모방한 기술로써 이미지의 공간 정보(차원: dimension)을 유지한 채 학습합니다.
데이터를 직접 학습하고 패턴을 사용해 이미지를 분류하고, 그러한 이미지의 패턴을 찾는데 특히 유용합니다.

-공간정보(차원: dimension)?

색을 표현하기 위해서는 몇차원이 필요할까요?
우리는 보통 색을 빛의 삼원색인 RGB(Red, Green, Blue)로 나누어 RGB 컬러의 3차원값을 다양하게 조합하여 색상을 표현합니다.
이렇게 표현된 공간을 '색공간'(Color Space)라고 부릅니다.
이공간을 컴퓨터의 비트연산으로 표현하면 각각 R: 256개(1~255), G: 256개(1~255), B: 256개(1~255)이고,
이것을 공간을 표현하면 아래의 사진처럼 2553255^3 의 값을 가지고 있습니다.

<이미지출처: http://overface.tistory/593 >

위의 결론을 바탕으로 이미지의 차원을 구하려면
가로 픽셀값(pixel_Length) ×\times 3 세로 픽셀값(pixel_Width) ×\times 3
이되고 흑백의 경우에는
가로 픽셀값(pixel_Length) ×\times 3 세로 픽셀값(pixel_Width) ×\times 1
이된다고 할 수 있습니다.

합성곱 신경망(CNN : Convolution Neral Network)의 특징

<이미지출저: http://aidev.co.kr/deeplearning/782 >

CNN은 위의 이미지처럼 이미지의 특징을 추출해내는 영역과
카테고리를 분류를 하는 영역으로 나눌 수 있습니다.
특징을 추출하는 부분은 합성곱을 하는 층(Convolution Layer)과
Pooling을 하는층(Pooling Layer)로 구성됩니다.

위 이미지의 설명처럼 pooling 이란 해당하는 이미지 데이터를 작은 사이즈의 이미지로 변환하는 연산입니다. sub-sampling 이라고도 합니다. 2차원 데이터의 세로 및 가로 방향의 공간을 줄이는 연산이라고 생각 하시면 되겠습니다.
더욱 쉽게 설명드리면 바로 눈앞에서 그림을보다가 점점 시점을 뒤로 옮기면서 그림을 보는 과정을 생각하시면 편하실겁니다.

pooling에는

  • max pooling
  • average pooling
  • stochastic pooling
  • Cross channel pooling

등이 있습니다.

tensorflow로 구현하기

유명한 손글씨 데이터는 tensorflow.keras.datasets에 있는 mnist를 활용해 CNN모델을 구현해보고자 합니다.

사용할 module들입니다.

import sys
import os
import tensorflow as tf
import numpy as np
from tensorflow.keras.datasets import mnist
from tensorflow.keras.optimizers import Adam

module을 import 해준후,

data = mnist #데이터 변수선언

(x_train, y_train), (x_valid, y_valid) = data.load_data()
x_train, x_valid = x_train / 255.0, x_valid / 255.0  #데이터 정규화


x_train=tf.cast(x_train, tf.float32) #텐서를 float(소숫값)형태로 캐스팅
x_train=np.expand_dims(x_train, -1) #차원추가함수에 -1을 넣어 차원축소
x_valid=tf.cast(x_valid, tf.float32)#텐서를 float(소숫값)형태로 캐스팅
x_valid=np.expand_dims(x_valid, -1)#차원추가함수에 -1을 넣어 차원축소

여기서 x_train, x_valid에 255를 나누는 이유는 사진을 읽어오면
RGB컬러[최대 (255, 255, 255)] 형태로 가져오는데 여기에 255를 나눠 0~1의 값을 가지게 만들어 데이터의 분산의 정도를 바꾸는 작업,
즉 데이터 정규화(Nomalization) 과정을 거치게 하기 위해서 입니다.

모델빌드

from tensorflow.keras import layers, models

model = models.Sequential([
    layers.Conv2D(kernel_size=(3,3), filters=16, activation='relu',padding="same",input_shape=(28, 28, 1)),
    layers.MaxPooling2D((2,2),strides=(1, 1)),
    layers.Dropout(0.2),
    layers.Conv2D(kernel_size=(3,3), filters=32, activation='relu',padding="same"),
    layers.MaxPooling2D((2,2),strides=(1, 1)),
    layers.Dropout(0.2),
    layers.Conv2D(kernel_size=(3,3), filters=64, activation='relu',padding="same"),
    layers.MaxPooling2D((2,2),strides=(2, 2)),
    layers.Dropout(0.2),
    layers.Conv2D(kernel_size=(3,3), filters=128, activation='relu',padding="same"),
    layers.MaxPooling2D((2,2),strides=(2, 2)),
    layers.Dropout(0.2),
    layers.Conv2D(kernel_size=(3,3), filters=256, activation='relu',padding="same"),
    layers.MaxPooling2D((2,2),strides=(2, 2)),
    layers.Dropout(0.2),
    layers.Dense(256, activation='relu'),
    layers.Dropout(0.5),
    layers.Flatten(),
    layers.Dense(10, activation='softmax')
    #모델시각화
   model.summary()
])

다음과같이 합성곱 층과, pooling 층을 번갈아서 주고, 과대적합의 방지를위해 dropout의 값을 0.2로 주어 서로 연결된 연결망(layer)에서 0부터 1 사이의 확률로 노드(node)를 제거(drop)해 주었습니다.

모델을 시각화 해보면

Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             (None, 28, 28, 16)        160       
                                                                 
 max_pooling2d (MaxPooling2D  (None, 27, 27, 16)       0         
 )                                                               
                                                                 
 dropout (Dropout)           (None, 27, 27, 16)        0         
                                                                 
 conv2d_1 (Conv2D)           (None, 27, 27, 32)        4640      
                                                                 
 max_pooling2d_1 (MaxPooling  (None, 26, 26, 32)       0         
 2D)                                                             
                                                                 
 dropout_1 (Dropout)         (None, 26, 26, 32)        0         
                                                                 
 conv2d_2 (Conv2D)           (None, 26, 26, 64)        18496     
                                                                 
 max_pooling2d_2 (MaxPooling  (None, 13, 13, 64)       0         
 2D)                                                             
                                                                 
 dropout_2 (Dropout)         (None, 13, 13, 64)        0         
                                                                 
 conv2d_3 (Conv2D)           (None, 13, 13, 128)       73856     
                                                                 
 max_pooling2d_3 (MaxPooling  (None, 6, 6, 128)        0         
 2D)                                                             
                                                                 
 dropout_3 (Dropout)         (None, 6, 6, 128)         0         
                                                                 
 conv2d_4 (Conv2D)           (None, 6, 6, 256)         295168    
                                                                 
 max_pooling2d_4 (MaxPooling  (None, 3, 3, 256)        0         
 2D)                                                             
                                                                 
 dropout_4 (Dropout)         (None, 3, 3, 256)         0         
                                                                 
 dense (Dense)               (None, 3, 3, 256)         65792     
                                                                 
 dropout_5 (Dropout)         (None, 3, 3, 256)         0         
                                                                 
 flatten (Flatten)           (None, 2304)              0         
                                                                 
 dense_1 (Dense)             (None, 10)                23050     
                                                                 
=================================================================
Total params: 481,162
Trainable params: 481,162
Non-trainable params: 0

다음과 같은 결과로 모델이 빌드된걸 확인 하실 수있습니다.

# #one-hot encoding을 안하는 대신에 sparse categorical cross entropy를 loss로 지정
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])    
    
model.summary()
hist = model.fit(x_train, y_train, epochs=10, validation_data=(x_valid, y_valid))

손실함수(loss function)와 활성함수(activation function),옵티마이저(optimizer)를 모델에 엮어주고(compile), fit하여 결과를 확인해봅니다.


Epoch 1/10
1875/1875 [==============================] - 211s 112ms/step - loss: 0.1978 - accuracy: 0.9371 - val_loss: 0.0356 - val_accuracy: 0.9878
Epoch 2/10
1875/1875 [==============================] - 221s 118ms/step - loss: 0.0629 - accuracy: 0.9805 - val_loss: 0.0337 - val_accuracy: 0.9888
Epoch 3/10
1875/1875 [==============================] - 218s 116ms/step - loss: 0.0515 - accuracy: 0.9839 - val_loss: 0.0359 - val_accuracy: 0.9908
Epoch 4/10
1875/1875 [==============================] - 221s 118ms/step - loss: 0.0435 - accuracy: 0.9867 - val_loss: 0.0269 - val_accuracy: 0.9919
Epoch 5/10
1875/1875 [==============================] - 216s 115ms/step - loss: 0.0423 - accuracy: 0.9868 - val_loss: 0.0245 - val_accuracy: 0.9918
Epoch 6/10
1875/1875 [==============================] - 224s 119ms/step - loss: 0.0390 - accuracy: 0.9882 - val_loss: 0.0208 - val_accuracy: 0.9935
Epoch 7/10
1875/1875 [==============================] - 235s 125ms/step - loss: 0.0353 - accuracy: 0.9892 - val_loss: 0.0192 - val_accuracy: 0.9936
Epoch 8/10
1875/1875 [==============================] - 231s 123ms/step - loss: 0.0356 - accuracy: 0.9895 - val_loss: 0.0261 - val_accuracy: 0.9916
Epoch 9/10
1875/1875 [==============================] - 230s 123ms/step - loss: 0.0331 - accuracy: 0.9898 - val_loss: 0.0220 - val_accuracy: 0.9929
Epoch 10/10
1875/1875 [==============================] - 229s 122ms/step - loss: 0.0320 - accuracy: 0.9906 - val_loss: 0.0206 - val_accuracy: 0.9932

다음과 같이 잘 학습되었음을 확인 할 수 있고, 그래프로 모델의 손실율(loss value)와 정확도(accuracy)를 확인 하실 수 있습니다.

import matplotlib.pyplot as plt
fig, loss_ax = plt.subplots()
acc_ax = loss_ax.twinx()

loss_ax.plot(hist.history['loss'], 'y', label = 'train loss')
loss_ax.plot(hist.history['val_loss'], 'r', label = 'val loss')

acc_ax.plot(hist.history['accuracy'], 'b', label = 'train accuracy')
acc_ax.plot(hist.history['val_accuracy'], 'g', label = 'valid accuracy')

loss_ax.set_xlabel('epoch')
loss_ax.set_ylabel('loss')
acc_ax.set_ylabel('accuracy')

loss_ax.legend(loc='upper left')
acc_ax.legend(loc='lower left')
plt.grid()
plt.show()

마무리

위와 같은 방법으로 합성곱 신경망(CNN : Convolution Neral Network)과 softmax함수를 사용해 이미지를 분류하는 모델을 빌드 해보았습니다.
CNN은 워낙 내용이 많아 수학적인 내용보단 구현에 대한 설명에 집중을 더 하였습니다. 긴 글 읽어주셔서 감사드리면서, 다음은 순환 신경망(Recurrent Neural Network, RNN)에 대해 적어보도록 하겠습니다.
감사합니다.

profile
DeepLearning, MLOps

0개의 댓글