드롭아웃(Dropout)은 학습 중 무작위로 뉴런을 비활성화해 과적합을 방지하는 정규화 기법이다. 2014년 Srivastava 등이 제안했으며, 마치 여러 신경망의 앙상블을 학습하는 효과를 낸다.
핵심 원리
학습 중: 각 뉴런을 확률 p로 0으로 설정 (드롭아웃)
추론 중: 모든 뉴런 활성화, 출력에 (1-p) 곱하거나
역 드롭아웃(Inverted Dropout): 학습 시 1/(1-p) 스케일링
구현
python
import torch
import torch.nn as nn
class Dropout(nn.Module):
def __init__(self, p=0.5):
super().__init__()
assert 0 <= p < 1
self.p = p
def forward(self, x):
if not self.training or self.p == 0:
return x
# 역 드롭아웃: 학습 시 1/(1-p) 스케일링
mask = (torch.rand_like(x) > self.p).float() / (1 - self.p)
return x * mask
# 사용 예
model = nn.Sequential(
nn.Linear(784, 512), nn.ReLU(), nn.Dropout(0.5),
nn.Linear(512, 256), nn.ReLU(), nn.Dropout(0.3),
nn.Linear(256, 10)
)
# 반드시 train/eval 모드 전환
model.train() # 드롭아웃 활성화
model.eval() # 드롭아웃 비활성화
드롭아웃 변형
python
# DropConnect: 가중치를 드롭
# SpatialDropout: CNN에서 채널 전체를 드롭
class SpatialDropout2D(nn.Module):
def __init__(self, p=0.5):
super().__init__()
self.p = p
def forward(self, x):
if not self.training: return x
# (B, C, H, W) → 채널 C 차원으로 드롭
mask = torch.bernoulli(torch.ones(x.shape[0], x.shape[1], 1, 1, device=x.device) * (1-self.p))
return x * mask / (1 - self.p)
# DropPath (Stochastic Depth): 레이어 전체를 드롭
def drop_path(x, drop_prob=0.1, training=True):
if drop_prob == 0 or not training:
return x
keep = 1 - drop_prob
shape = (x.shape[0],) + (1,) * (x.ndim - 1)
mask = torch.bernoulli(torch.full(shape, keep, device=x.device)) / keep
return x * mask
드롭아웃 vs 다른 정규화
| 기법 | 작동 | 위치 |
|---|
| Dropout | 뉴런 무작위 비활성화 | 레이어 사이 |
| L2 정규화 | 가중치 크기 페널티 | 손실 함수 |
| Batch Norm | 분포 정규화 | 레이어 내 |
| DropPath | 레이어 전체 드롭 | 트랜스포머 블록 |
관련 개념