이전 포스팅에서 우리는 딥러닝의 기초와 손글씨 숫자 분류 모델을 만드는 방법을 배웠습니다. 이번 포스팅에서는 딥러닝의 또 다른 강력한 도구인 컨볼루션 신경망(CNN)을 사용해 이미지를 분류하는 방법을 알아보겠습니다. CNN은 이미지와 같은 시각 데이터를 처리하는 데 특히 유용합니다.
1. 컨볼루션 신경망(CNN) 개요
컨볼루션 신경망(CNN)은 기본적인 신경망과 비슷하지만, 이미지와 같은 2차원 데이터를 처리할 때 훨씬 더 효율적입니다. CNN은 이미지의 특징을 자동으로 추출하며, 이를 통해 이미지 분류, 객체 인식, 자율 주행 등 다양한 비전 분야에서 널리 사용됩니다.
왜 CNN이 필요할까요?
기본적인 신경망(MLP)은 1차원 데이터에 적합합니다. 예를 들어, 한 줄의 숫자 배열을 처리하는 데 효과적이죠. 하지만 이미지와 같은 2차원 데이터를 처리할 때는 이미지의 공간적 관계(즉, 특정 픽셀이 주변 픽셀과 어떻게 연결되는지)를 고려할 수 없습니다. 이 때문에 CNN이 등장했습니다.
CNN은 이미지를 작은 부분으로 나누어 각 부분에서 특징을 추출합니다. 이 과정을 컨볼루션(Convolution)이라고 합니다. 이를 통해 이미지는 원래 크기를 유지하면서도 중요한 정보를 뽑아낼 수 있게 됩니다.
2. CNN의 주요 구성 요소
CNN은 여러 층(layer)으로 구성됩니다. 각 층은 특정 작업을 수행하여 이미지를 처리합니다. 주요 구성 요소는 다음과 같습니다:
- 컨볼루션 레이어(Convolutional Layer): 이미지의 작은 패치(예: 3×3 픽셀)를 스캔하면서 특징을 추출합니다.
- 풀링 레이어(Pooling Layer): 이미지의 크기를 줄이면서도 중요한 특징을 유지합니다. 예를 들어, 최대 풀링(Max Pooling)은 패치 내에서 가장 큰 값을 선택합니다.
- 활성화 함수(Activation Function): ReLU와 같은 활성화 함수를 사용해 신경망에 비선형성을 부여합니다. 이는 신경망이 더 복잡한 패턴을 학습할 수 있도록 돕습니다.
이제 실제 예시를 통해 이들 구성 요소가 어떻게 작동하는지 알아보겠습니다.
3. CNN 모델의 구현
이제 CNN을 사용해 실제로 이미지를 분류하는 모델을 만들어보겠습니다. 이 예제에서는 CIFAR-10 데이터셋을 사용할 것입니다. 이 데이터셋은 10개의 클래스(비행기, 자동차, 새, 고양이 등)로 구성된 32×32 픽셀 크기의 컬러 이미지로 이루어져 있습니다.
1) 데이터셋 로드 및 전처리
먼저, CIFAR-10 데이터셋을 로드하고, 데이터를 신경망에 맞게 전처리합니다. 데이터 전처리란 데이터를 학습에 적합한 형태로 변환하는 과정을 말합니다.
from tensorflow.keras.datasets import cifar10
from tensorflow.keras.utils import to_categorical
# CIFAR-10 데이터셋 로드
(X_train, Y_train), (X_test, Y_test) = cifar10.load_data()
# 데이터 정규화 (0~1 범위로 조정)
X_train = X_train.astype('float32') / 255.0
X_test = X_test.astype('float32') / 255.0
# 라벨을 원-핫 인코딩으로 변환
Y_train = to_categorical(Y_train, 10)
Y_test = to_categorical(Y_test, 10)
여기서 이해해야 할 개념:
- 정규화(Normalization): 이미지의 픽셀 값은 0에서 255까지의 값을 가집니다. 하지만 신경망이 더 쉽게 학습할 수 있도록 모든 값을 0에서 1 사이로 조정합니다.
- 원-핫 인코딩(One-Hot Encoding): 클래스 라벨(예: 0부터 9까지의 숫자)을 신경망이 이해할 수 있는 형식으로 변환합니다. 예를 들어, 3이라는 숫자는 [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]으로 변환됩니다.
2) CNN 모델 구축
CNN 모델을 Sequential API를 사용해 간단하게 구축할 수 있습니다. 이 모델은 두 개의 컨볼루션-풀링 블록과 완전 연결층으로 구성됩니다.
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
# CNN 모델 구축
model = Sequential()
# 첫 번째 컨볼루션-풀링 레이어
model.add(Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(32, 32, 3)))
model.add(MaxPooling2D((2, 2)))
# 두 번째 컨볼루션-풀링 레이어
model.add(Conv2D(64, (3, 3), activation='relu', padding='same'))
model.add(MaxPooling2D((2, 2)))
# 완전 연결층
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(10, activation='softmax'))
# 모델 요약
model.summary()
각 레이어의 역할:
- Conv2D 레이어: 필터(커널)를 사용해 이미지에서 특징을 추출합니다. 여기서 32와 64는 필터의 개수, (3, 3)은 필터의 크기입니다.
padding='same'
은 출력 이미지가 입력 이미지와 동일한 크기를 가지도록 합니다. - MaxPooling2D 레이어: 이미지의 크기를 절반으로 줄이면서 중요한 정보만을 남깁니다.
- Flatten 레이어: 2차원 데이터를 1차원 벡터로 변환하여 완전 연결층에 전달합니다.
- Dense 레이어: 완전 연결층으로, 최종적으로 10개의 클래스(0~9) 중 하나를 예측합니다.
3) 모델 컴파일 및 학습
이제 모델을 컴파일하고 학습시킬 준비가 되었습니다. 손실 함수로는 카테고리컬 크로스엔트로피를, 옵티마이저로는 Adam을 사용합니다.
from tensorflow.keras.optimizers import Adam
# 모델 컴파일
model.compile(optimizer=Adam(), loss='categorical_crossentropy', metrics=['accuracy'])
# 모델 학습
model.fit(X_train, Y_train, epochs=15, batch_size=64, validation_data=(X_test, Y_test))
여기서 이해해야 할 개념:
- 손실 함수(Loss Function): 모델이 얼마나 잘못 예측했는지를 측정하는 함수입니다. 카테고리컬 크로스엔트로피는 여러 클래스 중 하나를 예측할 때 자주 사용됩니다.
- 옵티마이저(Optimizer): 신경망의 가중치를 업데이트하는 알고리즘입니다. Adam 옵티마이저는 학습 속도와 성능의 균형이 좋아 많이 사용됩니다.
- 에포크(Epoch): 전체 데이터셋이 신경망을 통해 한 번 학습되는 주기를 의미합니다. 여러 에포크 동안 모델을 반복 학습시켜 성능을 향상시킵니다.
4) 모델 성능 평가
학습이 완료된 후, 테스트 데이터를 사용해 모델의 성능을 평가합니다.
# 모델 평가
test_loss, test_acc = model.evaluate(X_test, Y_test, verbose=2)
print(f'\nTest accuracy: {test_acc}')
이 코드는 테스트 데이터에서 모델의 정확도를 계산하고 출력합니다.
4. 데이터 증강을 통한 성능 향상
딥러닝 모델의 성능을 더욱 향상시키기 위해 데이터 증강(Data Augmentation)을 활용할 수 있습니다. 데이터 증강은 기존 이미지를 다양한 방법으로 변형하여 새로운 학습 데이터를 생성하는 기법입니다. 예를 들어, 이미지를 좌우로 뒤집거나 회전시킬 수 있습니다. 이를 통해 모델이 다양한 상황에서도 잘 동작하도록 만듭니다.
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# 데이터 증강을 위한 이미지 생성기 설정
datagen = ImageDataGenerator(
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
horizontal_flip=True,
)
# 데이터 증강 적용 및 학습
datagen.fit(X_train)
model.fit(datagen.flow(X_train, Y_train, batch_size=64), epochs=15, validation_data=(X_test, Y_test))
데이터 증강의 이점:
- 더 많은 데이터를 사용해 모델을 학습시킬 수 있습니다.
- 모델이 새로운 데이터에 대해 일반화할 수 있는 능력이 향
상됩니다.
5. 혼동 행렬을 이용한 오류 분석
모델의 성능을 평가할 때, 단순히 정확도만 보는 것보다 오류의 종류와 빈도를 분석하는 것이 중요합니다. 이를 위해 혼동 행렬(Confusion Matrix)을 사용할 수 있습니다.
혼동 행렬은 모델이 각 클래스를 얼마나 정확하게 예측했는지를 시각적으로 보여줍니다. 예를 들어, 모델이 고양이를 개로 잘못 예측한 횟수를 쉽게 확인할 수 있습니다.
from sklearn.metrics import confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
# 예측값 생성
Y_pred = model.predict(X_test)
Y_pred_classes = Y_pred.argmax(axis=-1)
Y_true = Y_test.argmax(axis=-1)
# 혼동 행렬 생성
cm = confusion_matrix(Y_true, Y_pred_classes)
# 혼동 행렬 시각화
plt.figure(figsize=(10, 8))
sns.heatmap(cm, annot=True, fmt="d", cmap="Blues", xticklabels=['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck'], yticklabels=['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck'])
plt.xlabel('Predicted')
plt.ylabel('True')
plt.show()
혼동 행렬이 중요한 이유:
- 모델의 강점과 약점을 파악할 수 있습니다.
- 잘못된 예측이 반복되는 패턴을 식별할 수 있습니다.
결론
이번 포스팅에서는 CNN을 사용해 이미지를 분류하는 방법을 매우 상세히 설명했습니다. CNN은 이미지에서 특징을 자동으로 학습하며, 이를 통해 다양한 비전 작업에 매우 유용합니다. 또한, 데이터 증강 기법을 사용해 모델의 성능을 더욱 향상시킬 수 있었습니다.
이제 여러분도 CNN을 사용해 다양한 이미지를 분류하는 모델을 만들어 볼 수 있을 것입니다. 실습을 통해 더 많은 경험을 쌓고, 다양한 아키텍처를 시도해보는 것이 중요합니다.
다음 포스팅에서는 더욱 발전된 CNN 아키텍처와 그 응용 사례를 다루어 보겠습니다.
이 포스팅이 유익했다면, 구독과 좋아요를 눌러주세요. 궁금한 점이나 의견이 있다면 댓글로 남겨주세요!