“GPU 여러 개 꽂으면 자동으로 빨라진다”는 착각에서 출발해, 실제로 무엇을 공부하면 분산 학습을 다룰 수 있는지까지 정리한 학습 로드맵입니다.
1. 핵심 전제: GPU는 도구, 분산은 설계
GPU를 늘린다고 자동으로 분산되지 않습니다. 실행되려면 아래 네 가지가 모두 갖춰져야 합니다.
GPU 여러 개
↓
분산 전략 선택 (Data / Model / Pipeline / Tensor Parallel)
↓
프레임워크 지원 (PyTorch DDP / DeepSpeed / FSDP / Accelerate)
↓
모델 구조 지원 (레이어 분할 가능 여부)
↓
실행
거대 AI 회사들의 경쟁력도 “GPU 수” 자체보다 “GPU 수천 장을 얼마나 효율적으로 묶는가”에 훨씬 가깝습니다.
2. 4가지 분산 방식 요약
① Data Parallel — 가장 흔함, 시작점
GPU1 → 배치 1~16
GPU2 → 배치 17~32
GPU3 → 배치 33~48
GPU4 → 배치 49~64
각 GPU: 동일한 모델 복사본 + 다른 데이터
→ gradient 합산 후 동기화
| 내용 | |
|---|---|
| 장점 | 구현 쉬움, 대부분 모델 지원, LoRA 파인튜닝에 흔함 |
| 단점 | GPU마다 모델 복사본 → 24GB + 24GB여도 실제 가용 모델 크기 ≈ 24GB |
| 쓰는 곳 | 이미지 분류, LoRA, 일반 파인튜닝 |
② Model Parallel — 큰 모델을 나눠 담기
GPU1: Layer 1 ~ 30
GPU2: Layer 31 ~ 60
→ 24GB + 24GB ≈ 더 큰 모델 가능
| 내용 | |
|---|---|
| 장점 | VRAM 합산 효과 — 실제로 더 큰 모델을 올릴 수 있음 |
| 단점 | GPU 간 통신이 많고, 한 GPU가 쉬는 동안 다른 GPU가 대기 (bubble 문제) |
| 쓰는 곳 | 70B+ 모델, 단일 GPU에 안 올라가는 모델 |
③ Pipeline Parallel — 공장 생산라인
입력 → GPU1(인코더) → GPU2(중간) → GPU3(디코더) → GPU4(출력)
micro-batch를 연속으로 흘려서 GPU 유휴 시간을 줄임
| 내용 | |
|---|---|
| 장점 | Model Parallel의 bubble 문제를 micro-batch로 완화 |
| 단점 | 설정 복잡, 모델을 균등하게 나누기 어려움 |
| 쓰는 곳 | GPT-3/4급 사전학습, DeepSpeed PipelineEngine |
④ Tensor Parallel — 행렬 자체를 쪼갬
거대한 Weight Matrix
↓
GPU1: 행렬 왼쪽 절반
GPU2: 행렬 오른쪽 절반
→ 각 GPU가 부분 계산 후 결과 합산
| 내용 | |
|---|---|
| 장점 | 대형 Attention/FFN 레이어를 여러 GPU에 분산 가능 |
| 단점 | GPU 간 All-Reduce 통신이 매 레이어마다 발생 → NVLink 없으면 병목 |
| 쓰는 곳 | GPT 계열, Llama, DeepSeek 사전학습 |
5가지 핵심 기법 한눈에 보기
| 기법 | 분류 | 핵심 아이디어 | 대표 API |
|---|---|---|---|
| DDP (DistributedDataParallel) | 데이터 병렬 | 동일 모델을 각 GPU에 복사, 미니배치를 나눠 처리한 뒤 gradient All-Reduce | torch.nn.parallel.DistributedDataParallel |
| FSDP (Fully Sharded DP) | 데이터+메모리 병렬 | 모델 가중치·gradient·optimizer state를 GPU 간 완전 분산. DDP 대비 메모리 대폭 절감 | torch.distributed.fsdp.FullyShardedDataParallel |
| DeepSpeed ZeRO | 메모리 최적화 | ZeRO-1(optimizer)/ZeRO-2(+gradient)/ZeRO-3(+parameter) 단계별 메모리 분산. CPU/NVMe Offload 지원 | deepspeed.initialize() |
| Tensor Parallel | 모델 병렬 | 레이어 내 가중치 행렬을 열/행 단위로 GPU에 분할. 대형 Attention·FFN 레이어에 효과적 | Megatron-LM, torch.distributed.tensor |
| Pipeline Parallel | 모델 병렬 | 레이어를 스테이지별로 GPU에 분할. 마이크로배치로 버블 최소화 | GPipe, PipeDream, Megatron PP |
실제 프레임워크는 여러 개를 조합
DeepSpeed = Data Parallel + Tensor Parallel + Pipeline Parallel + Memory Offload (ZeRO)
FSDP = 모델 가중치·gradient·optimizer state 자체를 GPU 간 분산 (Full Sharding)
Accelerate = 위 전략들을 코드 최소 변경으로 사용하는 래퍼
3. 주요 제약 사항
| 항목 | 영향 |
|---|---|
| GPU VRAM 크기가 다름 | 작은 GPU 기준으로 제한됨 (4090 24GB + 3060 12GB → 사실상 12GB 기준) |
| GPU 연결 속도 | PCIe 4.0 × 16: ~32GB/s, NVLink 4.0: ~900GB/s — 통신 비중 높을수록 차이 큼 |
| NVLink 유무 | Tensor Parallel / Model Parallel 효율에 직결. PCIe만이면 Data Parallel이 낫다 |
| 모델 구조 | Attention 구조가 독특한 모델은 Tensor Parallel 적용 어려움 |
| 배치 크기 | 너무 작으면 통신 오버헤드 > 연산 이득 → 효율 역전 |
| 모델 | 분산 난이도 | 비고 |
|---|---|---|
| Stable Diffusion | 낮음 | xformers + Data Parallel이면 충분 |
| FLUX | 중간 | 큰 모델이라 Model Parallel 필요할 수 있음 |
| Llama 7B~70B | 낮음~중간 | llama.cpp, vLLM, Accelerate 지원 풍부 |
| GPT류 | 중간 | Tensor Parallel 고려 필요 |
| 비디오 생성 | 높음 | 시퀀스 길이 + 3D 텐서로 VRAM 폭발 |
| 멀티모달 | 높음 | 인코더/디코더가 다른 모달리티라 분산 설계 어려움 |
4. 학습 로드맵 — 5단계
목표: 분산 학습의 기본 패턴 숙지 + 속도 체감. 홈랩(LoRA, 캐릭터 영상, 파인튜닝) 기준으로 현실적인 순서입니다.
1단계 — PyTorch DDP: 분산의 기초 문법
기간 목표: 2~3주
모든 분산 학습의 출발점입니다. GPU 1개짜리 학습 코드를 DDP로 바꿔서 2개 GPU에서 돌려보고 속도를 측정합니다.
import torch
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
from torch.utils.data.distributed import DistributedSampler
def setup(rank, world_size):
dist.init_process_group("nccl", rank=rank, world_size=world_size)
torch.cuda.set_device(rank)
def cleanup():
dist.destroy_process_group()
def train(rank, world_size):
setup(rank, world_size)
model = MyModel().to(rank)
model = DDP(model, device_ids=[rank]) # ← 이 한 줄이 핵심
sampler = DistributedSampler(dataset, num_replicas=world_size, rank=rank)
loader = DataLoader(dataset, sampler=sampler, batch_size=32)
for batch in loader:
loss = model(batch)
loss.backward()
optimizer.step()
cleanup()
# 실행: torchrun --nproc_per_node=2 train.py
체크포인트:
- GPU 1개 vs 2개 학습 시간 비교 기록
- gradient 동기화가 언제 일어나는지 이해
- DistributedSampler가 왜 필요한지 설명 가능
2단계 — Hugging Face Accelerate: 코드 변경 최소화
기간 목표: 2~3주
DDP를 직접 짜는 대신, Accelerate가 내부에서 처리하게 합니다. LoRA 파인튜닝에서 가장 많이 쓰이는 패턴입니다.
from accelerate import Accelerator
accelerator = Accelerator() # ← 환경 자동 감지
model, optimizer, loader = accelerator.prepare(
model, optimizer, train_loader
)
for batch in loader:
with accelerator.accumulate(model): # gradient accumulation
loss = model(**batch).loss
accelerator.backward(loss)
optimizer.step()
optimizer.zero_grad()
# 실행: accelerate launch --num_processes 2 train.py
# 또는: accelerate config → 설정 파일로 관리
체크포인트:
- Llama 또는 SD 모델을 Accelerate로 LoRA 파인튜닝 실행
- gradient accumulation steps를 바꿔가며 throughput 측정
- single GPU / multi GPU 설정 전환 자유롭게 가능
3단계 — DeepSpeed ZeRO: VRAM 절약의 핵심
기간 목표: 3~4주
ZeRO(Zero Redundancy Optimizer)는 모델 가중치·gradient·optimizer state를 GPU 간에 분산해서 저장합니다. 24GB GPU에서 70B 모델을 파인튜닝하는 것이 가능해지는 마법입니다.
// deepspeed_config.json
{
"zero_optimization": {
"stage": 3, // 0: 없음, 1: optimizer, 2: +gradient, 3: +weights
"offload_optimizer": { "device": "cpu" }, // CPU RAM으로 offload (VRAM 절약)
"offload_param": { "device": "cpu" }
},
"bf16": { "enabled": true },
"train_micro_batch_size_per_gpu": 1,
"gradient_accumulation_steps": 8
}
# Accelerate + DeepSpeed 조합 (가장 실용적)
accelerate launch --config_file deepspeed_config.json --num_processes 2 finetune.py
ZeRO Stage 비교:
| Stage | 분산 대상 | VRAM 절약 | 통신 비용 |
|---|---|---|---|
| ZeRO-1 | Optimizer state | 낮음 | 낮음 |
| ZeRO-2 | + Gradient | 중간 | 중간 |
| ZeRO-3 | + 모델 가중치 | 높음 | 높음 |
| ZeRO-3 + CPU offload | + CPU RAM 활용 | 매우 높음 | 속도 저하 있음 |
체크포인트:
- ZeRO Stage 1/2/3 각각 실행 후 VRAM 사용량 비교
- CPU offload 켰을 때 속도 차이 체감
- 단일 GPU에서 올라가지 않는 모델을 multi GPU + ZeRO로 실행
4단계 — FSDP: PyTorch 공식 분산 표준
기간 목표: 3~4주
FSDP(Fully Sharded Data Parallel)는 PyTorch가 공식적으로 제공하는 ZeRO-3 구현입니다. Meta의 Llama 파인튜닝 공식 코드가 FSDP를 씁니다.
from torch.distributed.fsdp import FullyShardedDataParallel as FSDP
from torch.distributed.fsdp.wrap import transformer_auto_wrap_policy
# Transformer 레이어 단위로 자동 분산
wrap_policy = transformer_auto_wrap_policy(
transformer_layer_cls={LlamaDecoderLayer} # 모델의 레이어 클래스
)
model = FSDP(
model,
auto_wrap_policy=wrap_policy,
device_id=torch.cuda.current_device(),
sharding_strategy=ShardingStrategy.FULL_SHARD, # ZeRO-3 상당
)
체크포인트:
- Llama 7B를 FSDP로 파인튜닝 실행
- checkpoint 저장/로드 (FSDP는 별도 처리 필요)
- DeepSpeed ZeRO-3 vs FSDP 속도 비교
5단계 — Ray + Kubernetes: 머신 경계를 넘기
기간 목표: 4~6주 (장기)
단일 머신의 GPU를 넘어, 집 PC + 클라우드 GPU + 여러 머신을 하나의 학습 클러스터로 묶는 단계입니다.
import ray
from ray import train
from ray.train.torch import TorchTrainer
from ray.train import ScalingConfig
def train_func():
# 기존 학습 코드 그대로
model = MyModel()
trainer = Trainer(model)
trainer.train()
trainer = TorchTrainer(
train_func,
scaling_config=ScalingConfig(
num_workers=4, # 4개 프로세스
use_gpu=True,
resources_per_worker={"GPU": 1}
)
)
trainer.fit()
# Kubernetes에서 Ray 클러스터 (홈랩 최종 형태)
# ray-cluster.yaml
apiVersion: ray.io/v1
kind: RayCluster
spec:
headGroupSpec:
replicas: 1
rayStartParams: { num-gpus: "1" }
workerGroupSpecs:
- replicas: 3
rayStartParams: { num-gpus: "1" }
체크포인트:
- 로컬 Ray 클러스터에서 분산 학습 실행
- 노드 추가/제거 시 학습 자동 재조정 확인
- 집 PC + 클라우드 1대를 Ray로 연결해서 학습
5. 미니 목표 체크리스트
각 단계에서 “이걸 했으면 다음으로 가도 됩니다”의 기준입니다.
| 단계 | 최소 확인 목표 | 보너스 목표 |
|---|---|---|
| 1단계 DDP | GPU 2개로 학습 실행 + 시간 측정 | GPU 1개 대비 속도 향상 그래프 그리기 |
| 2단계 Accelerate | LoRA 파인튜닝을 Accelerate로 실행 | config만 바꿔서 single/multi GPU 전환 |
| 3단계 DeepSpeed | ZeRO-3로 단일 GPU에 안 올라가는 모델 실행 | Stage별 VRAM 비교표 작성 |
| 4단계 FSDP | Llama 7B FSDP 파인튜닝 체크포인트 저장 | DeepSpeed vs FSDP 처리량 비교 |
| 5단계 Ray | 로컬 Ray 클러스터로 분산 실행 | Kubernetes RayCluster 매니페스트 작성 |
6. 홈랩 맥락에서의 현실적 조언
| 상황 | 추천 전략 |
|---|---|
| GPU 1개 (24GB) | ZeRO-3 + CPU offload로 70B 모델 LoRA 가능 |
| GPU 2개 동급 (24GB × 2) | Data Parallel + ZeRO-2가 가장 효율적 |
| GPU 2개 다른 크기 | 작은 GPU 기준 제한 → Data Parallel이 그나마 낫지만 효율↓ |
| NVLink 없는 멀티 GPU | Tensor/Model Parallel 피하기, Data Parallel 또는 ZeRO로 |
| 캐릭터 LoRA / SD 파인튜닝 | 2단계(Accelerate)에서 이미 충분 |
| 장기 — 집 + 클라우드 혼합 | 5단계(Ray) 이후 |
핵심 기억법: 모델이 GPU에 안 올라가면 ZeRO-3, 더 빠르게 하고 싶으면 Data Parallel, GPU가 여러 머신에 퍼져 있으면 Ray. 이 세 줄이 홈랩 기준 99%의 케이스를 커버합니다.
답글 남기기