728x90
728x90

인공지능에서 Multi-GPU란?
1. 왜 Multi-GPU가 필요한가요?
현대의 딥러닝 모델은 다음과 같은 이유로 엄청난 연산 자원을 요구합니다.
- 파라미터 수가 수억~수천억 개 (예: GPT, ViT, BERT)
- 학습 데이터가 수 TB 이상
- 한 번의 학습에 며칠~몇 주 소요
💡 단일 GPU로는 처리 시간이 길고, 메모리 용량에도 한계가 있습니다. → 이를 해결하기 위해 Multi-GPU 환경이 필요합니다.
2. Multi-GPU란?
Multi-GPU는 하나의 컴퓨터(또는 분산 시스템)에 여러 개의 GPU를 연결하여 연산을 병렬로 수행하는 구조입니다.
- 목적: 속도 향상 + 메모리 분산 + 대규모 모델 처리
- 구성: 1대의 머신에 여러 GPU (ex. 4x RTX 3090), 또는 여러 머신(GPU 서버) 연결
3. Multi-GPU의 2가지 주요 방식
| 구분 | Data Parallelism | Model Parallelism |
|---|---|---|
| 개념 | 동일한 모델을 복제하여 각 GPU에 데이터의 일부를 분산 | 모델을 파트별로 나누어 서로 다른 GPU에 배치 |
| 장점 | 구현이 쉬움 (PyTorch, HuggingFace 지원) | 매우 큰 모델도 처리 가능 (파라미터가 GPU 하나를 초과해도 학습 가능) |
| 단점 | 모델 크기가 GPU 메모리에 들어가야 함 | 구현 복잡, 디버깅 어려움 |
| 예시 | 배치 크기 64 → GPU 4개 → 각각 16개씩 분산 처리 | GPT의 Transformer Layer 1~6 → GPU 0, Layer 7~12 → GPU 1 |
4. Multi-GPU의 주요 도구
- PyTorch
nn.DataParallel: 쉬우나 속도 비효율적torch.nn.parallel.DistributedDataParallel (DDP)✅ 표준
- DeepSpeed / Hugging Face Accelerate / FairScale
- Mixed precision, ZeRO optimizer 등 활용 가능
- NCCL (NVIDIA Collective Communication Library)
- GPU 간 통신을 빠르게 처리하는 NVIDIA 라이브러리
5. 실행 예시: PyTorch DDP 구조
# 초기화
dist.init_process_group("nccl")
# 모델을 각 GPU에 할당
model = MyModel().to(local_rank)
model = DDP(model, device_ids=[local_rank])
# 데이터 로더는 DistributedSampler와 함께 사용
sampler = DistributedSampler(dataset)
loader = DataLoader(dataset, sampler=sampler, ...)
💡
torchrun,torch.distributed.launch등을 통해 프로세스를 GPU 수만큼 실행
6. Multi-GPU 환경에서 주의할 점
- GPU 간 통신 비용: GPU 간 데이터 이동은 느릴 수 있음 → 최소화해야 함
- 동기화 비용: 각 GPU가 병렬적으로 계산하더라도 업데이트(gradient sync)는 동기화 필요
- Random seed / Dropout 등은 GPU별로 일관성 있게 설정
- Batch size는 GPU 수에 맞게 나누어야 함 (예: 총 128, GPU 4개 → 각 32)
7. 기초 실습 구성 추천
- 🔹
torchrun --nproc_per_node=2 train.py
→ 로컬에서 2개 GPU로 학습 - 🔹
DataParallel vs DDP 비교 실험
→ DDP가 훨씬 빠르고 안정적인 결과 제공
마무리
| 항목 | 요약 |
|---|---|
| 목적 | 속도 향상, 대규모 모델 학습 |
| 핵심 기법 | Data Parallel, Model Parallel |
| 도구 | DDP, DeepSpeed, Accelerate |
| 주의점 | 통신/동기화 비용, 메모리 할당, seed 고정 |
핵심 개념 비교
| 항목 | DataParallel |
DistributedDataParallel (DDP) |
|---|---|---|
| 실행 방식 | 단일 프로세스, 여러 GPU에서 연산 | GPU당 하나의 프로세스 (멀티 프로세스) |
| 메인 GPU | 모든 연산 결과를 메인 GPU에서 수집 | 각 GPU에서 동시 병렬 처리 후 동기화 |
| 성능 | 병목이 심함, 느림 | 최적화된 병렬화, 빠름 ✅ |
| 권장 여부 | 실험용/비추천 ❌ | 실제 사용/표준 방식 ✅ |
| 통신 방식 | Python-level 통신 | NCCL 기반 GPU 간 고속 통신 |
| 사용 API | nn.DataParallel(model) |
torch.nn.parallel.DistributedDataParallel(model) |
구조도적 차이
DataParallel 구조 (단일 프로세스, 메인 GPU 집중)
+--------------+
Input -->| Main GPU | (Model, Loss, Backward)
+------+-------+
|
-----------------------
| | |
GPU 1 GPU 2 GPU 3 ← Submodule 복사
\_________/_________/
|
결과 수집 + loss 계산은 **Main GPU**
→ → 문제점: 모든 gradient가 메인 GPU로 모여 연산되어 병목 발생 (ex. GPU0 과부하)
DDP 구조 (프로세스 당 1 GPU, 진정한 병렬)
[Process 0] GPU 0: 모델 + 데이터 조각 → forward → backward
[Process 1] GPU 1: 모델 + 데이터 조각 → forward → backward
[Process 2] GPU 2: 모델 + 데이터 조각 → forward → backward
[Process N] ...
↘ NCCL 기반 통신으로 gradient 동기화 ↙
→ → 장점: 모든 GPU가 자기 몫의 연산과 업데이트를 병렬로 수행
→ 통신은 CUDA 커널 수준에서 이루어지며 병목 거의 없음
예제 코드 비교
DataParallel 예제
model = MyModel()
model = nn.DataParallel(model)
model = model.cuda()
DDP 예제
# GPU당 1 프로세스 실행 필수 (ex. torchrun 사용)
model = MyModel().to(local_rank)
model = DDP(model, device_ids=[local_rank])
어떤 상황에 무엇을 쓸까?
| 상황 | 추천 방식 |
|---|---|
| 연구용, 단순 실험 | DataParallel (비추천이나 간단함) |
| 대규모 학습, 실전 학습 | ✅ DDP |
| 정확한 시간 측정, 성능 최적화 | ✅ DDP |
| 다중 노드 (멀티 서버) | 반드시 DDP 사용 |
결론
"DataParallel은 입문자용 구조이며, 실전에서는 반드시 DistributedDataParallel을 사용해야 합니다."
DDP는 성능 최적화뿐만 아니라 정확한 결과 재현성과 메모리 효율성 측면에서도 훨씬 우수합니다.
Model Parallelism이란?
- Data Parallel: 같은 모델 복사본을 각 GPU에 두고 데이터를 나눠서 학습
- Model Parallel: 하나의 모델을 여러 GPU에 나눠서 배치하고, 순차적으로 연산을 수행
주 용도
- 거대한 모델(GPT, LLaMA 등)을 GPU 여러 개에 나누어 학습
- GPU 하나에 전체 모델이 올라가지 않을 때 필수
간단한 예제 구조 (2개 GPU에 모델 분산)
import torch
import torch.nn as nn
# 두 개 GPU가 필요
device0 = torch.device("cuda:0")
device1 = torch.device("cuda:1")
# 모델 정의: 두 layer를 다른 GPU에 올림
class ModelParallelNN(nn.Module):
def __init__(self):
super(ModelParallelNN, self).__init__()
self.seq1 = nn.Sequential(
nn.Linear(1024, 2048),
nn.ReLU()
).to(device0)
self.seq2 = nn.Sequential(
nn.Linear(2048, 1024),
nn.ReLU()
).to(device1)
def forward(self, x):
# 입력은 device0으로 전달됨
x = x.to(device0)
x = self.seq1(x)
# seq2가 있는 device1로 이동
x = x.to(device1)
x = self.seq2(x)
return x
학습 루프 예시
model = ModelParallelNN()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.MSELoss()
# dummy input/output
x = torch.randn(64, 1024).to("cuda:0") # 입력은 첫 번째 GPU로
y = torch.randn(64, 1024).to("cuda:1") # 출력은 마지막 GPU 기준
for epoch in range(5):
optimizer.zero_grad()
out = model(x)
loss = criterion(out, y)
loss.backward() # 역전파는 자동으로 GPU 간 통신 처리
optimizer.step()
print(f"Epoch {epoch+1}: Loss = {loss.item():.4f}")
주의사항 및 팁
| 항목 | 내용 |
|---|---|
.to(device) |
각 연산 전/후 데이터를 해당 GPU로 이동해야 함 |
| backward() | 자동으로 GPU 간 통신 수행 (Autograd 엔진) |
| 속도 | Layer 간 이동 시 GPU 간 통신 오버헤드 존재 |
| PyTorch 지원 | 수동으로 .to(device) 처리 필요, 자동화는 없음 (vs. DataParallel) |
정리
| 항목 | 설명 |
|---|---|
| 목적 | 모델이 GPU 메모리 하나에 안 들어갈 때 |
| 구조 | Layer 단위로 서로 다른 GPU에 배치 |
| 장점 | 대규모 모델 처리 가능 |
| 단점 | 구현 복잡, GPU 간 통신 속도에 민감 |
| 실사용 예 | GPT-3, LLaMA, T5 등 수십억 파라미터 모델 |
1. DDP의 핵심 철학
“GPU 당 하나의 프로세스” 원칙
- 각 GPU는 자기만의 프로세스와 모델 복사본을 가짐
- Forward + Backward 계산을 독립적으로 처리
- Backward 단계에서만 통신 (gradient all-reduce)
2. DDP의 내부 동작 순서
1. torchrun 또는 launch로 N개 프로세스 실행
2. 각 프로세스는 모델과 데이터를 자기 GPU에 로드
3. forward: 각 GPU가 자기 미니배치로 연산
4. backward: gradient를 all-reduce (NCCL)로 통신
5. optimizer step: 각 GPU가 동일한 업데이트 수행
3. DDP에서 꼭 필요한 설정 요소
| 항목 | 설명 | 예시 |
|---|---|---|
init_process_group |
DDP 통신 그룹 초기화 | dist.init_process_group("nccl", ...) |
local_rank |
각 프로세스의 GPU ID | torchrun에서 자동 전달됨 |
DistributedSampler |
각 GPU에 고유한 데이터 샘플링 | DataLoader(..., sampler=DistributedSampler(...)) |
device_ids |
GPU 지정 | DDP(model, device_ids=[local_rank]) |
4. 실전 코드 구조 예시 (단일 노드 N GPU)
import torch
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP
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(train_dataset, num_replicas=world_size, rank=rank)
dataloader = DataLoader(train_dataset, sampler=sampler, ...)
# 학습 루프
for epoch in range(num_epochs):
sampler.set_epoch(epoch) # epoch별 셔플 고정
for batch in dataloader:
...
cleanup()
실행:
torchrun --nproc_per_node=4 train.py
5. DDP 통신 방식: All-Reduce
- gradient 동기화 방식: All-Reduce (각 GPU가 gradient를 공유 후 평균)
- 기반 통신 백엔드:
NCCL(NVIDIA Collective Communication Library) - 효율성 팁:
- Mixed Precision (
fp16,bf16) + Gradient Accumulation - Gradient Bucketing (PyTorch 자동 처리)
- CUDA-aware 통신 → CPU로 안 거치고 바로 GPU-GPU 간 통신
- Mixed Precision (
6. 성능 최적화를 위한 팁
| 전략 | 설명 |
|---|---|
pin_memory=True |
CPU→GPU 데이터 전송 속도 향상 |
num_workers 최적화 |
데이터 로딩 병렬화 |
AMP (torch.cuda.amp) |
Mixed precision으로 메모리/속도 이득 |
| Gradient Accumulation | GPU 메모리 절약 + batch 크기 증가 |
find_unused_parameters=False |
비활성 파라미터 추적 안 함 → 속도 증가 |
gradient_checkpointing |
메모리 절약 (forward 계산 다시 수행) |
7. Multi-Node DDP 확장
| 항목 | 설명 |
|---|---|
init_method |
env://로 환경변수로 IP/PORT 설정 |
MASTER_ADDR, MASTER_PORT |
마스터 노드 주소 |
WORLD_SIZE, RANK |
전체 프로세스 수, 현재 프로세스 인덱스 |
예시:
MASTER_ADDR=10.0.0.1 MASTER_PORT=29500 \
WORLD_SIZE=8 RANK=2 \
torchrun --nproc_per_node=4 --nnodes=2 --node_rank=1 train.py
8. DDP 관련 문제 상황 및 디버깅
| 문제 | 원인 | 해결 방법 |
|---|---|---|
| 일부 GPU만 사용됨 | rank / device 설정 오류 | torch.cuda.set_device(local_rank) 필수 |
| 학습 멈춤, 무한 대기 | drop_last=False로 마지막 배치 크기 불일치 |
drop_last=True 강력 추천 |
| gradient sync 안 됨 | 파라미터 미사용 또는 mask | find_unused_parameters=True |
| 느림, 병목 발생 | CPU 병목 또는 통신 충돌 | DataLoader 튜닝, CUDA 버전 확인 |
핵심 요약
| 항목 | 내용 |
|---|---|
| 구조 | GPU당 하나의 프로세스, 모델 복사본 |
| 통신 | NCCL 기반 all-reduce (backward 시만 통신) |
| 데이터 | DistributedSampler 필수, set_epoch(epoch) 필요 |
| 실행 | torchrun 또는 torch.distributed.launch 사용 |
| 확장성 | 단일 노드 ↔ 다중 노드 모두 지원 |
| 성능 향상 | AMP, Accumulation, Efficient Sampler 등 활용 |
728x90
'인공지능 > 공부' 카테고리의 다른 글
| 딥러닝 응용 - 2주차 (0) | 2025.09.08 |
|---|---|
| mteb 한글 평가하기 (0) | 2025.08.29 |
| 인공지능 기초 학습 코드 + 개념 (4) | 2025.07.29 |
| Collator란? (4) | 2025.07.29 |
| 딥러닝 총 정리 (2) | 2025.07.04 |