forward()가 하는 일입력 → 연산 → 출력
forward() 안에서 self.conv1, self.pool, self.upconv 같은 레이어를 차례대로 호출해 입력 x를 변형시킵니다.
x = torch.relu(self.conv1(x)) # [B, 32, 128, 128]
x = self.pool(x) # [B, 32, 64, 64]
x = self.upconv(x) # [B, 3, 128, 128]
return x
계산 그래프 기록
forward() 안에서 수행되는 모든 연산(Conv, Pool, ReLU 등)은 autograd에 의해 자동으로 기록됩니다.
따라서 나중에 손실(loss)에 대해 loss.backward()를 호출하면, autograd가 이 그래프를 따라 역전파(Back‑Propagation)를 수행해 파라미터에 대한 기울기를 계산합니다.
모델 호출
실제로 모델을 사용하려면 output = model(input)처럼 model(input) 로 호출합니다.
nn.Module 내부의 __call__ 메서드가 먼저 실행되고, 그 안에서 self.forward()가 호출됩니다.
그래서 보통 model.forward() 를 직접 호출할 필요는 없으며, model(x) 를 쓰는 것이 관례입니다.
[B, 32, 128, 128] 이 나오는가?| 차원 | 의미 | 계산식 (conv1) |
|---|---|---|
| B | 배치 크기 (Batch Size) | 입력에서 그대로 전달 |
| 32 | feature map(채널) 수 | conv1 가 out_channels=32 로 정의되었으므로 32개의 채널을 생성 |
| 128 | 높이 | H_out = floor((H_in + 2·padding – kernel_size)/stride + 1)입력 높이 H_in = 128, padding = 1, kernel = 3, stride = 1 → 128 |
| 128 | 너비 | 위와 동일 (W_in = 128) |
[B, 3, 128, 128] 인 경우x = torch.randn(B, 3, 128, 128) # 예시 입력
x = torch.relu(self.conv1(x)) # conv1 -> [B, 32, 128, 128]
conv1 은 3채널(입력) → 32채널(출력) 으로 바꾸고, 주의: 입력이 다른 크기(예: 224x224)라면, conv1 후에도 같은 공식을 적용해 다른 HxW 가 나오게 됩니다.
B 가 무엇인가?B는 배치 크기를 나타내는 차원입니다.
B 값은 학습 중에 자유롭게 정할 수 있으며, 일반적으로 8, 16, 32, 64 등으로 설정합니다.예시:
B 값 | 입력 텐서 모양 (예시) | 의미 |
|---|---|---|
| 1 | [1, 3, 128, 128] | 한 장의 이미지 (테스트/추론 시) |
| 32 | [32, 3, 128, 128] | 한 번에 32장의 이미지 (훈련 시) |
batch = 32
input_imgs = torch.randn(batch, 3, 128, 128) # [32, 3, 128, 128]
output = model(input_imgs) # output shape -> [32, 3, 128, 128]
conv1 뒤에 MaxPool2d(2,2) 를 넣었으니, 공간 해상도는 2배로 감소됩니다. ConvTranspose2d(업컨볼루션) 로 2배로 증가시켜 원래 해상도로 복원합니다.즉, [B, 32, 128, 128] 형태는 컨볼루션 연산과 파라미터(채널 수, 커널 크기, padding, stride) 설정에 의해 결정되며, FCN이라서만 그런 것이 아니라 일반적인 CNN에서도 동일한 규칙이 적용됩니다.
x = torch.relu(self.conv1(x)) # conv1 : 3→32 채널, H,W = 128→128 (stride=1, padding=1)
conv1 은 nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1) 로 정의되었습니다. H_out = (H_in + 2*padding - kernel_size) // stride + 1W_out 역시 같은 계산.x = self.pool(x) # MaxPool2d(2,2) → H,W = 128→64 (2배 축소)
x = self.upconv(x) # ConvTranspose2d(32, 3, kernel_size=2, stride=2) → H,W = 64→128 (2배 확대)
결과적으로 최종 출력은 원본 이미지와 동일한 해상도(128x128) 가지만 채널 수는 다시 3(RGB)으로 바뀝니다.
| 항목 | 설명 |
|---|---|
| B | 배치 크기(한 번에 넣는 이미지 개수) |
| 32 | conv1 가 생성한 feature map(채널) 수 |
| 128 × 128 | 입력 해상도(높이 × 너비) → conv1 에서 그대로 유지 |
| FCN | FCN이란 풀링 없이(또는 필요에 따라) 공간 해상도를 보존/복원하는 구조이지만, 실제 차원 변화는 커널, stride, padding, pooling 설정에 따라 결정 |
forward()와 train() / eval() 모드model.train() : Dropout, BatchNorm 같은 레이어가 학습 모드로 동작하도록 설정합니다. model.eval() : 동일 레이어가 평가(추론) 모드로 동작하도록 설정합니다. 이러한 모드 전환은 forward() 안에서 self.training 플래그를 확인해 조건부 로직을 넣을 때 사용됩니다.
예를 들어:
def forward(self, x):
if self.training:
x = torch.dropout(x, p=0.5, training=True)
return x
하지만 forward() 그 자체가 학습/추론 모드에 관계없이 순전파 로직만 수행합니다.
model = FCN()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
for epoch in range(num_epochs):
for inputs, targets in dataloader: # inputs: [B,3,H,W], targets: [B, H, W] (클래스 라벨)
optimizer.zero_grad() # 기울기 초기화
outputs = model(inputs) # <‑‑ forward() 실행
loss = criterion(outputs, targets) # 손실 계산
loss.backward() # 역전파(Back‑Propagation) 실행
optimizer.step() # 파라미터 업데이트
forward() 는 여기서 outputs = model(inputs) 를 통해서만 호출됩니다.
loss.backward() 가 호출될 때 autograd가 forward() 에서 생성된 연산 그래프를 따라 기울기를 계산합니다.
| 용어 | 의미 |
|---|---|
| forward() | 입력 데이터를 받아서 레이어를 순서대로 적용한 뒤, 출력을 반환하는 함수. (순전파) |
| backward() | 손실에 대한 기울기를 계산하는 함수. autograd가 forward() 에서 기록된 연산 그래프를 이용해 자동으로 수행. |
| model(x) | nn.Module 의 __call__ 메서드가 forward() 를 호출. (일반적으로 이렇게 사용) |
따라서 forward()는 바로 “순전파”를 담당하는 함수이며, 학습 루프 안에서 model(inputs) 로 호출하면 자동으로 실행됩니다.