본문 바로가기
Artificial Intelligence/21. PyTorch

[PYTORCH] DistributedDataParallel (DDP) 기본 개념과 DataParallel의 3가지 차이 및 성능 해결 방법

by Papa Martino V 2026. 4. 4.
728x90

DistributedDataParallel (DDP) 기본 개념
DistributedDataParallel (DDP) 기본 개념

 

현업 딥러닝 아키텍트가 제안하는 고성능 분산 학습 아키텍처: 왜 기업용 AI 모델은 모두 DDP를 선택하는가?


1. 분산 학습의 필연성: 왜 DistributedDataParallel(DDP)인가?

최근 초거대 언어 모델(LLM)과 고해상도 이미지 생성 모델의 출현으로 단일 GPU만으로는 학습 시간을 감당하기 어려운 시대가 되었습니다. PyTorch에서 제공하는 DistributedDataParallel(DDP)은 멀티 GPU 및 멀티 노드 환경에서 모델을 학습시키기 위한 최적의 솔루션입니다. 과거에 많이 사용되던 `DataParallel(DP)` 방식은 단일 프로세스에서 멀티 스레딩을 사용하는 구조적 한계로 인해 GIL(Global Interpreter Lock) 문제와 마스터 GPU의 메모리 병목 현상을 피할 수 없었습니다. 반면 DDP는 각 GPU마다 독립적인 프로세스를 생성하여 연산을 수행함으로써 이론적으로 선형적인 성능 향상을 목표로 합니다.

2. DataParallel(DP) vs DistributedDataParallel(DDP) 핵심 차이 분석

두 방식의 구조적 차이를 명확히 이해해야 실무에서 발생하는 병목 현상을 해결할 수 있습니다.

비교 항목 DataParallel (DP) DistributedDataParallel (DDP) 비고
프로세스 구조 단일 프로세스 / 멀티 스레드 멀티 프로세스 (1 GPU당 1 Process) GIL 우회 가능성
통신 방식 마스터 GPU가 데이터를 복사/배포 Ring-AllReduce 기반 병렬 통신 DDP가 훨씬 효율적임
GPU 메모리 사용 0번 GPU에 부하가 집중됨 모든 GPU가 균등하게 사용 OOM(Out of Memory) 해결
멀티 노드 지원 지원하지 않음 (단일 서버용) 강력 지원 (여러 대의 서버 연결) 엔터프라이즈급 확장성
학습 속도 오버헤드로 인해 증가폭 제한적 GPU 개수에 비례하여 거의 선형 증가 실무 도입의 핵심 이유

3. 실무 최적화를 위한 PyTorch DDP 구현 Example (7가지)

단순한 튜토리얼을 넘어, 대규모 클러스터 환경에서 즉시 적용 가능한 7가지 전문가급 예제입니다.

Example 1: 최소 기능 구현 (Basic Setup)

DDP를 구동하기 위한 가장 기본적인 프로세스 그룹 초기화 단계입니다.

import torch
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP

def setup(rank, world_size):
    dist.init_process_group(
        backend='nccl',  # NVIDIA GPU 환경에서는 nccl이 필수
        init_method='env://',
        rank=rank,
        world_size=world_size
    )

def cleanup():
    dist.destroy_process_group()
        

Example 2: DistributedSampler를 이용한 데이터 분할

각 GPU 프로세스가 서로 겹치지 않는 데이터 서브셋을 처리하도록 보장하는 핵심 코드입니다.

from torch.utils.data.distributed import DistributedSampler

dataset = MyDataset()
sampler = DistributedSampler(dataset, num_replicas=world_size, rank=rank)
dataloader = torch.utils.data.DataLoader(dataset, batch_size=32, sampler=sampler)

# 매 Epoch마다 sampler의 set_epoch를 호출해야 데이터가 섞임
sampler.set_epoch(epoch)
        

Example 3: 모델 래핑 및 GPU 할당

모델을 DDP 클래스로 감싸고 해당 프로세스의 전용 GPU에 배치하는 방법입니다.

model = MyModel().to(rank)
ddp_model = DDP(model, device_ids=[rank])

# 연산 시 일반 모델처럼 사용 가능
output = ddp_model(input_data)
        

Example 4: 잃어버린 체크포인트 복구 (Save & Load)

DDP 환경에서 체크포인트는 반드시 마스터 프로세스(Rank 0)에서만 수행해야 합니다.

if rank == 0:
    # ddp_model.module로 접근해야 원본 모델 가중치가 저장됨
    torch.save(ddp_model.module.state_dict(), "checkpoint.pt")

# 로드 시에는 map_location 사용 필수
dist.barrier() # 모든 프로세스가 저장을 마칠 때까지 대기
map_location = {'cuda:%d' % 0: 'cuda:%d' % rank}
ddp_model.module.load_state_dict(torch.load("checkpoint.pt", map_location=map_location))
        

Example 5: SyncBatchNorm을 통한 정규화 정합성 해결

각 프로세스별로 계산되는 BatchNorm 통계치를 동기화하여 배치 사이즈 증가 효과를 극대화합니다.

# DDP 래핑 전에 수행해야 함
sync_bn_model = torch.nn.SyncBatchNorm.convert_sync_batchnorm(model)
ddp_model = DDP(sync_bn_model.to(rank), device_ids=[rank])
        

Example 6: Gradient Bucketing 최적화 전략

학습 속도를 높이기 위해 그래디언트 통신 버킷 크기를 조절하는 고급 설정입니다.

# bucket_cap_mb: 한번에 통신할 데이터 크기 (기본값 25MB)
# 대규모 모델일수록 크게 설정하는 것이 유리할 수 있음
ddp_model = DDP(model, device_ids=[rank], bucket_cap_mb=50)
        

Example 7: 다중 노드(Multi-Node) 실행을 위한 환경 변수 설정

여러 대의 서버를 연결할 때 필요한 네트워크 주소 및 포트 설정 예시입니다.

import os

os.environ['MASTER_ADDR'] = '10.0.0.1' # 마스터 서버의 사설 IP
os.environ['MASTER_PORT'] = '12355'    # 통신용 포트
os.environ['WORLD_SIZE'] = '16'        # 전체 GPU 개수
os.environ['RANK'] = str(current_rank) # 현재 프로세스의 절대적 순위
        

4. DDP 도입 시 반드시 체크해야 할 성능 병목 해결 가이드

  • 네트워크 대역폭(Bandwidth): DDP는 AllReduce 알고리즘을 사용하므로 GPU 간 통신 속도가 매우 중요합니다. NVLink가 있는 환경인지, 없다면 PCIe 대역폭이 충분한지 확인하십시오.
  • find_unused_parameters: 모델의 일부 출력이나 파라미터가 손실 계산에 사용되지 않는 경우, DDP는 오류를 발생시키거나 성능이 저하됩니다. `find_unused_parameters=True` 옵션으로 해결 가능하지만 연산 오버헤드가 발생하므로 가급적 모델 구조를 수정하는 것이 좋습니다.
  • CPU 워커 스레드 병목: 멀티 프로세스 환경이므로 DataLoader의 `num_workers`가 너무 높으면 CPU 자원 경합이 발생하여 오히려 GPU가 노는 현상이 발생할 수 있습니다.

5. 결론

PyTorch DistributedDataParallel은 현대적인 AI 연구와 서비스 개발에 있어 선택이 아닌 필수입니다. 단순히 기술을 적용하는 것에 그치지 않고, 프로세스 독립성통신 오버헤드의 관계를 명확히 이해할 때 비로소 진정한 의미의 'Linear Scaling'을 달성할 수 있습니다. 오늘 공유한 7가지 실무 예제를 통해 여러분의 학습 파이프라인을 한 단계 업그레이드해 보시기 바랍니다.


내용 출처 및 기술 참조

  • PyTorch Core Team, "Distributed communication package - torch.distributed", Official Documentation.
  • Li et al., "PyTorch Distributed: Experiences on Accelerating Data Parallel Training", VLDB 2020.
  • NVIDIA Collective Communications Library (NCCL) Developer Guide.
  • PyTorch Tutorials, "Getting Started with Distributed Data Parallel".
728x90