본문 바로가기 대메뉴 바로가기

테크니컬 스토리

아이티마야의 새로운 기술 뉴스를 만나보세요.
GPU 어디까지 써봤나요
등록일
2025.09.08
첨부파일
분산 학습 실행을 위한 PyTorch 공식 런처 사용법과 장단점
GPU 어디까지 써봤나요
  • Tochrun에 대하여
  • torchrun은 PyTorch의 분산 학습(Distributed Training) 실행 유틸리티이다.
  • 멀티-GPU / 멀티-노드 분산 작업을 쉽고 안전하게 띄워주며(환경 변수 자동 설정, 프로세스 스폰, rendezvous 관리 등) 기존의 torch.distributed.launch를 대체한다.
  • DDP 란?
  • DDP (DistributedDataParallel) =
  • PyTorch에서 멀티 GPU / 멀티 노드 학습을 할 때 사용하는 공식 분산 학습 방식이다.
  • - GPU마다 프로세스 하나**를 띄움 (즉, 1 GPU ↔ 1 프로세스 매핑)
  • - 각 프로세스는 자신의 GPU에서 모델 복사본을 가지고 학습
  • - 한 스텝(미니 배치)마다 그래디언트(gradient)를 서로 동기화(all-reduce) 해서 파라미터가 동일하게 업데이트됨
  • DDP 와 Tochrun 의 관계
DDP Torchrun
작업 방식 PyTorch에서 멀티 GPU/멀티 노드 학습을 지원하는 모듈 DDP 실행을 편하게 해주는 런처 (launcher)
역할 각 GPU에 모델 복제 → 각자 학습 → gradient를 통신으로 동기화 →
최종적으로 같은 모델이 학습됨
프로세스/ GPU 수만큼 자동으로 띄우고
nproc_per_node, RANK, WORLD_SIZE, LOCAL_RANK 같은 분산 통신 환경변수를 세팅함
  • 관계 정리
  • - DDP = 실제 학습 로직 (모델 병렬화, gradient sync)
  • - torchrun = 실행 도우미** (환경 세팅, 프로세스 스폰) 즉,
  • - 코드 안에는 반드시 DDP를 써야 하고,
  • - 실행할 때는 보통 torchrun으로 띄웁니다.
  • 장단점
  • 장점
  • - 표준화 & 권장: PyTorch 공식 런처로 자리잡음(구형 torch.distributed.launch는 deprecated)
  • - 간단한 실행: torchrun --nproc_per_node=N train.py 한 줄로 로컬 멀티-GPU 실행 가능
  • - Elastic / Fault-tolerant 기능: 리소스 변동, 워커 실패에 대응 가능한 옵션(스냅샷/재시작) 지원
  • - 클러스터/스케줄러 통합 용이: rdzv(러즌버스) 파라미터로 클라우드/온프렘 환경에서 유연하게 사용 가능
  • 단점
  • - 문서/옵션이 헷갈릴 수 있음: -master_*, -rdzv_*, -standalone 등 옵션 관계가 복잡하고, 일부 파라미터 문서가 부족하다는 이슈가 보고되어 있음(초기 사용자는 혼동 가능)
  • - 네트워크/포트 문제: 멀티노드 실행시 방화벽·포트(기본 29500 등)를 열어야 하고, 마스터 주소/호스트명 해결 문제가 발생할 수 있음
  • - 디버깅 어려움: 프로세스가 여러 개라 디버깅(중단점, 로그 수집)이 더 복잡
  • - 환경 의존성: NCCL, Infiniband, 드라이버 호환성 문제로 NCCL 관련 에러가 날 수 있음(환경변수 설정·드라이버 확인 필요)
  • 실습 예제

#실습 환경

      
          OS                   : ubuntu 22.04

          Nvidia driver : 535.171
          Cuda               : 12.1

          cudnn             : 8.8.0

          설치 패키지 : 

          [ torch, torchvision, torchaudio, —index-url]
    

클라이언트 설정 파일 생성

패키지 용도
torch PyTorch 핵심 라이브러리, GPU/텐서/모델 학습 지원
torchvision 컴퓨터 비전 유틸리티, 이미지 데이터셋/전처리/모델 제공
torchaudio 오디오 처리 유틸리티, 오디오 데이터셋/변환 제공
--index-url CUDA 버전에 맞는 공식 휠 저장소 지정, GPU 연산 가능

실습

      
        1. sudo apt install python3.10-venv             # Python 3.10용 가상환경 생성 패키지 설치
        2. python3 -m venv ~/pt-venv                    # 홈 디렉토리에 Python 가상환경(pt-venv) 생성
        3. source ~/pt-venv/bin/activate                # 가상환경 활성화
        4. pip install --upgrade pip setuptools wheel   # pip, setuptools, wheel 최신 버전으로 업그레이드
        5. pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121  # PyTorch, TorchVision, Torchaudio 설치(CUDA 12.1)
    

설치 패키지 확인

      
        #PyTorch 버전과 CUDA 사용 가능 여부 확인
        python -c "import torch; print(\'Torch version:\', torch.**version**, \'CUDA available:\',
        torch.cuda.is_available())"

        #TorchVision 버전 확인
        python -c "import torchvision; print(\'Torchvision version:\', torchvision.**version**)"

        #Torchaudio 버전 확인
        python -c "import torchaudio; print(\'Torchaudio version:\', torchaudio.**version**)"
    

간단한 gpu test 코드
gpu_test.py 파일 생성

      
          import torch

        #GPU 개수 확인
        num_gpus = torch.cuda.device_count()
        print("Available GPUs:", num_gpus)

        #GPU 이름 확인
        for i in range(num_gpus):
        print(f"GPU {i}: {torch.cuda.get_device_name(i)}")

        #간단한 연산 테스트
        if num_gpus >= 2:
        x = torch.randn(1000, 1000).cuda(0)
        y = torch.randn(1000, 1000).cuda(1)
        z = x.cuda(1) + y
        print("Multi-GPU operation successful. Mean value:", z.mean().item())
        else:
        print("GPU가 2장 이상 필요합니다.")
    
      
        #실행
        - python gpu_test.py
    

DDP 멀티 GPU 테스트 코드
ddp_test.py 파일 생성 (2 GPU 기준)

      
        import os
        import torch
        import torch.distributed as dist
        import torch.multiprocessing as mp
        from torch.nn import Linear
        from torch.nn.parallel import DistributedDataParallel as DDP
        from torch.utils.data import DataLoader, TensorDataset, DistributedSampler

        #------------------

        #NCCL 환경 변수 설정

        #------------------

        os.environ["NCCL_DEBUG"] = "WARN"             # NCCL 경고 메시지 출력
        os.environ["NCCL_IB_DISABLE"] = "1"           # InfiniBand 비활성화
        os.environ["NCCL_P2P_LEVEL"] = "NVL"          # P2P 통신 레벨 설정
        os.environ["CUDA_VISIBLE_DEVICES"] = "0,1"    # 사용할 GPU 선택

        #DDP 필수 환경 변수

        os.environ[\'MASTER_ADDR\'] = \'127.0.0.1\'
        os.environ[\'MASTER_PORT\'] = \'29500\'

        #------------------

        #DDP 초기화

        #------------------

        def setup(rank, world_size):
            dist.init_process_group("nccl", rank=rank, world_size=world_size)  # 프로세스 그룹 초기화
            torch.cuda.set_device(rank)   # 현재 프로세스를 특정 GPU에 매핑

        #------------------

        #DDP 종료

        #------------------

        def cleanup():
            dist.destroy_process_group()  # 프로세스 그룹 종료

        #------------------

        #학습 루프

        #------------------

        def train(rank, world_size):
            setup(rank, world_size)  # DDP 초기화

            # 모델 정의 및 GPU 이동
            model = Linear(10, 1).cuda(rank)  # Linear 모델을 해당 GPU로 이동
            ddp_model = DDP(model, device_ids=[rank])  # DDP로 래핑

            # 데이터셋 및 DataLoader
            dataset = TensorDataset(torch.randn(100, 10), torch.randn(100, 1))  # 랜덤 데이터 생성
            sampler = DistributedSampler(dataset, num_replicas=world_size, rank=rank)  # DDP용 샘플러
            loader = DataLoader(dataset, batch_size=8, sampler=sampler)  # DataLoader 생성

            optimizer = torch.optim.SGD(ddp_model.parameters(), lr=0.01)  # 옵티마이저 설정

            # 학습 루프
            for epoch in range(2):

                running_loss = 0.0  # **추가: epoch별 누적 loss 초기화**
                for batch_idx, (x, y) in enumerate(loader):
                    x, y = x.cuda(rank), y.cuda(rank)  # 입력 데이터를 GPU로 이동
                    optimizer.zero_grad()              # 기울기 초기화
                    loss = ((ddp_model(x) - y) ** 2).mean()  # MSE Loss 계산
                    loss.backward()                    # 역전파
                    optimizer.step()                   # 가중치 업데이트
                    

                    running_loss += loss.item()  # **추가: 배치 loss 누적**

                    # 5배치마다 출력 (기존 출력문 수정)

                    print(f"[GPU {rank} | Epoch {epoch} | Batch {batch_idx}] Loss: {loss.item():.6f}")

                    # **기존: rank==0만 출력 → 이제 모든 GPU 출력**

                # ------------------- 추가: epoch 끝난 뒤 평균 loss 출력 -------------------
                avg_loss = running_loss / len(loader)
                print(f"[GPU {rank} | Epoch {epoch}] Average Loss: {avg_loss:.6f}")
                # **추가: 한 눈에 GPU별 학습 상태 확인 가능**

            cleanup()  # DDP 종료

        #------------------

        #메인 실행

        #------------------

        if __name__ == "__main__":
            world_size = torch.cuda.device_count()  # 사용 가능한 GPU 개수
            mp.spawn(train, args=(world_size,), nprocs=world_size, join=True)  # 멀티프로세스 학습 시작
    
      
        #실행
        torchrun --standalone --nproc_per_node=2 ddp_test.py
    

정상 출력 시 로그

      
        (pt-venv) test@ubuntu:~$ python ddp_test.py
        NCCL version 2.21.5+cuda12.4
        [GPU 1 | Epoch 0 | Batch 0] Loss: 0.512695
        [GPU 0 | Epoch 0 | Batch 0] Loss: 1.596358
        [GPU 0 | Epoch 0 | Batch 1] Loss: 3.234331
        [GPU 1 | Epoch 0 | Batch 1] Loss: 1.230204
        [GPU 0 | Epoch 0 | Batch 2] Loss: 1.251617
        [GPU 1 | Epoch 0 | Batch 2] Loss: 2.918502
        [GPU 0 | Epoch 0 | Batch 3] Loss: 0.790517
        [GPU 1 | Epoch 0 | Batch 3] Loss: 0.996800
        [GPU 0 | Epoch 0 | Batch 4] Loss: 1.685620
        [GPU 1 | Epoch 0 | Batch 4] Loss: 1.339857
        [GPU 0 | Epoch 0 | Batch 5] Loss: 0.529339
        [GPU 1 | Epoch 0 | Batch 5] Loss: 1.109558
        [GPU 0 | Epoch 0 | Batch 6] Loss: 0.962902
        [GPU 0 | Epoch 0] Average Loss: 1.435812
        [GPU 1 | Epoch 0 | Batch 6] Loss: 0.309195
        [GPU 1 | Epoch 0] Average Loss: 1.202401
        [GPU 1 | Epoch 1 | Batch 0] Loss: 0.476248
        [GPU 0 | Epoch 1 | Batch 0] Loss: 1.503265
        [GPU 1 | Epoch 1 | Batch 1] Loss: 1.115403
        [GPU 0 | Epoch 1 | Batch 1] Loss: 3.244143
        [GPU 1 | Epoch 1 | Batch 2] Loss: 2.682358
        [GPU 0 | Epoch 1 | Batch 2] Loss: 1.068382
        [GPU 1 | Epoch 1 | Batch 3] Loss: 0.868395
        [GPU 0 | Epoch 1 | Batch 3] Loss: 0.723319
        [GPU 1 | Epoch 1 | Batch 4] Loss: 1.248225
        [GPU 0 | Epoch 1 | Batch 4] Loss: 1.516317
        [GPU 1 | Epoch 1 | Batch 5] Loss: 0.936232
        [GPU 0 | Epoch 1 | Batch 5] Loss: 0.508594
        [GPU 1 | Epoch 1 | Batch 6] Loss: 0.269102
        [GPU 1 | Epoch 1] Average Loss: 1.085138
        [GPU 0 | Epoch 1 | Batch 6] Loss: 0.833279
        [GPU 0 | Epoch 1] Average Loss: 1.342471
    
  • #정상 출력 문 설명
  • [GPU 0], [GPU 1] → 각 GPU(rank 0, rank 1)가 독립적으로 배치 학습 수행
  • [GPU 0] → GPU 0이 처리한 배치 결과
  • [GPU 1] → GPU 1이 처리한 배치 결과
  • 각 GPU가 자신에게 할당된 데이터를 처리하면서 Loss 계산
  • 배치별 Loss를 GPU별로 따로 보여주기 때문에 사람이 봐도 어느 GPU가 어떤 데이터를 학습했는지 바로 확인 가능
PLEASE WAIT WHILE LOADING...