
📓Google Colab에서 실습하기
이 레슨은 PyTorch/GPU가 필요합니다. 노트북을 다운로드 후 Google Colab에서 열어주세요.
학습 내용
합성곱 연산
학습 목표
이 레슨을 완료하면:
- •합성곱 연산의 원리를 이해합니다
- •커널/필터의 역할을 배웁니다
- •스트라이드와 패딩의 효과를 이해합니다
- •특성 맵(Feature Map)의 의미를 파악합니다
핵심 메시지
"합성곱은 작은 창문으로 이미지를 훑으면서 특징을 찾아내는 연산입니다." 3×3 크기의 작은 필터가 이미지 위를 슬라이딩하면서 "여기에 세로선이 있나?", "모서리가 있나?" 같은 질문에 답합니다.
1. 합성곱(Convolution)이란?
비유: 돋보기로 신문을 읽는다고 상상해보세요. 돋보기(커널)를 신문(이미지) 위에서 한 칸씩 이동하면서 글자(특징)를 확인합니다. 합성곱은 이와 비슷하게 작은 필터로 이미지 전체를 훑으면서 패턴을 감지합니다.
MLP vs CNN 비교
| 특성 | MLP | CNN |
|---|---|---|
| 이미지 처리 | 1차원으로 펼침 (flatten) | 2D 구조 유지 |
| 공간 정보 | 손실됨 | 보존됨 |
| 파라미터 수 | 매우 많음 | 적음 (가중치 공유) |
| 위치 불변성 | 없음 | 있음 |
2. 합성곱 계산 방법
합성곱 연산은 커널과 이미지 영역의 요소별 곱셈 후 합산입니다.
계산 예시
입력 이미지의 3×3 영역과 3×3 커널:
| 이미지 영역 | 커널 |
|---|---|
| 1, 2, 3 | 1, 0, 1 |
| 0, 1, 2 | 0, 1, 0 |
| 1, 2, 1 | 1, 0, 1 |
계산: (1×1) + (2×0) + (3×1) + (0×0) + (1×1) + (2×0) + (1×1) + (2×0) + (1×1) = 8
이 과정을 이미지 전체에서 반복하면 **특성 맵(Feature Map)**이 생성됩니다.
🔬 실습: 합성곱 연산 직접 구현
pythonimport numpy as np import matplotlib.pyplot as plt # ═══════════════════════════════════════════════════════════════ # 📊 합성곱 연산 직접 구현하기 # ═══════════════════════════════════════════════════════════════ def conv2d_manual(image, kernel): """합성곱 연산을 직접 구현 (padding=0, stride=1)""" h, w = image.shape kh, kw = kernel.shape out_h = h - kh + 1 out_w = w - kw + 1 output = np.zeros((out_h, out_w)) for i in range(out_h): for j in range(out_w): # 이미지 영역과 커널의 요소별 곱 후 합산 region = image[i:i+kh, j:j+kw] output[i, j] = np.sum(region * kernel) return output # 5×5 입력 이미지 image = np.array([ [1, 2, 3, 0, 1], [0, 1, 2, 3, 1], [1, 2, 1, 0, 0], [0, 1, 1, 2, 1], [2, 0, 1, 1, 0] ], dtype=float) # 3×3 커널 (엣지 검출용) kernel = np.array([ [1, 0, -1], [1, 0, -1], [1, 0, -1] ], dtype=float) # 합성곱 수행 output = conv2d_manual(image, kernel) print("=" * 50) print("📊 합성곱 연산 결과") print("=" * 50) print(f"입력 이미지 크기: {image.shape}") print(f"커널 크기: {kernel.shape}") print(f"출력 크기: {output.shape}") print(f"\n출력 특성 맵:\n{output}") # 시각화 fig, axes = plt.subplots(1, 3, figsize=(12, 4)) axes[0].imshow(image, cmap='gray') axes[0].set_title('Input Image (5x5)', fontsize=12) axes[0].axis('off') axes[1].imshow(kernel, cmap='RdBu', vmin=-1, vmax=1) axes[1].set_title('Kernel (Vertical Edge)', fontsize=12) axes[1].axis('off') axes[2].imshow(output, cmap='gray') axes[2].set_title('Output Feature Map (3x3)', fontsize=12) axes[2].axis('off') plt.suptitle('Convolution Operation', fontsize=14, fontweight='bold') plt.tight_layout() plt.show() print("\n💡 커널이 이미지를 훑으면서 수직 엣지를 감지했습니다!")
3. 커널(필터)의 역할
커널은 학습 가능한 작은 가중치 행렬입니다. 각 커널은 특정 패턴이나 특징을 감지합니다.
일반적인 커널 크기
| 크기 | 용도 |
|---|---|
| 3×3 | 가장 많이 사용, 효율적 |
| 5×5 | 더 넓은 영역 감지 |
| 7×7 | 초기 레이어에서 가끔 사용 |
| 1×1 | 채널 수 조정용 |
커널의 특징 검출 예시
| 커널 종류 | 역할 |
|---|---|
| 수평 엣지 | 가로선 감지 |
| 수직 엣지 | 세로선 감지 |
| 가우시안 | 블러 (노이즈 제거) |
| 샤프닝 | 선명도 강화 |
4. 스트라이드(Stride)
스트라이드 = 커널이 이동하는 칸 수
| 스트라이드 | 효과 |
|---|---|
| 1 (기본값) | 한 칸씩 이동, 출력 크기 큼 |
| 2 | 두 칸씩 이동, 출력 크기 절반 |
출력 크기 계산
출력 크기 = (입력 - 커널) / 스트라이드 + 1
| 입력 | 커널 | 스트라이드 | 출력 |
|---|---|---|---|
| 7×7 | 3×3 | 1 | 5×5 |
| 7×7 | 3×3 | 2 | 3×3 |
| 32×32 | 3×3 | 1 | 30×30 |
5. 패딩(Padding)
패딩 = 이미지 가장자리에 값을 추가하여 출력 크기를 조절
패딩의 필요성
합성곱 후에는 크기가 줄어듭니다:
- •입력 5×5 → (3×3 커널) → 출력 3×3
패딩을 사용하면 크기를 유지할 수 있습니다:
- •입력 5×5 + 패딩 1 → (3×3 커널) → 출력 5×5
패딩 종류
| 종류 | 설명 |
|---|---|
| Valid (패딩 없음) | 크기 감소 |
| Same | 출력 = 입력 크기 |
| Zero Padding | 0으로 채움 (가장 일반적) |
완전한 출력 크기 공식
출력 = (입력 + 2×패딩 - 커널) / 스트라이드 + 1
🔬 실습: 스트라이드와 패딩 효과
python⚠️ 로컬 실행 필요import torch import torch.nn as nn # ═══════════════════════════════════════════════════════════════ # 📊 스트라이드와 패딩에 따른 출력 크기 변화 # ═══════════════════════════════════════════════════════════════ def test_conv_output(in_size, kernel, stride, padding): """합성곱 출력 크기 테스트""" conv = nn.Conv2d(1, 1, kernel_size=kernel, stride=stride, padding=padding) x = torch.randn(1, 1, in_size, in_size) out = conv(x) return out.shape[-1] print("=" * 60) print("📊 합성곱 출력 크기 실험") print("=" * 60) print(f"{'설정':<30} {'출력 크기':<10}") print("-" * 40) # 다양한 설정 테스트 configs = [ (32, 3, 1, 0, "기본 (패딩 없음)"), (32, 3, 1, 1, "Same 패딩"), (32, 3, 2, 0, "Stride=2"), (32, 3, 2, 1, "Stride=2 + 패딩"), (32, 5, 1, 2, "5×5 커널, Same"), ] for in_size, kernel, stride, padding, desc in configs: out_size = test_conv_output(in_size, kernel, stride, padding) print(f"입력={in_size}, k={kernel}, s={stride}, p={padding} ({desc}): {out_size}×{out_size}") # 공식으로 직접 계산 print("\n" + "=" * 60) print("📐 출력 크기 공식: (입력 + 2×패딩 - 커널) / 스트라이드 + 1") print("=" * 60) for in_size, kernel, stride, padding, desc in configs: calc = (in_size + 2*padding - kernel) // stride + 1 print(f"({in_size} + 2×{padding} - {kernel}) / {stride} + 1 = {calc}") print("\n💡 패딩=1, 커널=3, 스트라이드=1이면 크기가 유지됩니다!")
6. PyTorch로 합성곱 구현
python⚠️ 로컬 실행 필요import torch import torch.nn as nn # ═══════════════════════════════════════════════════════════════ # 📊 PyTorch Conv2d 사용법 # ═══════════════════════════════════════════════════════════════ # 합성곱 레이어 정의 conv = nn.Conv2d( in_channels=3, # 입력 채널 수 (RGB) out_channels=64, # 출력 채널 수 (필터 개수) kernel_size=3, # 커널 크기 3×3 stride=1, # 스트라이드 padding=1 # 패딩 (same) ) # 입력: (배치, 채널, 높이, 너비) x = torch.randn(1, 3, 32, 32) output = conv(x) print("=" * 50) print("📊 Conv2d 레이어 분석") print("=" * 50) print(f"입력 shape: {x.shape}") print(f"출력 shape: {output.shape}") # 파라미터 수 계산 # 가중치: out_channels × in_channels × kernel × kernel # 편향: out_channels weight_params = 64 * 3 * 3 * 3 bias_params = 64 total_params = sum(p.numel() for p in conv.parameters()) print(f"\n파라미터 수:") print(f" 가중치: {weight_params} (64 × 3 × 3 × 3)") print(f" 편향: {bias_params}") print(f" 총합: {total_params}")
핵심 요약
| 개념 | 핵심 내용 | 기억할 포인트 |
|---|---|---|
| 합성곱 | 커널 × 이미지 영역의 합 | 특징 추출기 |
| 커널 | 학습되는 가중치 행렬 | 보통 3×3 사용 |
| 스트라이드 | 커널 이동 칸 수 | 크면 출력 작아짐 |
| 패딩 | 가장자리에 값 추가 | 크기 유지 가능 |
| 출력 크기 | (입력 + 2P - K) / S + 1 | 공식 암기! |
학습 체크리스트
- • 합성곱 연산 과정을 설명할 수 있다
- • 커널의 특징 추출 역할을 이해한다
- • 스트라이드와 패딩의 효과를 안다
- • 출력 크기 계산 공식을 사용할 수 있다
다음 강의 예고
"풀링과 정규화" - 특성 맵의 크기를 줄이고 학습을 안정화하는 기법을 배웁니다!
레슨 정보
- 레벨
- Level 5: CNN & 이미지 처리
- 예상 소요 시간
- 50분
- 참고 영상
- YouTube 링크
💡실습 환경 안내
이 레벨은 PyTorch/GPU가 필요하여 Google Colab 사용을 권장합니다.
Colab은 무료 GPU를 제공하여 PyTorch, CNN, Transformer 등을 실행할 수 있습니다.