본문 바로가기
[파이썬]/딥러닝

[딥러닝] 합성곱신경망(CNN) 개념부터 모델 구축까지

by sung min_Kim 2024. 1. 16.


 이번 글에서는 "합성곱신경망의 개념부터 모델 구축"에 대한 내용들을 살펴보려 한다. 
차례와 사용 툴 및 라이브러리는 아래와 같다.

 [차례]
 첫 번째, 합성곱신경망(Convolutional Neural Network; CNN) 개념
 두 번째, 합성곱신경망(CNN) 특징
 세 번째, 합성곱신경망(CNN) 구조
 네 번째, 합성곱 연산
 다섯 번째, 합성곱신경망(CNN) 모델 구축

 [사용 툴]

- Jupyter notebook(웹 기반 대화형 코딩 환경)
 
 [사용 라이브러리 및 모듈]

  • 딥러닝 라이브러리 및 모델: TensorFlow
    - tensorflow.keras: 사용자 친화적 인터페이스를 제공하는 TensorFlow의 고수준 API
    - tensorflow.keras.utils.plot_model: 케라스 모델의 구조 시각화

 


합성곱신경망(Convolutional Neural Network; CNN) 개념

 

 

 합성곱신경망(CNN)은 이미지 인식에 특화된 인공신경망의 한 종류이다. 이는 사람이 그림을 그리거나 사진을 찍는 방식과 유사하게 이미지를 '보는' 방법을 컴퓨터에게 가르쳐 준다.

 기존 인공신경망은 이미지를 일렬로 늘어선 숫자의 나열로 보았다. 즉, 이미지를 '픽셀'이라는 작은 점들의 나열로 바라보았다. 그러나 이 방식은 이미지 내에서 픽셀이 서로 어디에 위치하는지, 어떤 관계를 가지는지와 같은 '공간적인 정보'를 잃게 된다. 예를 들어, 얼굴 사진에서 눈과 입의 위치와 그들 사이의 관계를 기존 인공신경망으로는 파악하기 어렵다. 이런 정보는 이미지를 이해하는 데 중요하다.

 그래서 이러한 문제를 해결하기 위해 만들어진 것이 바로 합성곱신경망(CNN)이다. CNN은 이미지를 일렬로 나열하는 대신, 이미지를 '원래의 모습' 보며 공간적인 정보를 파악한다. 즉, CNN은 이미지에서 작은 부분을 잘라내어 그 안의 패턴을 찾아낸다.

 예를 들어, 얼굴 사진에서는 눈, 코, 입 등의 특징을 찾아내어 얼굴을 인식한다. 이렇게 작은 부분에서 시작해 점점 더 큰 부분의 이미지를 이해하게 된다. 이런 방식으로 CNN은 이미지를 더욱 잘 이해하고, 더욱 정확하게 인식하는 데 큰 도움이 된다.
 


합성곱신경망(CNN) 특징

 


 합성곱신경망(CNN)의 주요 특징 중 하나는 이미지의 원본 형태를 그대로 유지하며 학습할 수 있다는 점이다. 기존의 인공신경망은 이미지를 1차원 데이터로 변환해 처리하였다. 이 방식은 이미지의 높이와 너비를 곱하여 데이터 배열을 1차원으로 변환하는 방식이었다.

 그러나 이 방식은 이미지의 공간 정보, 즉 픽셀 사이의 위치 관계를 무시하게 되어 중요한 특징을 놓칠 수 있다. 이러한 단점을 보완하기 위해 CNN은 4차원의 데이터를 활용하여 이미지를 분석한다.

 원본 이미지의 공간 정보를 그대로 활용하는 CNN은 인접한 픽셀들 사이의 관계를 포착하여 특징을 추출하는 능력을 가지고 있다. 이를 통해 이미지 분석이 효과적으로 이루어지며, 더욱 정확한 학습이 가능하게 된다. 

 따라서, CNN은 기존 인공신경망의 단점을 보완하고, 이미지 분석의 효율성과 정확도를 크게 향상시킨 모델이라 할 수 있다.

 


합성곱신경망(CNN) 구조



합성곱신경망 구조(출처: https://compmath.korea.ac.kr/appmath2021/ConvolutionNN.html)


 합성곱신경망의 주요 계층으로는 '합성곱 계층(Convolutional Layer)', '풀링 계층(Pooling Layer)', '전결합 계층 또는 완전연결 계층(Fully Connected Layer)'으로 구성되어 있다. 각 계층들은 서로 연결되어 있으며, 이미지를 입력으로 받아 이를 처리하고, 그 결과를 다음 계층으로 전달한다.

 합성곱 계층에서는 이미지의 특징을 추출하고, 풀링 계층에서는 그 특징들의 크기를 줄이며, 완전 연결 계층에서는 이러한 특징들을 바탕으로 해당 이미지가 어떤 클래스에 속하는지를 결정한다. 이렇게 각 계층은 전체 네트워크 중 일부를 담당하며, 그 결과를 다음 계층으로 전달함으로써 전체 네트워크의 작동에 기여한다.

 각 계층에 대한 설명은 다음과 같다.

합성곱 계층(Convolutional Layer)


 이 계층은 사진을 잘게 나누어 보는 것과 같은 역할을 한다. 예를 들어 큰 풍경 사진을 보면, 그 안에 나무, 집, 하늘 등 다양한 요소들이 있을 것이다. 합성곱 계층에서는 이런 큰 사진을 작은 사각형 영역으로 나누어 각각을 따로 본다. 그리고 그 작은 사각형 안에 어떤 패턴이나 특징이 있는지를 알아내는 것이 바로 합성곱 연산이다. 사진 전체를 한 번에 보는 것이 아니라, 작은 부분을 보면서 이해하는 방식이다.

 

풀링 계층(Pooling Layer)


 이 계층은 이미지에서 중요한 특징만을 선택적으로 보존하는 역할을 한다. 예를 들어, 사람의 얼굴을 인식하는 데는 눈, 코, 입 등의 특징이 중요하지만, 배경이나 옷의 패턴 등은 상대적으로 중요하지 않다. 이와 같이
풀링 계층은 중요한 특징들을 잘 보존하면서, 중요성이 낮은 요소들은 축소시킨다.

 이로 인해, 신경망은 이미지 속의 사람 얼굴을 더욱 정확하게 인식할 수 있게 된다. 만약 신경망이 배경이나 옷의 패턴에 집중하게 되면, 사람의 얼굴을 인식하는 데 방해가 될 수 있기 때문이다.


 따라서, 풀링 계층은 중요한 정보를 강조하고, 합성곱 계층에서 추출한 특징들의 크기를 축소함으로써 계산량을 감소시키며, 모델의 과적합을 방지하는 역할을 수행한다.

 

완전 연결 계층(Full Connected Layer)


 이 계층은 합성곱 계층과 풀링 계층에서 추출된 특징들을 종합하여 최종 예측을 수행하는 역할을 한다. 이는 마치 사진을 보고 "이것은 무엇인가?"라고 판단하는 과정과 유사하다. 예를 들어, 나무, 집, 하늘 등의 특징들을 종합하여 "이 사진은 풍경 사진이다"라고 판단하는 것처럼 말이다.


 이처럼 각 계층이 서로 연결되어 이미지를 분석하고, 그 이미지가 무엇인지를 판단하는 이런 과정이 바로 CNN, 즉 합성곱신경망의 작동 원리이다.

 


합성곱 연산

 

 

 합성곱 연산은 이미지 처리에서 추출하는 방법 중 하나이다. 합성곱 연산은 아래의 단계로 이루어진다.

합성곱 연산(출처: https://compmath.korea.ac.kr/appmath2021/ConvolutionNN.html)

 

  1. 필터를 이미지의 왼쪽 상단부터 시작하여 오른쪽으로, 그리고 아래로 이동시키며 적용한다. 이 때 필터가 적용되는 부분은 맨 좌측 이미지의 특정 영역이다.

  2. 필터의 각 요소와 이에 대응하는 이미지의 픽셀값을 곱한 후, 그 결과를 모두 더한다. 이렇게 계산한 값이 해당 위치의 출력 값이 된다. (맨 우측의 특정 영역)

  3. 필터를 이미지 내에서 이동시키면서 이 과정을 반복한다.


 이 과정을 통해, 필터는 이미지의 특정 지역에서 특정 특징(ex. 가장자리, 직선, 색상 등)을 감지하는 역할을 한다. 이런 방식으로 이미지 전체에 대한 정보를 요약하고, 이미지 내에서 중요한 특징을 추출할 수 있다.

 합성곱 연산을 수행하면, 원본 이미지보다는 작지만, 이미지의 주요 특징이 담긴 새로운 행렬(특징 맵)이 생성된다. 이 특징 맵은 원본 이미지를 대표하는 간략한 정보를 담고 있어, 이미지 분류와 같은 작업을 효율적으로 수행하는 데 사용된다.

(출처: https://goldenrabbit.co.kr/2023/11/08/다시-살펴보는-딥러닝-주요-개념-2편-합성곱-신경망cnn)

 


합성곱신경망(CNN) 모델 구축

 


 합성곱 계층(Convolutional Layer)을 포함하는 신경망을 일반적으로 합성곱신경망(Convolutional Neural Network, CNN)이라고 한다. 단일 합성곱 계층만으로도 합성곱 신경망이라고 할 수 있지만, 일반적으로 여러 개의 합성곱 계층과 풀링 계층, 그리고 완전연결 계층 등이 조합되어 복잡한 합성곱신경망(CNN) 모델을 구성한다. 

1. 합성곱 계층(Convolutional Layer) 추가


 이미지와 같은 2차원 데이터 분류에는 주로 2차원 합성곱 'Conv2D'가 사용된다.
입력 데이터의 형태는 4차원 배열로, 각 차원은 (배치 크기, 높이, 너비, 채널)을 나타낸다. 여기서 배치 크기(batch_size)는 모델이 한 번에 처리할 이미지의 수를 의미한다. 이는 모델의 계산 효율성을 높이는 데 중요한 요소이다. 


 Conv2D 계층을 모델에 추가하려면 아래와 같은 코드를 입력한다.

model.add(keras.layers.Conv2D(kernel_size=3,
                              filters=32,
                              activation="relu",
                              padding="same",
                              strides=1,
                              input_shape=(28, 28, 1)))


 이때, Conv2D 클래스에 활용되는 각 파라미터들의 역할은 다음과 같다.

  • kernel_size
    이 파라미터는 이미지를 스캔하면서 '특징을 추출'하는 필터의 사이즈를 설정한다. 'kernel_size=3'은 필터 사이즈가 '3x3'임을 의미한다. 커널 사이즈는 주로 홀수(3, 5)로 설정한다.

  • filters
    이 파라미터는 단일 행렬 공간에 적용되는 필터의 수를 설정한다. 이 필터들은 데이터를 스캔하며 '특징을 감지'하는 역할을 수행한다. 필터의 수가 많을수록 훈련 속도는 느려진다. 일반적으로 '32', '64'가 주로 사용되고, 여러 개의 CNN 계층을 사용하는 경우 처음 CNN 계층에는 비교적 작은 값(16, 32, 64, 128 등)이 주로 사용된다.

  • activation
    이 파라미터는 활성화 함수를 설정한다. 활성화 함수는 신경망의 각 노드에서 출력값을 결정하는 함수로, 비선형성을 도입함으로써 모델이 복잡한 패턴을 학습할 수 있게 해 준다. 그중 'relu'는 가장 널리 사용되는 활성화 함수로, 입력값이 0보다 크면 그대로 출력하고, 0 이하면 0을 출력하는 특성을 가진다. 이런 특성 덕분에 'relu'는 비선형성을 부여하면서도 계산상의 효율성을 유지하게 해 준다.

  • padding
    이 파라미터는 경계 처리 방식을 설정한다. 입력 데이터 주변에 '0'으로 채워진 가상의 픽셀을 추가하는 방법이다. 이 과정은 합성곱 연산을 수행한 후에도 입력 데이터와 동일한 크기의 출력 데이터를 생성하기 위해 필요하다. 이 방식은 네트워크가 이미지의 경계 부분에서 중요한 특징을 유지하도록 돕고, 합성곱 계층을 여러 번 거쳐도 출력 데이터의 크기가 과도하게 축소되는 것을 방지한다. 이를 통해 네트워크가 더 깊은 계층까지 효과적으로 학습할 수 있다.
    처리 방식 방식은 'same'과 'valid'가 있다.

    - same: 입력과 출력의 크기를 일치시키기 위해 패딩을 사용 (주로 권장되는 방식)
    - valid: 패딩을 사용하지 않음

    패딩을 적용한 합성곱 연산(출처: https://goldenrabbit.co.kr/2023/11/08/다시-살펴보는-딥러닝-주요-개념-2편-합성곱-신경망cnn)


  • strides
    이 파라미터는 커널이 이미지 데이터를 스캔할 때의 이동 간격을 설정한다. 커널은 왼쪽 상단에서 시작하여 오른쪽으로 이동하고, 오른쪽 열을 모두 스캔한 후에 아래로 이동한다. 'strides=1'은 오른쪽으로 1칸, 아래로 1칸 이동함을 의미한다.

  • input_shape
    이 파라미터는 이미지의 높이, 너비, 채널 수를 설정한다. 'input_shape' 파라미터에는 배치 크기(batch_size)를 포함하지 않는다. 이는 배치 크기가 학습 과정에서 입력 데이터의 양을 제어하는 역할을 하기 때문이다. 이렇게 설정하면, 모델의 구조를 정의하는 단계에서는 배치 크기를 자동으로 고려하게 된다. 즉, 모델은 각 배치에 대해 독립적으로 동작하며, 배치 크기에 영향을 받지 않는다.

 

2. 풀링 계층(Pooling Layer) 추가


 'MaxPool2D'는 풀링 레이어 중 하나로, 주요 특징을 유지하면서 이미지의 크기를 줄이는 역할을 한다. 'pool_size=2'는 2행 2열의 공간에 중요한 특징들만을 저장하라는 의미이며, 'strides=2'는 CNN에서 추출한 특징값들의 행렬을 오른쪽으로 2칸, 아래로 2칸 이동하며 중요한 특징값을 추출하라는 의미이다. 이 과정은 계산 효율성을 높이고 과적합을 방지하는 데 도움을 준다.

 또한, MaxPool2D는 '위치 불변성'을 보완하는 역할도 한다. 위치 불변성은 객체가 이미지 내의 어느 위치에 있더라도 그 객체를 인식할 수 있어야 한다는 개념이다. 

 합성곱 계층은 이미지 내의 특징 위치를 정확히 고려하지 못하는 반면, MaxPool2D는 이미지를 작은 영역으로 나누고 각 영역에서 가장 중요한 특징을 선택함으로써, 특징의 위치 변화도 인식할 수 있다. 이를 통해 객체의 안전성이 향상된다.

 MaxPool2D 계층을 모델에 추가하려면 아래와 같은 코드를 입력한다.

model.add(keras.layers.MaxPool2D(pool_size=2, strides=2))

MaxPool (출처: https://goldenrabbit.co.kr/2023/11/08/다시-살펴보는-딥러닝-주요-개념-2편-합성곱-신경망cnn)

 

3. 완전 연결 계층(Full Connected Layer) 추가


 합성곱신경망(CNN)의 마지막 부분에는 일반적으로 완전 연결 계층이 위치한다. 이 완전 연결 계층은 합성곱 계층과 풀링 계층을 통해 추출된 특징들을 바탕으로 최종적인 분류를 수행하는 역할을 한다. 

 완전 연결 계층을 모델에 추가하려면 아래와 같이 코드를 입력한다.

model.add(keras.layers.Flatten())

model.add(keras.layers.Dense(100, activation="relu"))

model.add(keras.layers.Dense(10, activation="softmax"))


 이때, 완전 연결 계층에 추가된 각 계층들의 역할은 다음과 같다. 

  1. Flatten 계층
    이 계층은 합성곱 계층(Conv2D)과 풀링 계층(MaxPool2D)에서 추출된 다차원(2D 또는 3D)의 특징 맵을 1차원(1D)으로 변환하는 역할을 한다. 이 변환 과정이 필요한 이유는 완전 연결 계층(Dense)이 1D 벡터 형태의 입력만 처리할 수 있기 때문이다. 이렇게 변환된 1D 벡터는 이후의 완전 연결 계층(Dense)에 입력으로 사용되며, 이 과정은 공간 정보를 유지하면서 데이터를 완전 연결 계층에 적합한 형태로 변환하는 데 중요하다.

  2. 은닉 계층에서의 Dense 계층
    은닉 계층에서는 Dense 계층이 주로 사용되며, 보통 활성화 함수로 'relu'를 사용한다. 'relu'는 음수를 0으로 만들어 신경망에 필요한 비선형성을 제공한다. 이를 통해 신경망은 복잡한 패턴을 학습할 수 있게 된다. 따라서, 은닉 계층에 사용되는 Dense 계층은 주로 복잡한 패턴을 학습하는 데 사용된다.

  3. 출력 계층에서의 Dense 계층
    출력 계층에서의 Dense 계층은 보통 활성화 함수로 'softmax' 또는 'sigmoid'를 사용한다. 이 함수들은 다중 분류와 이진 분류 문제에서 각 클래스에 대한 확률을 출력한다. 따라서, 출력 계층에 사용되는 Dense 계층은 모델의 최종 예측값을 출력하는 데 사용된다.

 또한, 훈련 과정 중 무작위로 뉴런을 비활성화시키는 Dropout 계층도 은닉 계층으로서 사용될 수 있다. 이 계층은 모델의 과적합을 방지하는 데 도움을 준다.

4. 합성곱신경망 모델 확인하기


 아래와 같이 합성곱 계층(Conv2D, relu)과 풀링 계층(MaxPool2D)을 연속적으로 추가함으로써 합성곱 신경망(CNN) 모델을 구축해 보았다. 이 모델은 추출된 특징들을 처리하기 위해 완전 연결 계층(Flatten - Dense - Dropout - Dense)을 이용한다.


 위 계층이 추가된 모델의 속성을 시각화 및 저장시키는 방법은 다음과 같다.

from tensorflow.keras.utils import plot_model

plot_model(model, show_shapes=True,
           to_file="./model_img/CNN_Layer.png",
           dpi=300)