정규화 (Regularization)
학습 목표
과적합(Overfitting)의 원인과 진단 방법을 이해한다
Dropout의 동작 원리와 학습/추론 시 차이를 설명할 수 있다
Batch Normalization과 Layer Normalization의 차이를 이해한다
실무에서 정규화 기법을 조합하여 적용할 수 있다
왜 중요한가
딥러닝 모델은 파라미터가 매우 많아 학습 데이터를 완벽하게 암기 할 수 있습니다. 이러한 과적합이 발생하면 학습 데이터에서는 높은 성능을 보이지만, 새로운 데이터에서는 성능이 급락합니다. 정규화 기법은 모델의 복잡도를 제약하여 일반화(Generalization) 성능을 높입니다.
Dropout
학습 시 뉴런을 확률 p p p 로 무작위 비활성화합니다. 매 학습 스텝마다 다른 부분 네트워크가 학습되어, 앙상블(Ensemble) 효과를 냅니다.
import torch
import torch.nn as nn
class MLPWithDropout ( nn . Module ):
def __init__ ( self , input_dim , hidden_dim , num_classes , dropout_rate = 0.5 ):
super (). __init__ ()
self .layers = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Dropout( p = dropout_rate), # 50% 확률로 뉴런 비활성화
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Dropout( p = dropout_rate),
nn.Linear(hidden_dim, num_classes),
)
def forward ( self , x ):
return self .layers(x)
model = MLPWithDropout( 784 , 256 , 10 , dropout_rate = 0.5 )
# 학습 모드: Dropout 활성화
model.train()
output_train = model(torch.randn( 1 , 784 ))
# 추론 모드: Dropout 비활성화 (모든 뉴런 사용, 가중치 스케일링)
model.eval()
output_eval = model(torch.randn( 1 , 784 ))
학습 시에는 반드시 model.train()을, 추론 시에는 model.eval()을 호출하세요. Dropout과 BatchNorm은 학습/추론 모드에서 동작이 다릅니다.
Batch Normalization (배치 정규화)
미니배치 내에서 각 특성의 평균을 0, 분산을 1로 정규화합니다. 내부 공변량 이동(Internal Covariate Shift)을 줄여 학습을 안정화하고 가속합니다.
x ^ i = x i − μ B σ B 2 + ϵ \hat{x}_i = \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}} x ^ i = σ B 2 + ϵ x i − μ B
y i = γ x ^ i + β y_i = \gamma \hat{x}_i + \beta y i = γ x ^ i + β
μ B , σ B 2 \mu_B, \sigma_B^2 μ B , σ B 2 : 미니배치의 평균과 분산
γ , β \gamma, \beta γ , β : 학습 가능한 스케일/시프트 파라미터
ϵ \epsilon ϵ : 수치 안정성을 위한 작은 값
# 1D 데이터 (MLP, RNN)
bn1d = nn.BatchNorm1d( num_features = 256 )
# 2D 데이터 (CNN) - 채널 방향 정규화
bn2d = nn.BatchNorm2d( num_features = 64 )
# CNN 예시
cnn_block = nn.Sequential(
nn.Conv2d( 3 , 64 , kernel_size = 3 , padding = 1 ),
nn.BatchNorm2d( 64 ), # Conv 뒤에 BN 적용
nn.ReLU(),
)
주의 : 배치 크기가 너무 작으면(1~2) 통계량이 불안정해집니다. 추론 시에는 학습 중 계산된 이동 평균(Running Mean/Variance)을 사용합니다.
Layer Normalization (층 정규화)
배치가 아닌 각 샘플의 모든 특성에 대해 정규화합니다. 배치 크기에 의존하지 않으므로 시퀀스 모델과 Transformer에서 선호됩니다.
x ^ i = x i − μ L σ L 2 + ϵ \hat{x}_i = \frac{x_i - \mu_L}{\sqrt{\sigma_L^2 + \epsilon}} x ^ i = σ L 2 + ϵ x i − μ L
μ L , σ L 2 \mu_L, \sigma_L^2 μ L , σ L 2 : 한 샘플의 모든 특성에 대한 평균과 분산
# Layer Normalization
ln = nn.LayerNorm( normalized_shape = 256 )
# Transformer 블록에서의 사용 (Pre-LN 구조)
class TransformerBlock ( nn . Module ):
def __init__ ( self , d_model ):
super (). __init__ ()
self .ln1 = nn.LayerNorm(d_model)
self .ln2 = nn.LayerNorm(d_model)
self .attn = nn.MultiheadAttention(d_model, num_heads = 8 )
self .ffn = nn.Sequential(
nn.Linear(d_model, d_model * 4 ),
nn.GELU(),
nn.Linear(d_model * 4 , d_model),
)
def forward ( self , x ):
# Pre-LN: 정규화 먼저, 그 다음 연산
x = x + self .attn( self .ln1(x), self .ln1(x), self .ln1(x))[ 0 ]
x = x + self .ffn( self .ln2(x))
return x
BatchNorm vs LayerNorm
특성 BatchNorm LayerNorm 정규화 축 배치 방향 (같은 특성끼리) 특성 방향 (같은 샘플 내) 배치 크기 의존 예 (작은 배치 시 불안정) 아니오 학습/추론 차이 있음 (Running Stats) 없음 주 사용처 CNN Transformer, RNN
Weight Decay (가중치 감쇠)
가중치의 크기를 직접 줄여 모델 복잡도를 제한합니다. L2 정규화와 개념적으로 유사하지만, AdamW에서는 분리된 형태로 적용됩니다.
w t + 1 = ( 1 − λ ) w t − η ∇ w L w_{t+1} = (1 - \lambda)w_t - \eta \nabla_w \mathcal{L} w t + 1 = ( 1 − λ ) w t − η ∇ w L
# AdamW에서의 Weight Decay
optimizer = torch.optim.AdamW(
model.parameters(),
lr = 0.001 ,
weight_decay = 0.01 # 가중치 감쇠 계수
)
Early Stopping (조기 종료)
검증 손실(Validation Loss)이 더 이상 감소하지 않으면 학습을 중단합니다.
best_val_loss = float ( 'inf' )
patience = 10 # 개선 없이 기다리는 에포크 수
counter = 0
for epoch in range ( 1000 ):
train_loss = train_one_epoch(model, train_loader)
val_loss = evaluate(model, val_loader)
if val_loss < best_val_loss:
best_val_loss = val_loss
counter = 0
# 최적 모델 저장
torch.save(model.state_dict(), 'best_model.pt' )
else :
counter += 1
if counter >= patience:
print ( f "조기 종료: epoch { epoch } " )
break
실무 조합 가이드
아키텍처 권장 정규화 조합 MLP Dropout(0.3~0.5) + Weight Decay CNN BatchNorm + Dropout(0.2~0.3) + Weight Decay Transformer LayerNorm + Dropout(0.1) + Weight Decay RNN/LSTM LayerNorm + Dropout(0.2~0.5)
일반적으로 MLP에서 0.5, CNN에서 0.2~0.3, Transformer에서 0.1을 사용합니다. 데이터가 적으면 더 높은 Dropout을, 데이터가 많으면 더 낮은 Dropout을 적용합니다. 하이퍼파라미터 탐색으로 최적값을 찾는 것이 좋습니다.
BatchNorm과 Dropout을 함께 사용해도 되나요?
사용할 수 있지만, BatchNorm 직후에 Dropout을 적용하면 학습이 불안정해질 수 있습니다. 일반적으로 Conv → BN → ReLU → Dropout 순서를 따르거나, 최근에는 BatchNorm이 충분한 정규화 효과를 제공하므로 Dropout을 제거하는 추세입니다.
체크리스트
다음 문서