합성곱 신경망
다층 신경망에서 이미지 처리
- 이미지는 높이, 너비, 채널을 가진 형태
- 이미지 분류용 다층 신경망은 보통
Flatten으로 이미지를 길이 인 벡터로 변환 Flatten은 픽셀값과 순서를 삭제하지 않지만 높이·너비 축을 하나의 축으로 펼침- Dense 레이어는 지역적으로 가까운 픽셀을 따로 구분하지 않고 모든 입력을 각 뉴런에 연결
- 입력 크기와 출력 뉴런 수가 커질수록 개의 파라미터가 필요

합성곱 신경망 Convolutional Neural Network
- 합성곱 신경망(CNN)은 작은 지역 패치에 필터를 반복 적용해 특징을 추출
- 필터(filter) 또는 커널(kernel)은 데이터에서 학습하는 가중치
- 같은 필터를 이미지의 여러 위치에서 공유하므로 지역 패턴을 효율적으로 탐색
- 필터 하나는 하나의 피처 맵을 생성하며, 필터 수는 출력 채널 수와 같음
주요 용어
- 지역 패치(local patch): 필터가 한 번에 읽는 입력의 작은 영역
- 필터 또는 커널: 지역 패치와 곱하고 더할 학습 가능한 가중치
- 수용 영역(receptive field): 특정 뉴런의 값에 영향을 주는 원본 입력 영역
- 피처 맵(feature map): 필터가 각 위치에서 계산한 합성곱 출력
첫 번째 합성곱 레이어에서는 커널이 덮는 입력 영역이 해당 출력 뉴런의 수용 영역. 여러 레이어를 거치면 한 뉴런의 수용 영역이 이전 레이어를 통해 점차 넓어짐.

부분 특징에서 전체 특징으로
- 얕은 레이어는 선, 방향, 모서리 같은 낮은 수준의 특징을 추출
- 다음 레이어는 앞에서 찾은 특징을 조합해 눈, 코, 입처럼 더 큰 패턴을 표현
- 깊은 레이어는 부분 특징을 다시 조합해 얼굴이나 사물 전체에 가까운 특징을 표현
- 실제로 학습되는 특징은 데이터와 학습 목표에 따라 달라짐

풀링 pooling
- 풀링은 피처 맵의 지역 값을 요약해 공간 크기를 줄이는 다운샘플링
- 학습하는 가중치가 없으며 합성곱 레이어 수를 자동으로 줄이지 않음
- 공간 크기가 줄어 이후 레이어의 연산량과 Dense 레이어의 파라미터 수를 줄일 수 있음
- 세부 위치 정보가 손실되므로 위치가 중요한 작업에서는 성능에 영향을 줄 수 있음
- 최대 풀링(max pooling)은 지역의 최댓값을 선택
- 평균 풀링(average pooling)은 지역의 평균값을 계산


CNN의 기본 구조
- 특징 추출 부분: 합성곱, 활성화 함수, 필요에 따른 풀링
- 분류 부분:
Flatten또는 전역 풀링으로 특징을 모은 뒤 Dense 레이어로 예측 Flatten은 한 가지 연결 방법이며 모든 CNN에 필수인 것은 아님

합성곱의 공간 크기를 조절하는 방법은 패딩과 스트라이드에서 학습. 대표 모델 구조는 CNN의 다양한 구조에서 이어서 학습.
Keras 실습
데이터 준비
노트북과 같은 Torch 백엔드와 난수 초기값을 사용.
import os
os.environ["KERAS_BACKEND"] = "torch"
import keras
import numpy as np
keras.utils.set_random_seed(812) # 실행 결과 재현용 난수 초기값
Fashion MNIST를 불러오면 훈련 이미지에는 채널 축이 없는 (60000, 28, 28) 형태가 저장됨.
(x_train, y_train), (x_test, y_test) = (
keras.datasets.fashion_mnist.load_data()
)
x_train.shape, y_train.shape, x_test.shape, y_test.shape
실행 결과
((60000, 28, 28), (60000,), (10000, 28, 28), (10000,))
첫 실행에서는 데이터 다운로드 진행 상황이 함께 표시될 수 있음.
- 훈련 이미지 60,000개와 테스트 이미지 10,000개
- 각 이미지는 28×28 크기의 흑백 이미지
Conv2D입력을 위해 마지막에 채널 축 추가 필요
CNN 구성
- 첫 합성곱은
padding="same"으로 28×28 공간 크기를 유지하며 피처 맵 32개 생성 - 2×2 최대 풀링은 공간 크기를 14×14로 축소
- 두 번째 합성곱은 피처 맵 64개를 생성
- 두 번째 풀링 뒤
Flatten으로 분류용 벡터 생성 - 마지막 Dense 레이어는 10개 클래스의 로짓 출력
padding="same"의 크기 계산은 패딩과 스트라이드에서 확인.
x_train_cnn = np.expand_dims(x_train, axis=-1) # 채널 축 추가
x_test_cnn = np.expand_dims(x_test, axis=-1)
keras.utils.set_random_seed(812) # 모델 가중치 초기값 재현
cnn_model = keras.models.Sequential([
keras.Input(shape=(28, 28, 1)), # 28×28 흑백 이미지
keras.layers.Rescaling(1/255), # 픽셀값을 0~1로 변환
# 공간 크기를 유지하며 지역 특징 32개 추출
keras.layers.Conv2D(
32, (3, 3), padding="same", activation="relu"
),
# 높이와 너비를 각각 절반으로 축소
keras.layers.MaxPooling2D((2, 2)),
# 더 깊은 지역 특징 64개 추출
keras.layers.Conv2D(64, (3, 3), activation="relu"),
keras.layers.MaxPooling2D((2, 2)),
keras.layers.Flatten(),
keras.layers.Dense(10), # 10개 클래스의 로짓
])
cnn_model.compile(
# 실습에서 사용할 고정 학습률
optimizer=keras.optimizers.SGD(learning_rate=0.001),
loss=keras.losses.SparseCategoricalCrossentropy(
from_logits=True # 마지막 Dense가 로짓을 출력
),
metrics=["accuracy"],
)
각 레이어의 출력 형태와 전체 파라미터 수를 확인.
for layer in cnn_model.layers:
print(layer.__class__.__name__, tuple(layer.output.shape))
cnn_model.count_params()
실행 결과
Rescaling (None, 28, 28, 1)
Conv2D (None, 28, 28, 32)
MaxPooling2D (None, 14, 14, 32)
Conv2D (None, 12, 12, 64)
MaxPooling2D (None, 6, 6, 64)
Flatten (None, 2304)
Dense (None, 10)
41866
- 첫 합성곱 출력은 28×28×32
- 첫 풀링 출력은 14×14×32
- 두 번째 합성곱과 풀링을 거친 출력은 6×6×64
Flatten은 개 특징으로 변환- 전체 학습 파라미터는 41,866개
모델 훈련
- 최대 5에포크 훈련
- 한 배치에는 이미지 64개 사용
- 훈련 데이터의 20%를 검증 데이터로 사용
- SGD 학습률은
0.001로 지정
cnn_history = cnn_model.fit(
x_train_cnn,
y_train,
epochs=5, # 짧은 실습을 위한 반복 횟수
batch_size=64, # 한 번에 처리할 이미지 수
validation_split=0.2, # 훈련 데이터의 20%로 검증
verbose=0, # 마지막 지표만 확인
)
cnn_history.history["accuracy"][-1] # 훈련 정확도
실행 결과
0.6410416960716248
cnn_history.history["val_accuracy"][-1] # 검증 정확도
실행 결과
0.659500002861023
cnn_history.history["val_loss"][-1] # 검증 손실
실행 결과
1.0048625469207764
- 5번째 에포크의 훈련 정확도는
0.6410, 검증 정확도는0.6595 - 검증 손실은
1.0049 - 실행 장치와 라이브러리 버전에 따라 구체적인 값은 달라질 수 있음
테스트 데이터 평가
cnn_test_loss, cnn_test_accuracy = cnn_model.evaluate(
x_test_cnn, y_test, verbose=0 # 진행 막대 숨김
)
cnn_test_accuracy # 테스트 정확도
실행 결과
0.6417999863624573
- 테스트 정확도는 약 64.18%
- 테스트 데이터는 모델 선택이나 훈련에 사용하지 않고 마지막 성능 확인에만 사용
- 이 결과는 5에포크만 훈련한 간단한 CNN의 성능이며 CNN 전체의 일반적인 성능을 뜻하지 않음