🤖 AI/ML

Batch Size

배치 크기

한 번의 학습에 사용하는 샘플 수. 메모리와 학습 안정성에 영향. 하이퍼파라미터.

📖 상세 설명

Batch Size(배치 크기)는 한 번의 gradient update에 사용하는 학습 샘플의 수입니다. 전체 데이터셋을 한 번에 처리하는 대신, 작은 묶음(batch)으로 나누어 순차적으로 학습하며, 이 묶음의 크기가 batch size입니다. 딥러닝에서 가장 중요한 하이퍼파라미터 중 하나입니다.

Mini-batch gradient descent는 1960년대부터 연구되었으나, GPU 병렬 처리가 보편화된 2010년대 이후 실질적으로 중요해졌습니다. GPU 메모리와 연산 효율의 균형을 맞추는 것이 핵심이며, 최근 대규모 모델 학습에서는 gradient accumulation과 distributed training으로 effective batch size를 키우는 기법이 표준이 되었습니다.

Batch size는 학습 역학에 깊은 영향을 미칩니다. 작은 배치(32 이하)는 노이즈가 많아 일반화에 유리하지만 학습이 불안정하고, 큰 배치(1024 이상)는 안정적이지만 sharp minima에 빠지기 쉽습니다. 이론적으로 batch size를 N배 늘리면 learning rate를 sqrt(N)배 늘려야 유사한 학습 역학을 유지할 수 있습니다.

실무에서는 GPU 메모리가 허용하는 최대 batch size에서 시작해서, 학습 불안정이 보이면 줄이는 접근이 일반적입니다. V100 16GB에서 BERT-base는 약 batch size 32, A100 40GB에서는 64-128이 적절합니다. 메모리가 부족하면 gradient accumulation을 활용해 effective batch size를 키울 수 있습니다.

💻 코드 예제

# Batch Size와 Gradient Accumulation 예제
import torch
from torch.utils.data import DataLoader, TensorDataset

# 1. 기본 DataLoader 설정
dataset = TensorDataset(
    torch.randn(1000, 10),  # 입력
    torch.randint(0, 2, (1000,))  # 레이블
)

# Batch size 설정
batch_size = 32
dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)

print(f"데이터셋 크기: {len(dataset)}")
print(f"배치 크기: {batch_size}")
print(f"배치 수 (iterations per epoch): {len(dataloader)}")

# 2. Gradient Accumulation으로 Effective Batch Size 키우기
model = torch.nn.Linear(10, 2)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = torch.nn.CrossEntropyLoss()

# 실제 배치: 8, Accumulation steps: 4 -> Effective batch: 32
actual_batch_size = 8
accumulation_steps = 4
effective_batch_size = actual_batch_size * accumulation_steps

small_dataloader = DataLoader(dataset, batch_size=actual_batch_size, shuffle=True)

# 학습 루프
model.train()
optimizer.zero_grad()

for i, (inputs, labels) in enumerate(small_dataloader):
    outputs = model(inputs)
    loss = criterion(outputs, labels)

    # Gradient 누적을 위해 나누기
    loss = loss / accumulation_steps
    loss.backward()

    # accumulation_steps마다 업데이트
    if (i + 1) % accumulation_steps == 0:
        optimizer.step()
        optimizer.zero_grad()
        print(f"Step {(i+1)//accumulation_steps}: "
              f"Effective batch size = {effective_batch_size}")

    if i >= 15:  # 예시용 조기 종료
        break

# 3. 배치 크기에 따른 Learning Rate 스케일링
def get_scaled_lr(base_lr, base_batch_size, target_batch_size):
    """Linear scaling rule"""
    return base_lr * (target_batch_size / base_batch_size)

base_lr = 1e-3
base_batch = 32
target_batch = 256

scaled_lr = get_scaled_lr(base_lr, base_batch, target_batch)
print(f"\n배치 {base_batch} -> {target_batch}로 변경 시")
print(f"Learning rate: {base_lr} -> {scaled_lr}")

🗣️ 실무 대화 예시

GPU 메모리 에러 해결 논의에서

"CUDA OOM이 뜨면 일단 batch size를 반으로 줄여보세요. 그래도 안 되면 gradient checkpointing을 켜거나, mixed precision(FP16)을 적용하면 메모리가 절반으로 줄어듭니다. 배치를 줄이면 gradient accumulation으로 effective batch를 유지하세요."

학습 불안정 이슈 디버깅 중

"Loss가 진동하면 batch size가 너무 작거나 learning rate가 너무 높은 거예요. 배치 32에서 128로 올리고, linear scaling rule에 따라 LR도 4배로 올리거나, 아니면 배치만 올리고 LR은 유지하면서 warmup을 길게 주는 방법도 있습니다."

기술 면접에서

"큰 배치로 학습하면 sharp minima에 수렴해 일반화 성능이 떨어진다는 연구가 있습니다. 해결책으로 LARS, LAMB 같은 layer-wise adaptive learning rate를 쓰거나, warmup을 충분히 주는 방법이 있습니다. GPT-3 학습에서도 배치 크기를 점진적으로 늘리는 batch size rampup을 사용했습니다."

📊 GPU별 권장 배치 사이즈 가이드

GPU VRAM BERT-base ResNet-50 LLaMA 7B
RTX 3090 24GB 32 64 1 (QLoRA)
RTX 4090 24GB 32 64 2 (QLoRA)
A100 40/80GB 64~128 128~256 4~8
H100 80GB 128 256 8~16

💡 실무 팁: OOM 발생 시 → 배치 50% 감소 또는 FP16/BF16 활성화. 배치 줄이면 Gradient Accumulation으로 effective batch 유지. BERT fine-tuning 권장: 16~32, LLM 권장: 1~4 (메모리 한계).

⚠️ 주의사항

1
BatchNorm과의 상호작용

Batch Normalization은 배치 통계를 사용하므로 batch size가 너무 작으면(8 이하) 추정이 불안정해집니다. 작은 배치에서는 GroupNorm이나 LayerNorm을 사용하세요.

2
Learning Rate 조정 필수

Batch size를 변경하면 learning rate도 함께 조정해야 합니다. 배치를 N배 키우면 LR을 sqrt(N)~N배 사이로 키우고, warmup 스텝도 그에 맞게 조정하세요.

3
Evaluation 시 배치 크기

평가 시에는 gradient 계산이 없어 메모리 여유가 있으므로 evaluation batch size를 학습보다 2-4배 크게 설정할 수 있습니다. 이렇게 하면 평가 속도가 크게 향상됩니다.

🔗 관련 용어

📚 더 배우기