Level 4: 실전 프로젝트
🚀

Level 4

nn.Module 기초

레이어 정의, forward(), 파라미터 관리

약 4분
nn.Module 기초 강의 영상
강의 영상 보기 (새 탭에서 재생)YouTube

📓Google Colab에서 실습하기

이 레슨은 PyTorch/GPU가 필요합니다. 노트북을 다운로드 후 Google Colab에서 열어주세요.

학습 내용

nn.Module 기초

학습 목표

이 레슨을 완료하면:

  • nn.Module이 PyTorch에서 차지하는 역할을 이해합니다
  • 커스텀 모델과 레이어를 자유롭게 설계할 수 있습니다
  • forward() 메서드의 동작 원리를 설명합니다
  • 파라미터를 확인하고 관리하는 방법을 익힙니다

nn.Module이란?

비유: nn.Module은 레고의 "기본 브릭"과 같습니다. 작은 브릭(개별 레이어)을 조합해 더 큰 구조물(모델)을 만들고, 그 구조물을 또다시 더 큰 구조물의 부품으로 사용할 수 있습니다. PyTorch의 모든 신경망 구성 요소는 이 기본 브릭을 기반으로 만들어집니다.

nn.Module은 PyTorch에서 모든 신경망 레이어와 모델의 기본 클래스(부모 클래스) 입니다.

기능설명예시
파라미터 관리학습 가능한 가중치 자동 추적model.parameters()
디바이스 이동GPU/CPU 간 이동model.to("cuda")
모드 전환학습/평가 모드 전환model.train() / model.eval()
저장/로드모델 가중치 저장 및 복원torch.save(model.state_dict(), ...)
서브모듈 관리하위 레이어 자동 등록model.children()

기본 구조: 반드시 지켜야 할 규칙

python
⚠️ 로컬 실행 필요
import torch import torch.nn as nn class MyModel(nn.Module): def __init__(self): # [규칙 1] 반드시 부모 클래스 초기화를 호출해야 합니다 super().__init__() # [규칙 2] __init__에서 레이어를 정의합니다 self.layer1 = nn.Linear(784, 256) self.layer2 = nn.Linear(256, 10) def forward(self, x): # [규칙 3] forward에서 데이터 흐름을 정의합니다 x = torch.relu(self.layer1(x)) x = self.layer2(x) return x

왜 super().init()이 필수인가?

super().init()을 호출하지 않으면 PyTorch가 내부적으로 사용하는 파라미터 추적 시스템이 초기화되지 않습니다. 결과적으로:

  • model.parameters()가 빈 리스트를 반환합니다
  • model.to(device)가 작동하지 않습니다
  • optimizer가 학습할 파라미터를 찾지 못합니다

이것은 PyTorch 초보자가 가장 자주 겪는 오류 중 하나입니다.


자주 사용하는 레이어 총정리

완전 연결층 (Linear)

비유: nn.Linear는 "투표 시스템"입니다. 각 입력에 가중치(투표 영향력)를 곱하고 합산하여 결과를 냅니다.

python
# 784개 입력을 받아 256개 출력을 만드는 레이어 linear = nn.Linear(in_features=784, out_features=256) # 내부적으로 가중치 행렬 [256, 784]와 편향 벡터 [256]을 가짐

합성곱층 (Conv2d)

python
# 3채널 입력, 64채널 출력, 3x3 필터 conv = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, padding=1)

활성화 함수

python
relu = nn.ReLU() # max(0, x) - 음수를 0으로 sigmoid = nn.Sigmoid() # 0~1 사이로 압축 tanh = nn.Tanh() # -1~1 사이로 압축
활성화 함수출력 범위주로 사용되는 곳
ReLU[0, +무한)은닉층 (가장 보편적)
Sigmoid(0, 1)이진 분류 출력층
Tanh(-1, 1)RNN 은닉 상태
Softmax(0, 1), 합=1다중 분류 출력층

정규화 레이어

python
bn = nn.BatchNorm2d(64) # 배치 정규화 (CNN용) bn1d = nn.BatchNorm1d(256) # 배치 정규화 (FC용) dropout = nn.Dropout(0.5) # 50% 뉴런을 무작위로 끔

nn.Sequential: 간단한 모델 만들기

레이어가 단순히 순서대로 연결되는 경우, nn.Sequential을 사용하면 코드가 간결해집니다.

python
# 방법 1: nn.Sequential 사용 (간결) model_simple = nn.Sequential( nn.Linear(784, 256), nn.ReLU(), nn.Dropout(0.5), nn.Linear(256, 10) ) # 방법 2: nn.Module 상속 (유연) class ModelFlexible(nn.Module): def __init__(self): super().__init__() self.fc1 = nn.Linear(784, 256) self.fc2 = nn.Linear(256, 10) self.dropout = nn.Dropout(0.5) def forward(self, x): x = torch.relu(self.fc1(x)) x = self.dropout(x) x = self.fc2(x) return x
비교 항목nn.Sequentialnn.Module 상속
코드 길이짧음
유연성낮음 (순차적만 가능)높음 (분기, 잔차 연결 등)
가독성단순 모델에서 좋음복잡 모델에서 좋음
적합한 경우레이어가 순서대로복잡한 데이터 흐름

왜 nn.Module 상속이 더 많이 사용되는가?

실제 모델은 단순히 레이어를 쌓는 것 이상입니다. 잔차 연결(ResNet), 다중 입력/출력, 조건부 분기 등을 구현하려면 forward()를 직접 작성해야 합니다.


파라미터 확인과 관리

모델이 정확히 어떤 파라미터를 가지고 있는지 확인하는 것은 디버깅과 최적화에 매우 중요합니다.

python
model = ModelFlexible() # 모든 파라미터의 이름과 크기 출력 for name, param in model.named_parameters(): print("{}: {}".format(name, param.shape)) # 출력: # fc1.weight: torch.Size([256, 784]) # fc1.bias: torch.Size([256]) # fc2.weight: torch.Size([10, 256]) # fc2.bias: torch.Size([10]) # 총 파라미터 수 계산 total_params = sum(p.numel() for p in model.parameters()) print("Total parameters: {:,}".format(total_params)) # 출력: Total parameters: 203,530 # 학습 가능한 파라미터만 세기 trainable = sum(p.numel() for p in model.parameters() if p.requires_grad) print("Trainable parameters: {:,}".format(trainable))

모드 전환: train() vs eval()

비유: 축구 선수가 연습(train)할 때와 시합(eval)할 때 행동이 다르듯, 모델도 학습할 때와 평가할 때 동작이 달라야 합니다.

python
# 학습 모드: Dropout 활성화, BatchNorm이 배치 통계 사용 model.train() # 평가 모드: Dropout 비활성화, BatchNorm이 저장된 통계 사용 model.eval() # 평가 시에는 그래디언트 계산도 꺼서 메모리와 속도를 절약 with torch.no_grad(): output = model(test_data)
동작train() 모드eval() 모드
Dropout뉴런 무작위 비활성화모든 뉴런 활성화
BatchNorm현재 배치의 평균/분산 사용학습 중 누적된 평균/분산 사용
용도학습 루프검증/테스트/추론

실전 예제: 재사용 가능한 블록 설계

큰 모델은 반복되는 패턴을 "블록"으로 만들어 재사용하면 코드가 깔끔해집니다.

python
class ConvBlock(nn.Module): """Conv -> BatchNorm -> ReLU 패턴을 하나의 블록으로""" def __init__(self, in_ch, out_ch, kernel_size=3, padding=1): super().__init__() self.conv = nn.Conv2d(in_ch, out_ch, kernel_size, padding=padding) self.bn = nn.BatchNorm2d(out_ch) self.relu = nn.ReLU() def forward(self, x): return self.relu(self.bn(self.conv(x))) class MyNet(nn.Module): """ConvBlock을 재사용해서 모델 구성""" def __init__(self, num_classes=10): super().__init__() self.block1 = ConvBlock(3, 32) # 3채널 -> 32채널 self.block2 = ConvBlock(32, 64) # 32채널 -> 64채널 self.block3 = ConvBlock(64, 128) # 64채널 -> 128채널 self.pool = nn.MaxPool2d(2) self.fc = nn.Linear(128 * 4 * 4, num_classes) def forward(self, x): x = self.pool(self.block1(x)) # 32x32 -> 16x16 x = self.pool(self.block2(x)) # 16x16 -> 8x8 x = self.pool(self.block3(x)) # 8x8 -> 4x4 x = x.view(x.size(0), -1) # Flatten return self.fc(x) model = MyNet(num_classes=10)

블록 기반 설계의 장점:

  1. 코드 중복 제거: 같은 패턴을 반복 작성하지 않아도 됩니다
  2. 수정 용이: 블록 하나만 수정하면 모든 곳에 반영됩니다
  3. 가독성 향상: 모델 구조를 한눈에 파악할 수 있습니다

핵심 요약

개념설명비유
nn.Module모든 레이어/모델의 기본 클래스레고의 기본 브릭
init레이어 정의부품 목록
forward데이터 흐름 정의조립 설명서
parameters()학습 가능한 가중치 반환조절 가능한 나사들
train()/eval()모드 전환연습/시합 모드 전환
nn.Sequential순차적 레이어 묶음파이프라인

학습 체크리스트

  • super().init()을 호출해야 하는 이유를 안다
  • __init__과 forward의 역할 차이를 설명할 수 있다
  • nn.Sequential과 nn.Module 상속의 차이를 안다
  • model.parameters()로 파라미터를 확인할 수 있다
  • train()과 eval() 모드에서 Dropout/BatchNorm의 동작 차이를 안다
  • 블록 기반 모델 설계의 장점을 이해한다

레슨 정보

레벨
Level 4: 실전 프로젝트
예상 소요 시간
약 4분
참고 영상
YouTube 링크

💡실습 환경 안내

이 레벨은 PyTorch/GPU가 필요하여 Google Colab 사용을 권장합니다.

Colab은 무료 GPU를 제공하여 PyTorch, CNN, Transformer 등을 실행할 수 있습니다.