위클리페이퍼

CNN을 구성하는 각 레이어의 역할에 대해 설명해보세요.

upstack 2026. 8. 10. 08:54

CNN(합성곱 신경망)이란?

- 이미지나 영상 데이터를 처리하는 데 특화된 딥러닝 모델

- 인간의 시신경 구조에서 영감을 받아 만들어졌으며, 이미지를 단순한 숫자의 나열이 아닌 '공간적인 구조'를 유지한 채로 분석하는 것입니다. 

CNN의 핵심 레이어 4가지

1. 합성곱 층 (Convolutional Layer)

 

  • 역할: 이미지에서 특징(Feature)을 찾아내는 가장 핵심적인 레이어
  • 동작 방식: 필터(Filter) 또는 커널(Kernel)이라고 불리는 작은 행렬이 이미지 위를 돋보기처럼 훑으며(Sliding) 겹치는 부분의 픽셀 값들과 수학적인 곱셈/덧셈(합성곱 연산)을 수행
  • 효과: 네트워크의 얕은 부분(초기 레이어)에서는 선, 모서리, 색상 같은 단순한 특징을 잡아내고, 층이 깊어질수록 눈, 코, 강아지의 얼굴 등 복잡하고 추상적인 패턴을 인식

 

2. 활성화 층 (Activation Layer)

 

  • 역할: 모델에 비선형성(Non-linearity)을 부여
  • 동작 방식: 합성곱 층을 통과해 나온 결과물(Feature Map)에 활성화 함수(주로 ReLU)를 적용하며,
                     ReLU는 결과값이 음수면 0으로 만들고, 양수면 그대로 통과시킵니다.
  • 효과: 현실 세계의 복잡한 데이터는 단순한 1차 방정식(선형 연산)들의 조합만으로는 표현할 수 없으며, 
             이 층을 거쳐야만 신경망이 복잡한 패턴을 제대로 학습할 수 있습니다.

 

3. 풀링 층 (Pooling Layer)

 

  • 역할: 데이터의 크기(차원)를 줄이고 핵심 정보만 남기는 압축 레이어
  • 동작 방식: 필터가 훑고 지나가면서 해당 영역에서 가장 큰 값만 뽑아내거나(Max Pooling), 평균값을 구합니다(Average Pooling).                  이미지 분류에서는 주로 Max Pooling을 사용합니다.
  • 효과: 불필요한 데이터를 버림으로써 연산량을 획기적으로 줄여 학습 속도를 높입니다.
             또한, 이미지 속 객체의 위치가 살짝 바뀌거나 회전해도 모델이 동일한 특징으로 인식할 수 있도록(공간적 불변성) 돕습니다.

 

4. 완전 연결 층 (Fully Connected Layer)

  • 역할: 앞서 추출되고 압축된 특징들을 종합하여 최종적인 판단(분류)을 내립니다.
  • 동작 방식: 합성곱과 풀링을 반복하며 만들어진 3차원 형태의 텐서를 1차원 벡터로 평탄화(Flatten)한 뒤, 일반적인 인공 신경망 구조(Dense Layer)에 통과시킵니다.
  • 효과: 최종적으로 Softmax 등의 함수를 거쳐 "이 이미지는 80% 확률로 강아지이고, 20% 확률로 고양이이다"와 같은 확률 기반의 예측값을 도출합니다.

 

 

샘플 코드 

[ PyTorch를 사용해서 합성곱(Conv) 층과 풀링(Pool) 층이 포함된 아주 기본적인 CNN 모델을 구성하는 샘플 코드 ]

  • 가장 널리 쓰이는 예제 중 하나인 '28x28 크기의 흑백 이미지(예: 손글씨 숫자)를 10가지로 분류하는 상황'을 가정하여 작성했습니다.
import torch
import torch.nn as nn
import torch.nn.functional as F

# 1. 모델 클래스 정의 (nn.Module 상속)
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        
        # [특징 추출 층 - Feature Extraction]
        # 첫 번째 합성곱 층: 흑백 이미지(채널 1)를 입력받아 16개의 특징 맵 생성
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=16, kernel_size=3, padding=1)
        
        # 첫 번째 풀링 층: 2x2 영역에서 가장 큰 값만 남겨 크기를 절반으로 줄임
        self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2)
        
        # 두 번째 합성곱 층: 16개 채널을 받아 32개의 더 복잡한 특징 맵 생성
        self.conv2 = nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, padding=1)
        
        # 두 번째 풀링 층: 다시 크기를 절반으로 줄임
        self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2)
        
        # [분류 층 - Classification]
        # 28x28 이미지가 두 번의 풀링을 거치면 7x7 크기가 됨 (28 -> 14 -> 7)
        # 평탄화(Flatten)된 벡터의 크기는 32(채널) * 7(가로) * 7(세로)
        self.fc1 = nn.Linear(32 * 7 * 7, 128)
        
        # 최종 출력 층: 10개의 클래스(0~9 숫자)에 대한 예측값 출력
        self.fc2 = nn.Linear(128, 10)

    # 2. 데이터가 층을 통과하는 순서 정의
    def forward(self, x):
        # 합성곱 -> ReLU 활성화 -> 풀링 (1단계)
        x = self.pool1(F.relu(self.conv1(x)))
        
        # 합성곱 -> ReLU 활성화 -> 풀링 (2단계)
        x = self.pool2(F.relu(self.conv2(x)))
        
        # 평탄화(Flatten): 3차원 특징 맵(32x7x7)을 1차원 벡터로 쫙 폅니다.
        # -1은 배치(Batch) 크기를 유지하라는 의미입니다.
        x = x.view(-1, 32 * 7 * 7)
        
        # 완전 연결 층 -> ReLU 활성화
        x = F.relu(self.fc1(x))
        
        # 최종 출력 (여기서는 분류를 위해 10개의 값이 나옵니다)
        x = self.fc2(x)
        return x

# ----------------------------------------------------
# 3. 모델 생성 및 테스트 해보기
# ----------------------------------------------------
model = SimpleCNN()
print("--- 모델 구조 ---")
print(model)

# 임의의 더미(Dummy) 데이터 생성 (배치 크기 1, 채널 1, 높이 28, 너비 28)
dummy_input = torch.randn(1, 1, 28, 28)

# 모델에 데이터를 통과시켜 예측값 도출
output = model(dummy_input)

print("\n--- 텐서 형태 변화 확인 ---")
print(f"입력 이미지 형태: {dummy_input.shape}")
print(f"최종 출력 형태: {output.shape} (1개의 데이터에 대한 10개의 클래스 예측 점수)")