Skip to main content

튜토리얼: 합성곱 신경망

이 초보자용 튜토리얼에서는 CNN의 작동 원리를 자세히 살펴보기 전에 이미지 분류를 위한 첫 번째 합성곱 신경망(CNN)을 함께 만들어 봅니다. 이 글은 AI 번역본입니다. 오역이 의심되는 부분이 있다면 댓글로 알려 주세요.
Created on September 15|Last edited on September 15


이 영상에서는 이미지 분류를 위한 첫 번째 합성곱 신경망을 만들어 보며, CNN이 어떻게 작동하는지 자세히 설명합니다.

프로젝트

https://github.com/lukas/ml-class/tree/master/projects/3-fashion-mnist-cnn 에 접속해 패션 분류기를 직접 만들어 보며 이해도를 확인하세요.

주제

  • 합성곱이란 무엇인가요?
  • 이미지에 합성곱 적용하기
  • 평탄화와 풀링
  • 여러 개의 CNN 사용하기

합성곱 신경망

지금까지 우리가 한 작업은 입력과 출력을 고정 길이의 숫자 목록으로 변환할 수 있는 모든 데이터셋에 적용됩니다. 하지만 그 과정에서 중요한 정보를 일부 버렸습니다. 이미지를 평탄화할 때, 픽셀의 순서에 의미가 있다는 사실을 잃게 됩니다. 그리고 실제로 픽셀의 순서에는 의미가 있을 가능성이 큽니다.

합성곱

합성곱은 오래전부터 존재해 왔지만, 2011년 무렵부터 이미지 인식에 적용되면서 큰 성공을 거두기 시작했습니다.
합성곱이란 무엇일까요? 합성곱은 픽셀의 순서, 즉 공간적 구조에 대한 정보를 포착하는 방법입니다. 여기서 다루는 합성곱은 2차원 이산 합성곱으로, 픽셀 영역에 대해 가중치가 적용된 슬라이딩 합처럼 동작합니다. 예를 들어, 커널이라 불리는 3×3 행렬이 이미지의 픽셀 위를 가로질러 이동합니다. 각 위치에서 커널의 값과 해당 위치의 3×3 픽셀 조각을 요소별로 곱해 가중 합을 계산합니다. 이렇게 계산된 합은 출력 이미지의 첫 번째 값으로 기록됩니다. 그런 다음 커널은 한 픽셀만큼 이동하고, 이미지의 모든 픽셀 위치에 대해 이 과정을 반복합니다.

이 과정은 각 픽셀의 주변 값 정보를 그 픽셀의 값에 반영합니다. 원본 이미지와 출력 이미지를 비교해 보면, 결과는 저렴한 포토샵 필터처럼 보입니다. 예를 들어, 커널의 모든 값이 0.1이라면 합성곱은 사실상 3×3 블록에 대한 평균을 내는 것이므로, 이 경우의 ‘필터’는 흐림 효과처럼 보입니다.


컬러 이미지 합성곱

이제 단일 픽셀 값으로 이루어진 이미지에 합성곱을 적용하는 방법을 이해했으니, 중요한 경우인 컬러 이미지에서는 어떻게 되는지 살펴보겠습니다. 컬러 이미지의 픽셀은 빨강, 초록, 파랑의 세 가지 값을 갖습니다. 따라서 컬러 이미지에 합성곱을 적용하려면 먼저 이미지를 빨강, 초록, 파랑 성분으로 분리한 뒤, 빨강 데이터에는 하나의 커널, 초록 데이터에는 또 하나, 파랑 데이터에는 또 하나의 커널을 각각 적용하고, 그 결과들을 모두 합산해야 합니다.


합성곱의 속성

합성곱에는 여러 가지 유형이 있습니다. 때로는 합성곱이 한 번에 한 칸보다 더 많이 이동하기도 합니다. 예를 들어 각 반복에서 두 칸씩 이동한다면, 그 합성곱의 스트라이드는 2라고 말합니다.

가장자리 처리를 어떻게 할지도 고려해야 합니다. 이미지에 3×3 합성곱을 적용할 때 가장자리를 넘어가지 않으면, 출력 이미지는 입력 이미지보다 조금 작아집니다. 이것이 Keras의 기본 동작입니다. 하지만 이미지 크기를 유지하고 싶다면 입력 이미지 가장자리에 0을 둘러서 추가하는 제로 패딩을 사용할 수 있습니다.


풀링

또 하나의, 더 단순하지만 신경망에서 매우 흔한 변환이 바로 풀링입니다. 합성곱이 거친 필터 효과라면, 풀링은 거친 크기 조절 알고리즘에 비유할 수 있습니다. 보통 풀링은 이미지의 2×2 영역을 취해 각 영역에서 가장 큰 값을 선택합니다. 이를 맥스 풀링이라고 합니다. 같은 방식으로 2×2 영역의 모든 픽셀 값을 평균내는 애버리지 풀링도 사용할 수 있습니다. 이렇게 하면 이미지의 가로와 세로 크기는 2배 줄어들고, 전체 면적은 4배 줄어듭니다. 풀링의 목적은 서로 다른 스케일에서 합성곱을 수행할 수 있도록 하는 데 있습니다.



코드

이제 코드로 가서 모든 요소가 어떻게 맞물리는지 확인해 봅시다. cnn.py를 열어 보세요. 이 코드는 다층 퍼셉트론에서 우리가 멈췄던 지점과 매우 유사하며, 19행과 20행이 추가되었습니다.
// line 19

X_train = X_train.reshape(X_train.shape[0], config.img_width, config.img_height, 1)
X_test = X_test.reshape(X_test.shape[0], config.img_width, config.img_height, 1)
이미지가 흑백이기 때문에 X 데이터를 재구성해야 합니다. Keras는 각 입력을 세 번째 차원이 색상을 나타내는 3차원 이미지로 기대합니다. 그러나 그레이스케일 이미지는 이 차원이 없으므로, 입력을 수동으로 재구성하여 색상 차원을 1로 설정해야 합니다.
또 다른 변경 사항은 29행에 있습니다. 지금까지는 이미지를 평탄화해서 사용했지만, 이제는 합성곱을 수행할 것입니다.
// line 29
model.add(Conv2D(32, (config.first_layer_conv_width, config.first_layer_conv_height), input_shape=(28,28,1), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(config.dense_layer_size, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
이는 우리가 32개의 합성곱을 병렬로 수행하고 있으며, 각 합성곱의 파라미터 가중치를 학습해야 함을 보여 줍니다. 다음으로 입력을 1차원으로 줄이는 평탄화(Flatten) 레이어를 추가합니다. 마지막으로, 다음 레이어가 퍼셉트론(밀집 레이어)으로서 1차원 입력을 기대하기 때문에 평탄화 레이어를 한 번 더 추가합니다.
모델을 실행해 보면, 자유 파라미터의 수는 다음과 같습니다:

우리 모델에는 거의 100만 개에 가까운 자유 파라미터가 있지만 학습 데이터는 6만 개뿐입니다. 무엇을 걱정해야 할까요?
정답은 과적합입니다. 과적합을 줄이기 위해 항상 드롭아웃을 추가합니다. 일반적으로 자유 파라미터가 있는 레이어 뒤에 드롭아웃을 넣습니다. 이번 경우에는 첫 번째 밀집 레이어 앞과 두 번째 밀집 레이어 앞에 둡니다. 드롭아웃 비율은 40%로 설정했지만, 보통 20%에서 50% 사이에서 선택할 수 있습니다. 이제 우리의 코드는 다음과 같습니다:
//line 29

model.add(Conv2D(32, (config.first_layer_conv_width, config.first_layer_conv_height), input_shape=(28,28,1), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dropout(0.4))
model.add(Dense(config.dense_layer_size, activation='relu'))
model.add(Dropout(0.4))
model.add(Dense(num_classes, activation='softmax'))
이제 우리 모델의 정확도는 98%입니다. 정확도를 99%로 끌어올리려면 여러 개의 합성곱 레이어가 필요합니다. 왜 그럴까요?
여러 개의 합성곱 레이어를 사용하는 직관적 이유는, 풀링이나 축소를 거친 뒤에 또 한 번의 합성곱을 수행하면 이미지의 다른 스케일에서 특징을 학습할 수 있기 때문입니다. 네트워크에 합성곱 레이어를 몇 개 더 추가해 보세요.
이제 이 데이터셋에서 거의 완벽한 정확도를 얻을 수 있어야 합니다.

도전

또 다른 도전 과제로, 다른 데이터셋에 대해 직접 CNN을 구축해 보는 것도 좋��니다. 우리는 이미 fashion MNIST라는 유사한 데이터셋을 로드해 두었습니다. 60,000장의 이미지로 구성되어 있으며, 의류 이미지이고 범주는 "T-shirt/top", "Trouser", "Pullover", "Dress", "Coat", "Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"입니다.
fashion.py를 열어 보면, 이 연습 전체가 시작된 지점에서 출발하도록 뼈대 코드를 넣어 두었습니다. 지금까지 배운 내용을 적용해, 유사한 데이터셋에서 패션 분류기를 직접 만들어 볼 수 있나요?



이 글은 AI로 번역되었습니다. 오역이 있을 수 있으니 댓글로 알려 주세요. 원문 보고서 링크는 다음과 같습니다: 원문 보고서 보기