🤖 AI/ML

배치 정규화

Batch Normalization

각 레이어의 입력을 정규화하여 학습을 안정화하는 기법. 학습 속도 향상과 과적합 방지.

📖 상세 설명

배치 정규화(Batch Normalization, BatchNorm)는 2015년 Sergey Ioffe와 Christian Szegedy가 발표한 기법으로, 신경망의 각 레이어 입력을 정규화하여 학습을 안정화하고 가속화합니다. 미니 배치 단위로 평균을 0, 분산을 1로 맞춘 후, 학습 가능한 파라미터(gamma, beta)로 스케일링과 시프트를 적용합니다.

BatchNorm이 등장하기 전에는 Internal Covariate Shift 문제로 인해 깊은 신경망 학습이 어려웠습니다. 각 레이어의 입력 분포가 학습 중 계속 변화하면서 가중치가 불안정해지는 현상인데, BatchNorm은 이를 해결하여 더 높은 학습률 사용과 빠른 수렴을 가능하게 했습니다.

BatchNorm의 핵심 수식은 x_normalized = (x - mean) / sqrt(variance + epsilon)이며, 최종 출력은 y = gamma * x_normalized + beta입니다. 학습 시에는 배치 통계를 사용하고, 추론 시에는 학습 중 누적된 이동 평균(running mean/variance)을 사용합니다.

실무에서 BatchNorm은 CNN, ResNet, EfficientNet 등 대부분의 컴퓨터 비전 모델에서 표준으로 사용됩니다. 다만 배치 크기가 작거나(< 16), RNN/Transformer에서는 Layer Normalization이나 Group Normalization을 대신 사용합니다. 2024년 현재도 이미지 분류, 객체 탐지 등에서 필수 구성 요소입니다.

💻 코드 예제

# PyTorch에서 배치 정규화 사용 예제
import torch
import torch.nn as nn

class ConvBlockWithBatchNorm(nn.Module):
    """
    Conv -> BatchNorm -> ReLU 패턴의 기본 블록
    대부분의 CNN 아키텍처에서 표준으로 사용됩니다.
    """
    def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1):
        super().__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, bias=False)
        # bias=False: BatchNorm의 beta가 bias 역할을 하므로 불필요
        self.bn = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU(inplace=True)

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x

# ResNet 스타일 Residual Block with BatchNorm
class ResidualBlock(nn.Module):
    def __init__(self, channels):
        super().__init__()
        self.conv1 = nn.Conv2d(channels, channels, 3, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(channels)
        self.conv2 = nn.Conv2d(channels, channels, 3, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(channels)
        self.relu = nn.ReLU(inplace=True)

    def forward(self, x):
        residual = x
        out = self.relu(self.bn1(self.conv1(x)))
        out = self.bn2(self.conv2(out))
        out += residual  # Skip connection
        return self.relu(out)

# 모델 생성 및 학습/추론 모드 전환
model = ResidualBlock(64)

# 학습 모드: 배치 통계 사용 + running stats 업데이트
model.train()
x_train = torch.randn(32, 64, 56, 56)  # batch=32
output_train = model(x_train)

# 추론 모드: running mean/variance 사용
model.eval()
with torch.no_grad():
    x_test = torch.randn(1, 64, 56, 56)  # 단일 이미지도 OK
    output_test = model(x_test)

print(f"학습 출력 shape: {output_train.shape}")
print(f"추론 출력 shape: {output_test.shape}")

🗣️ 실무에서 이렇게 말하세요

💬 회의에서
"학습이 불안정하다면 BatchNorm 레이어가 제대로 들어가 있는지 확인해보세요. Conv 다음에 BatchNorm을 넣으면 학습률을 10배까지 높일 수 있어서 수렴 속도가 크게 개선됩니다. 단, 추론 시에는 반드시 model.eval()을 호출해야 합니다."
💬 면접에서
"BatchNorm은 Internal Covariate Shift 문제를 해결하기 위해 제안되었습니다. 미니 배치의 평균과 분산으로 정규화한 후, gamma와 beta 파라미터로 선형 변환을 적용합니다. 학습 시에는 배치 통계를, 추론 시에는 running statistics를 사용하는 것이 핵심입니다."
💬 기술 토론에서
"배치 크기가 8 이하로 작으면 BatchNorm 대신 GroupNorm을 사용하는 게 좋아요. GPU 메모리 제약으로 큰 배치를 못 쓰는 상황에서 BatchNorm은 통계가 불안정해져서 성능이 떨어집니다. Transformer에서는 LayerNorm이 표준이고요."

⚠️ 흔한 실수 & 주의사항

추론 시 model.eval() 누락

추론 시 model.eval()을 호출하지 않으면 배치 통계를 사용하게 되어, 단일 이미지 추론에서 예측값이 불안정해집니다. 배치 크기가 1일 때 특히 심각한 문제가 발생합니다.

작은 배치 크기에서 사용

배치 크기가 4 이하일 때 BatchNorm을 사용하면 배치 통계가 불안정해져 성능이 크게 저하됩니다. 의료 영상, 고해상도 이미지 등 메모리 제약이 있는 경우 GroupNorm이나 LayerNorm을 사용하세요.

올바른 방법: 상황에 맞는 정규화 선택

CNN + 충분한 배치 크기(16+)에서는 BatchNorm, RNN/Transformer에서는 LayerNorm, 작은 배치에서는 GroupNorm을 사용하세요. Conv 레이어에는 bias=False를 설정하여 중복 파라미터를 제거합니다.

🔗 관련 용어

📚 더 배우기