AWS 기술 블로그
분산 학습을 위한 AWS 컴퓨트 선택 가이드 (1편: 모델 규모와 하드웨어 선택)
대규모 언어 모델(LLM) 학습을 준비하는 팀이 가장 먼저 부딪히는 질문은 결국 “어떤 GPU를 얼마나, 어떻게 확보할 것인가”로 귀결됩니다. 그러나 이 질문은 H100이냐 B200이냐를 고르는 단순한 하드웨어 선택으로 끝나지 않습니다. 하나의 노드로 충분한지, 아니면 여러 노드로 확장해야 하는지, On-Demand로 그때그때 띄울지, Capacity Block으로 미리 예약할지, 평범한 EC2 클러스터로 감당이 되는지, 아니면 Amazon EC2 울트라클러스터(UltraClusters)나 Amazon EC2 울트라서버(UltraServer) 같은 특수한 아키텍처가 필요한지까지, 서로 맞물린 여러 층위의 의사결정이 동시에 요구됩니다.
이번 시리즈는 AWS에서 분산 학습 클러스터를 직접 설계 또는 운영하는 ML 엔지니어와 인프라 엔지니어를 독자로 상정하고 작성하였습니다. 첫 편인 이번 글에서는 모델 규모에 따른 확장 전략에서 출발해 GPU 인스턴스 포트폴리오, 노드 내부와 노드 간을 연결하는 인터커넥트, 모델을 여러 GPU에 나누는 병렬화 전략과 메모리 산정까지 ‘무엇을 고를까’의 기초를 순서대로 짚습니다. 잘못된 컴퓨트 선택은 곧바로 비용 낭비와 성능 저하로 이어지기 때문에, 각 갈림길에서 무엇을 근거로 판단해야 하는지에 초점을 맞췄습니다.
시리즈 블로그 보기
- 분산 학습을 위한 AWS 컴퓨트 선택 가이드 (1편: 모델 규모와 하드웨어 선택)
- 분산 학습을 위한 AWS 컴퓨트 선택 가이드 (2편: 초대규모 스케일링과 인스턴스 확보)
- 분산 학습을 위한 AWS 컴퓨트 선택 가이드 (3편: 클러스터 구축과 운영)
두 가지 확장 전략: 스케일 업과 스케일 아웃
분산 학습에서 컴퓨트를 키우는 방향은 크게 두 갈래로 나뉩니다. 하나는 단일 인스턴스 안에서 더 강력한 GPU와 더 많은 메모리로 밀어붙이는 스케일 업(Scale Up)이고, 다른 하나는 여러 인스턴스를 네트워크로 묶어 하나의 클러스터로 확장하는 스케일 아웃(Scale Out)입니다. 어느 쪽을 택할지는 거의 전적으로 학습하려는 모델의 규모가 결정합니다.
파라미터가 10M에서 10B 사이라면 단일 인스턴스 안에서 학습하거나 파인 튜닝하는 편이 가장 비용 효율적입니다. 이 구간에서는 노드 안의 NVLink와 NVSwitch가 GPU 사이의 통신을 모두 처리하기 때문에, 노드와 노드를 연결하는 네트워크를 따로 설계할 필요가 없습니다. 반면 10B에서 100B 구간으로 올라가면 본격적인 대규모 분산 학습이 불가피해집니다. 수백에서 수천 개의 GPU가 울트라클러스터로 묶여 함께 학습하며, 이때부터 AWS EFA(Elastic Fabric Adapter) 인터커넥트와 NCCL 설정이 성능을 좌우하는 필수 요소가 됩니다. 그리고 100B를 넘어 1T 이상으로 향하는 Frontier 모델에서는 단순히 클러스터를 키우는 것만으로는 인터커넥트가 병목이 되어 버립니다. 울트라서버 아키텍처가 바로 이 구간을 겨냥해 설계되었습니다.
CPU 기반 HPC 클러스터와 GPU 클러스터의 차이
전통적인 HPC용으로 사용되는 CFD(Computational Fluid Dynamics)나 WRF(Weather Research and Forecasting)와 같은 워크로드는 CPU 클러스터 위에서 MPI로 실행되며, 인터커넥트는 100~300 Gbps 정도로도 충분한 경우가 많습니다. 반면 ML/DL 학습은 GPU 클러스터에서 NCCL을 사용하고, p6-b300 단일 노드 기준으로는 최대 6,400 Gbps에 이르는 대역폭을 활용합니다. 같은 “클러스터”라는 단어를 쓰지만 두 세계가 요구하는 컴퓨트와 네트워크의 성격은 상당히 다릅니다. 아래 표1은 그 차이를 한눈에 정리한 것입니다.
| 항목 | CPU 기반 클러스터 (전통 HPC) | GPU 클러스터 (ML/DL) |
|---|---|---|
| 주요 워크로드 | CFD, NWP, FEA 등 | LLM/FM 학습, 파인튜닝, 추론 |
| 주요 컴퓨트 노드 | Hpc7g/7a/8a, C-타입 인스턴스 | p5/p6 (GPU) |
| 노드 간 통신 | MPI | NCCL |
| 인터커넥트 요구 | 100-300 Gbps
(워크로드 특성상 충분) |
최대 6,400 Gbps
(p6-b300 단일 노드) |
| AWS 운영 플랫폼 | ParallelCluster, PCS, AWS Batch | ParallelCluster, PCS, HyperPod, EKS |
표1. CPU 기반 클러스터와 GPU 클러스터 비교
참고로 AWS PCS(Parallel Computing Service)는 관리형 서비스, AWS ParallelCluster는 AWS에서 제공하는 오픈소스 기반 플랫폼입니다.
HPC 인프라 담당자가 분산 학습으로 전환할 때 알아야 할 것들
전통적인 HPC 클러스터를 운영해 온 인프라 담당자가 ML 분산 학습 환경을 담당하게 되면, 기존 경험과 어긋나는 지점들을 만나게 됩니다. 이 차이를 미리 이해해 두면 예상치 못한 문제를 줄일 수 있습니다. 다만 한 가지 먼저 짚어 둘 것이 있습니다. 흔히 “GPU를 좋은 것으로 채우면 빠를 것”이라고 생각하지만, 실제로 분산 학습 클러스터의 처리량과 비용을 결정하는 것은 GPU 그 자체보다 GPU를 둘러싼 네트워크와 데이터, 그리고 운영 방식인 경우가 훨씬 많습니다. 그래서 이 글에서는 처리량과 비용에 직접 영향을 주는 항목부터 순서대로 살펴보겠습니다.
첫째, 네트워크 패브릭이 학습 속도를 좌우합니다. 데이터 병렬 학습은 매 step마다 모든 GPU가 계산한 그래디언트를 AllReduce로 주고받는데, 모델이 커질수록 이 통신량이 수십에서 수백 기가바이트에 이릅니다. 결국 노드 간 대역폭과 지연이 곧 학습 처리량이 되고, GPU를 아무리 최신 사양으로 채워도 통신 단계에서 시간을 다 까먹으면 의미가 없습니다. AWS에서는 이 문제를 EFA와 NCCL, GPUDirect RDMA의 조합으로 풉니다. 주의할 점은 EFA가 제대로 동작하지 않으면 통신이 조용히 일반 TCP로 폴백되어, 성능은 크게 떨어지면서도 오류 메시지는 나오지 않아 원인을 찾기 어렵다는 것입니다. 또한 노드를 물리적으로 가깝게 묶는 cluster placement group은 노드 간 지연을 고르게 맞춰, 뒤에서 다룰 straggler(낙오자) 문제를 구조적으로 줄여 줍니다. 마지막으로 data parallel, tensor parallel, pipeline parallel, FSDP 및 ZeRO 같은 병렬화 전략을 워크로드 규모와 모델 구조에 맞게 골라야 통신과 연산의 균형이 맞습니다.
둘째, 데이터 파이프라인이 값비싼 GPU를 굶길 수 있습니다. GPU는 시간당 과금되는 비싼 자원이라, GPU가 데이터를 기다리며 놀고 있는 상태, 즉 idle은 그 자체로 가장 비싼 낭비입니다. 전통 HPC에서도 I/O는 신경 쓰는 부분이었지만, 분산 학습에서는 수천만에서 수억 개에 이르는 작은 파일을 반복적으로 읽어 들이는 경우가 많아 스토리지의 IOPS와 메타데이터 처리가 쉽게 병목이 됩니다. 이를 막는 방법은 크게 세 가지입니다. 첫째, Amazon S3에 있는 원본 데이터를 Amazon FSx for Lustre에 연결해 고속으로 읽어 들입니다. 둘째, 데이터를 GPU별로 겹치지 않게 나눠(샤딩) 각 GPU가 서로 다른 부분만 읽게 합니다. 셋째, 데이터 로더(data loader) 설정을 GPU가 굶지 않도록 튜닝합니다. 데이터 로더는 PyTorch와 같은 학습 프레임워크에 내장된 기능으로, CPU를 이용해 학습에 쓸 데이터를 읽고 다듬어 GPU에 공급하는 일을 맡습니다. 구체적으로는 저장소에서 데이터를 CPU 메모리로 읽어 와 디코딩 및 전처리하고, 여러 샘플을 배치(batch) 단위로 묶어 GPU가 바로 사용할 수 있도록 준비해 둡니다. 즉 GPU가 연산하는 동안 다음에 쓸 데이터를 미리 마련해 두는 공급 라인인 셈입니다. 이 공급 라인이 GPU 연산 속도를 따라가지 못하면 GPU는 다음 배치를 기다리며 놀게 됩니다. 그래서 데이터를 얼마나 미리 준비해 둘지(prefetch)와 데이터를 병렬로 읽어 오는 워커 프로세스 수(num_workers)를 조정해 GPU가 멈추지 않도록 맞춰 줍니다. 핵심은 단순합니다. 비싼 GPU가 멈추지 않고 계속 일하도록 데이터를 제때 공급하는 것입니다.
셋째, 비용과 용량 확보의 셈법이 완전히 다릅니다. 온프레미스 GPU 클러스터는 하드웨어를 구매하는 순간 비용이 모두 지출됩니다. 그래서 GPU를 놀려도 추가로 나가는 돈은 없고, 이미 들인 투자를 회수하려면 가동률을 최대한 끌어올려 빈틈없이 굴리는 것이 관건입니다. 반면 클라우드 GPU는 인스턴스가 켜져 있는 시간만큼 과금됩니다. 따라서 GPU가 일을 하든 놀든, 켜져 있는 한 매 시간 실제 비용이 빠져나가며, 유휴 GPU는 곧바로 금전적 손실이 됩니다. 온프레미스가 ‘이미 산 자산을 얼마나 알차게 쓰느냐’의 문제라면, 클라우드는 ‘필요할 때만 켜고 끝나면 바로 끄느냐’의 문제인 셈입니다. 따라서 잡 큐가 비면 노드 수를 0까지 줄이는 스케일 다운 운영(PCS나 Slurm의 power-saving 기능)이 중요해집니다. 또 하나, 클라우드에서는 용량 확보 자체가 과제입니다. 최신 GPU 인스턴스는 원하는 시점에 온디맨드로 항상 잡히지 않을 수 있어, 다수의 GPU 노드가 필요하면 Capacity Block이나 ODCR(On-Demand Capacity Reservation)을 미리 계획해야 합니다. 비용을 더 아끼려 Amazon EC2 스팟 인스턴스를 쓴다면 중간 회수(interruption)를 전제로 운영해야 하며, 이는 뒤에서 다룰 체크포인트 전략과 연결됩니다.
넷째, 주기적인 체크포인트가 필수이며, 회복까지 자동화해야 합니다. 전통 HPC 잡은 수 시간 안에 끝나는 경우가 많아 재시작이 드물었습니다. 하지만 대규모 LLM 학습은 며칠에서 몇 주까지 이어지기 때문에, 노드 장애나 스팟 회수에 대비한 체크포인트 저장을 빼놓을 수 없습니다. 여기서 한 걸음 더 나아가야 할 부분이 있습니다. 노드 수가 수십에서 수천 대로 늘어나면 하드웨어 장애는 더 이상 드문 예외가 아니라 일상적으로 일어나는 일이 됩니다. 단일 GPU의 ECC 메모리 오류, NCCL 통신 timeout, 노드 한 대의 다운 — 그런데 동기식 학습에서는 노드 하나만 멈춰도 전체 학습이 함께 멈춰 버립니다. 그래서 단순히 체크포인트를 저장하는 것을 넘어, 헬스 체크로 불량 노드를 감지하고, 그 노드를 격리한 뒤, 가장 최근 체크포인트에서 자동으로 재시작하는 회복 루프가 필요합니다. Amazon SageMaker HyperPod의 자동 복구 기능이 바로 이 문제를 겨냥한 것입니다.
다섯째, AllReduce는 동기적으로 동작하며, 가장 느린 노드가 전체를 결정합니다. AllReduce는 모든 GPU가 그래디언트 계산을 끝내야 동기화가 시작되므로, 가장 느린 노드(straggler)가 전체 학습 속도를 좌우합니다. 클러스터의 모든 노드가 하드웨어 스펙과 네트워크 지연 면에서 고르게 맞춰져 있어야 하는 이유입니다.
여섯째, 소프트웨어 스택의 버전 정합성이 까다롭습니다. MPI나 컴파일러 버전을 맞추던 전통 HPC 경험과 비슷하지만 한층 더 예민합니다. 분산 학습 스택은 여러 층이 위아래로 맞물려 있습니다. 맨 아래에 GPU 드라이버가 있고, 그 위에 CUDA가, 다시 그 위에 cuDNN 같은 연산 라이브러리와 NCCL 같은 통신 라이브러리가, 그리고 맨 위에 PyTorch 같은 딥러닝 프레임워크가 얹힙니다. 이 계층들의 버전이 정확히 맞물려야 하고, 하나만 어긋나도 학습이 명확한 오류 없이 느려집니다. 특히 원인이 두 갈래로 나뉘는데, 어긋나는 계층에 따라 연산이 느려지는 경우와 통신이 느려지는 경우로 갈립니다. 먼저 CUDA, cuDNN, PyTorch 버전이 어긋나면 노드 내 GPU 연산이 최적화된 커널 대신 느린 커널로 실행되거나(성능 저하) 크래시가 납니다. 반면 EFA 통신 계층(aws-ofi-nccl 플러그인, libfabric 등)이 어긋나거나 누락되면 NCCL이 EFA를 쓰지 못하고 TCP(Socket)로 폴백해 노드 간 통신 대역폭이 급락합니다. 전자는 GPU 내 연산의 문제이고 후자는 노드 사이 네트워크의 문제라, 병목이 생기는 위치부터 다릅니다. 두 경우 모두 대개 명확한 오류 없이 성능만 떨어지기 때문에 더 곤란합니다. 그래서 분산 학습에서는 컨테이너가 사실상 표준입니다. CUDA, cuDNN, NCCL과 그 위의 프레임워크(PyTorch 등)를 검증된 조합으로 묶으면 노드마다 버전을 맞출 필요가 없으며, AWS Deep Learning Containers(DLC)나 NVIDIA NGC 컨테이너가 그 예입니다. 다만 GPU 드라이버와 EFA는 컨테이너가 아니라 호스트에 있어야 하므로, 드라이버와 EFA가 미리 깔린 AWS Deep Learning AMI를 베이스로 쓰고 그 위에 컨테이너를 올리는 구성(AMI가 아랫층, 컨테이너가 윗층)이 가장 안정적입니다.
일곱째, GPU 메모리에는 swap이 없고, 모니터링 지표도 다릅니다. 먼저 GPU 메모리에는 swap이 없습니다. 일반적인 시스템에서는 메모리가 부족하면 운영체제가 당장 쓰지 않는 데이터를 디스크(swap 영역)로 잠시 내보내 프로세스를 (느려질지라도) 이어 가지만, GPU는 GPU 메모리가 부족해지는 순간 OOM(Out Of Memory)과 함께 프로세스가 즉시 종료됩니다. 그래서 모델 크기, 배치 크기, gradient checkpointing 설정을 GPU 메모리 용량에 맞춰 사전에 계산해 두어야 합니다. 최근에는 메모리가 부족할 때 옵티마이저 상태나 파라미터를 CPU나 NVMe로 내리는 offload 기법(DeepSpeed ZeRO-Offload/ZeRO-Infinity, PyTorch FSDP의 CPU offload 등)도 있지만, 이는 운영체제가 투명하게 해 주는 swap이 아니라 PyTorch와 같은 프레임워크가 명시적으로 설계해야 하는 동작이고 PCIe 대역폭에서 성능 페널티를 동반합니다. 따라서 ‘기본적으로 swap에 의존할 수 없으므로 메모리를 사전에 계산한다’는 원칙은 그대로 유효합니다. 다음으로 모니터링 지표가 다릅니다. 전통 HPC가 CPU 사용률과 MPI 통신 메트릭을 봤다면, 분산 학습에서는 GPU 활용률(SM utilization)과 GPU 메모리 사용량이 핵심입니다. 한 가지 주의할 점은, nvidia-smi의 ‘GPU-Util’ 수치는 SM(GPU 안에서 실제 연산을 수행하는 Streaming Multiprocessor)이 얼마나 바쁜지가 아니라 ‘측정 구간 동안 커널이 하나라도 돌았는가’에 가깝다는 것입니다. 진짜 SM 활용률이나 텐서코어 활용률을 보려면 NVIDIA DCGM(Data Center GPU Manager) 지표(DCGM_FI_PROF_SM_ACTIVE, DCGM_FI_PROF_PIPE_TENSOR_ACTIVE 등)가 정확하며, AWS에서는 보통 CloudWatch와 DCGM exporter를 함께 구성합니다.
# GPU 활용률 실시간 모니터링
nvidia-smi dmon -s u # SM utilization + 메모리 I/O 시간 비율 (%, 1초 간격)
# (단, 정밀한 SM 활용률은 DCGM_FI_PROF_SM_ACTIVE 권장)
# GPU 활용률이 낮을 때 진단 순서
# 1. 데이터 로딩 후 idle인가? -> lfs hsm_state로 FSx Preload 확인
# 2. AllReduce 후 idle인가? -> NCCL_DEBUG=INFO로 EFA 통신 확인
# 3. 특정 노드만 느린가? -> straggler 노드 하드웨어 점검
AWS GPU 인스턴스 포트폴리오
AWS의 GPU 인스턴스는 용도에 따라 크게 세 가지 유형으로 이해하면 편합니다. 소규모 학습과 그래픽 작업을 위한 G 계열, 대규모 분산 학습의 표준으로 자리 잡은 P 계열의 노드 내 8-GPU 구성(흔히 NVL8라고 부릅니다), 그리고 그보다 더 큰 NVLink 도메인으로 Frontier 모델을 겨냥하는 울트라서버 구성입니다. 다만 ‘NVL8’이나 ‘울트라서버’는 아키텍처를 가리키는 표현이고, 실제로 콘솔에서 고르는 단위는 g6, p5, p6-b200, p6-b300와 같은 인스턴스 패밀리라는 점은 기억해 두면 좋습니다. 어떤 카테고리를 고르느냐에 따라 GPU 사이의 통신 방식과 확장 한계가 근본적으로 달라지기 때문입니다.
G 계열: 소규모 모델과 그래픽
G 계열은 소규모 모델의 학습과 파인튜닝, 그리고 추론에 적합합니다. 다만 G 계열 인스턴스는 노드 안에 여러 GPU를 탑재하더라도 이들을 NVLink로 연결하지 않아, GPU 사이의 통신이 대역폭이 낮은 PCIe에 묶입니다. PCIe는 GPU를 직접 연결하는 NVLink에 비해 대역폭이 한참 낮기 때문에, 여러 GPU를 긴밀하게 묶어 자주 통신해야 하는 대규모 분산 학습에는 맞지 않습니다. 그래서 G 계열은 본격적인 분산 학습보다는 비용 효율적인 실험이나 추론 환경으로 활용하는 것이 현실적입니다.
P 계열(NVL8): 대규모 분산 학습의 표준
P 계열의 NVL8 구성은 각 인스턴스에 GPU 8장을 NVLink/NVSwitch로 묶어 탑재합니다. 노드 안에서는 GPU끼리 NVLink로 직접 고속으로 통신하고, 노드 사이는 EFA 네트워크로 연결되는 구조입니다. 현재 대표적으로 H100 세대의 p5, H200 세대의 p5en, 그리고 Blackwell 세대의 p6(B200 및 B300)등이 제공되고 있습니다.
먼저 p5.48xlarge는 H100 GPU 8장에 총 640 GiB의 GPU 메모리를 갖추고, 노드 간에는 32개의 EFA 인터페이스로 총 3,200 Gbps의 대역폭을 제공합니다. 10B에서 100B 규모의 모델 학습에 가장 널리 쓰이는 선택지입니다.
p5en.48xlarge는 p5와 동일하게 GPU 8장을 탑재하지만, GPU가 H200으로 업그레이드되어 GPU 메모리가 총 약 1.1 TiB(GPU당 약 141 GiB)로 p5 대비 76% 늘어납니다. 시스템 RAM은 2.0 TiB, EFA 대역폭은 3,200 Gbps로 동일하나, 3세대 EFA(EFAv3)를 적용해 네트워크 레이턴시가 최대 35% 개선됩니다. 노드 내 GPU 연결도 p5와 같은 NVSwitch 900 GB/s입니다. p5 대비 GPU 메모리가 크게 늘어 더 큰 모델을 사용할 수 있으면서 NVLink 및 EFA 대역폭은 동일하므로, p5에서 메모리 부족이 제약이었던 워크로드에 적합한 선택입니다.
다음으로 p6-b200.48xlarge는 B200 GPU 8장에 약 1.4 TiB의 GPU 메모리(GPU당 약 179 GiB)와 2.0 TiB의 시스템 RAM을 갖추고, 8개의 EFA 인터페이스로 총 3,200 Gbps를 제공합니다. p5보다 GPU 메모리가 두 배 이상 크기 때문에, 더 큰 파운데이션 모델이나 MoE를 더 적은 노드에 담아야 할 때 고려할 만한 선택지입니다.
가장 위에는 p6-b300.48xlarge가 있습니다. B300(Blackwell Ultra) GPU 8장에 약 2.1 TiB의 GPU 메모리(GPU당 약 269 GiB)와 4.0 TiB의 시스템 RAM을 갖추고, 16개의 EFA 인터페이스로 총 6,400 Gbps를 제공합니다. 이는 B200의 정확히 두 배에 해당하는 네트워크 대역폭으로, 수조 파라미터 규모의 Frontier 모델이나 대형 MoE 학습처럼 노드 간 통신이 병목이 되는 워크로드에 적합합니다.
| 인스턴스 | GPU | GPU 수 | GPU 메모리 | 시스템 RAM | EFA 대역폭 | NVLink BW/GPU |
|---|---|---|---|---|---|---|
| p5.48xlarge | H100 SXM5 | 8 | 640 GiB | 2.0 TiB | 3,200 Gbps (32 IF) | 4세대 / 900 GB/s |
| p5en.48xlarge | H200 | 8 | 1,128 GiB | 2.0 TiB | 3,200 Gbps (16 IF) | 4세대 / 900 GB/s |
| p6-b200.48xlarge | B200 | 8 | 1,432 GiB | 2.0 TiB | 3,200 Gbps (8 IF) | 5세대 / 1,800 GB/s |
| p6-b300.48xlarge | B300 Blackwell Ultra | 8 | 2,144 GiB | 4.0 TiB | 6,400 Gbps (16 IF) | 5세대 / 1,800 GB/s |
표2. 대표 P-Series NVL8 인스턴스 사양 비교
(*) GPU 메모리는 AWS EC2 사양(GiB) 기준, NVLink BW는 NVIDIA 데이터시트(GB/s, 양방향 합산) 기준
리전 가용성도 함께 고려해야 합니다. 같은 인스턴스라도 모든 리전에서 사용할 수 있는 것은 아니며, 특히 최신 GPU 세대일수록 초기에는 소수 리전에서만 제공되다가 점차 확대됩니다. 일반적으로 이전 세대인 P5(H100)가 미국, 유럽, 아시아 등 다수 리전에 널리 퍼져 있는 반면, 최신 세대인 p6-b200(Blackwell) 및 p6-b300(Blackwell Ultra)은 미국 중심의 제한된 리전에서 제공합니다. 리전 목록은 수시로 확대되므로 본 글의 특정 목록을 신뢰하기보다, 사용 시점에 직접 확인하는 것을 권장합니다.
GPU 인터커넥트: PCIe에서 NVLink, 그리고 NVSwitch로
NVLink는 NVIDIA가 개발한 GPU 간 고속 직접 통신 인터페이스로, CPU를 거치지 않고 GPU끼리 직접 데이터를 주고받습니다. p5 기준으로 GPU당 양방향 900 GB/s, p6 기준으로는 1,800 GB/s를 제공합니다. 기존 서버에서 GPU끼리 통신하려면 데이터가 CPU 메모리를 경유해야 했고, 이 경로가 대규모 분산 학습에서는 심각한 병목이었습니다. NVLink는 이 경로를 GPU 직결로 바꿔 병목을 제거합니다.
| 구분 | PCIe (G-Series) | NVLink (P-Series) |
|---|---|---|
| GPU 간 통신 경로 | CPU 메모리 경유 | GPU 직접 통신 (CPU 우회) |
| 대역폭 (양방향) | PCIe Gen5 기준 시스템 약 128 GB/s | 4세대(P5) 900 GB/s/GPU
5세대(P6) 1,800 GB/s/GPU |
| 레이턴시 | 높음 (CPU 개입) | 낮음 (직접 연결) |
| 대규모 분산 학습 | 부적합 (통신 병목 발생) | 적합 (고속 병렬 통신) |
표3. PCIe와 NVLink 비교
그런데 GPU를 NVLink로 1:1 직접 연결하는 방식만으로 8개 GPU를 모두 연결하기에는 한계가 있습니다. GPU당 NVLink 포트 수가 정해져 있어, 모든 GPU 쌍을 직접 연결(full-mesh)하려면 포트가 부족하고, 무리하게 연결하더라도 일부 쌍은 다른 GPU를 경유해야 해서 쌍마다 대역폭과 레이턴시가 달라지는 비균일 토폴로지가 됩니다.
이 문제를 해결하는 것이 NVSwitch입니다. NVSwitch는 중앙 스위치 칩으로, 모든 GPU가 여기에 연결되고 NVSwitch가 라우팅을 담당합니다. 덕분에 어떤 GPU 쌍이든 NVSwitch를 단 한 번만 거쳐(1-hop) 통신하게 되어, 위치에 상관없이 대역폭과 레이턴시가 균일해집니다. 흔히 말하는 “All-to-All 패브릭”이란, 어느 GPU든 다른 모든 GPU와 동시에, 풀 대역폭으로, 단일 hop으로 통신할 수 있는 구조를 뜻합니다. 그래서 p5, p6 같은 8-GPU 인스턴스는 NVLink와 NVSwitch를 함께 써서, 노드 안의 GPU들이 균일하게 맞물립니다. 집합 통신(AllReduce 등)의 성능이 GPU 쌍에 따라 흔들리지 않는 것도 이 덕분입니다. 참고로 p5 및 p6 같은 8-GPU 인스턴스에는 NVSwitch가 여러 개 탑재되어, 일부에 장애가 생겨도 통신이 유지됩니다.
[P5 기준 인트라노드 vs 인터노드 대역폭 비교]
인트라노드 (NVLink/NVSwitch):
NVLink 4세대 기준 GPU당 양방향 900 GB/s
8 GPU 노드 내 집계(aggregate): 7,200 GB/s
인터노드 (EFA):
p5 기준 EFA 총 3,200 Gbps = 400 GB/s (노드 전체 집계)
노드 내 NVLink가 노드 사이 EFA보다 한 자릿수(대략 10배 안팎) 높은 대역폭을 냅니다. 단순 집계로는 7,200 GB/s 대 400 GB/s로 약 18배지만, 이 둘은 기준이 다릅니다. NVLink 7,200은 노드 안 8개 GPU의 대역폭을 양방향 합산해 모두 더한 값이고, EFA 400 GB/s은 노드 하나가 외부로 내보내는 단방향 총 대역폭입니다. 방향 기준을 같은 쪽으로 맞추면 배수는 약 9배 안팎으로 좁혀집니다. 어느 기준으로 따지든 노드 안이 노드 사이보다 압도적으로 빠르다는 결론은 변하지 않습니다.
그래서 Tensor Parallel처럼 레이어마다 통신이 빈번한 병렬화는 반드시 동일 노드 내 GPU 간(NVLink) 안에서 처리해야 성능을 유지할 수 있습니다.
이 격차가 중요한 이유는 병렬화 방식마다 GPU 사이 통신의 빈도와 위치가 다르기 때문입니다. 먼저 Tensor Parallel과 Pipeline Parallel이 모델을 나누는 방식이 정반대라는 점을 짚어 둘 필요가 있습니다. Pipeline Parallel은 층을 통째로 갈라 GPU마다 서로 다른 구간을 맡깁니다. 100층 모델을 4개 GPU에 나눈다면(4개 stage) 1번 GPU가 1~25층, 2번 GPU가 26~50층을 담당하는 식입니다. 반면 Tensor Parallel은 층을 나누는 게 아니라 각 층 내부의 가중치 행렬을 GPU들에 조각내어 분산합니다. 따라서 100층 모델에 Tensor Parallel을 8-way로 걸면, 1층부터 100층까지 모든 층이 8개 GPU에 쪼개져 올라가고, 모든 GPU가 전 층의 계산에 함께 관여합니다.
바로 이 구조 때문에 Tensor Parallel은 통신이 극도로 잦습니다. 각 층을 계산할 때마다 GPU들이 자기가 맡은 행렬 조각의 부분 결과를 내놓고, 이를 AllReduce로 합쳐야 다음 단계로 넘어갈 수 있습니다. 이렇게 빈번한 통신이 EFA를 통해 인스턴스 경계를 넘어가는 순간, 노드 내 NVLink 대비 한참 낮은 대역폭에 묶여 학습 효율이 급격히 떨어집니다.
그래서 정석은 Tensor Parallel의 분할 수(degree)를 노드당 GPU 수인 8을 넘지 않게 두어, 이 잦은 AllReduce가 노드 안 NVLink 도메인 안에서만 일어나도록 가두는 것입니다. 그리고 노드 경계를 넘는 통신에는 상대적으로 빈도가 낮은 병렬화, 즉 stage 경계에서만 데이터를 주고받는 Pipeline Parallel이나 step당 한 번만 그래디언트를 동기화하는 Data Parallel을 배치합니다.
병렬화 전략과 컴퓨트 배치의 관계
어떤 병렬화 전략을 쓰느냐에 따라 통신 패턴이 달라지고, 그에 따라 어떤 인터커넥트 계층이 병목이 되는지도 바뀝니다. 따라서 병렬화 전략과 컴퓨트 배치는 늘 함께 결정해야 합니다.
| 병렬화 전략 | 주 통신 패턴 | 통신 빈도 | 권장 배치 |
|---|---|---|---|
| Data Parallel (DDP/FSDP) | All-Reduce (gradient sync) | step당 1회 | 울트라클러스터(EFA)로 충분 |
| Tensor Parallel | All-Reduce (레이어마다) | 레이어마다 | 노드 내 NVLink 또는 울트라서버 |
| Pipeline Parallel | P2P send/recv (stage 경계) | stage 경계 | EFA로 충분 |
| Expert Parallel (MoE) | All-to-All (token dispatch/combine) | 레이어마다 | NVLink 도메인(울트라서버) 권장 |
표4. 병렬화 전략별 통신 패턴과 권장 배치
특히 MoE(Mixture of Experts)를 사용하면 token을 여러 expert로 분배하고 그 결과를 다시 모으는 단계에서 All-to-All 통신이 발생합니다. 이 통신이 왜 부담이 되는지는 AllReduce와 비교하면 분명해집니다. 먼저 reduce(리듀스)는 여러 GPU가 각자 가진 값을 하나의 연산(학습에서는 주로 gradient 합산)으로 합쳐 단일 결과로 줄이는 것을 말합니다. AllReduce는 바로 이 reduce를 gradient에 적용한 통신입니다. 각 GPU가 자기 gradient를 내놓으면 이를 모두 더해(= reduce) 하나로 만든 뒤, 그 동일한 결과를 모든 GPU에 똑같이 되돌려줍니다.
반면 All-to-All은 reduction(합치는 단계)이 없습니다. 각 GPU가 상대별로 서로 다른 데이터를 보내고, 서로 다른 데이터를 돌려받는 personalized 통신이라, 합쳐서 줄일 것 없이 데이터가 그대로 재배치됩니다. 그래서 알고리즘적으로 최적화하거나 다른 연산과 겹쳐 숨기기 어렵고, 레이턴시 및 토폴로지에 민감합니다. 게다가 MoE에서는 큰 activation을 층마다 두 번(dispatch & combine) 재배치하므로 실질적인 통신 부담이 상당합니다.
여기에 MoE 특유의 문제가 하나 더 겹칩니다 — 토큰이 어느 expert로 몰리느냐에 따라 GPU마다 처리 및 전송할 양이 달라지는 부하 불균형(load imbalance)입니다. 즉 균등하게 주고받는 통신이 아니라 GPU마다 양이 달라지면서 straggler가 발생합니다. 이 통신이 EFA를 타고 노드 경계를 넘어가면, 큰 통신량과 불균형이 맞물려 성능이 크게 떨어집니다.
반면 울트라서버의 NVLink Switch 기반 연결에서는 훨씬 낮은 레이턴시와 높은 대역폭으로 이 All-to-All을 소화할 수 있습니다. 그래서 MoE 학습처럼 All-to-All이 빈번한 워크로드에서는 노드 경계를 넘지 않는 울트라서버(확장된 NVLink 도메인)가 유리하게 작용합니다. 울트라서버에 대해서는 다음 블로그에서 좀 더 자세히 설명할 예정입니다.
모델 메모리 요구량 계산
어떤 인스턴스가 필요한지 가늠하려면 먼저 모델의 메모리 요구량을 계산해야 합니다. 보수적으로 fp32를 기준으로 잡으면 다음과 같습니다.
메모리 계산 (fp32 기준 보수적 추정):
파라미터 4 bytes + 그래디언트 4 bytes + Adam optimizer state 8 bytes = 16 bytes/param
-> 70B 모델: 70 x 10^9 x 16 bytes = 약 1,120 GB
혼합 정밀도(bf16 forward + fp32 master weight) 사용 시:
bf16 파라미터 2 + fp32 master 4 + 그래디언트 4 + optimizer 8 = 약 18 bytes/param
activation memory와 통신 버퍼는 별도 추가됨
이 계산대로라면 70B 모델은 fp32 기준 약 1,120 GB(≈1,043 GiB)의 모델 상태가 필요합니다. 혼합 정밀도를 써도 이 값은 줄지 않습니다 — bf16 파라미터와 별도로 fp32 master weight를 유지해야 해서 model-state는 오히려 소폭 늘어나기(16→18 bytes/param) 때문입니다. 혼합 정밀도의 이점은 연산 속도와 activation 메모리 절감이지, model-state 절감이 아닙니다.
어느 쪽이든 이 크기는 GPU 메모리가 640 GiB인 단일 p5.48xlarge에 수용할 수 없습니다. 모델 상태만으로도 노드 두 대분(2×640 GiB)에 육박하고, 여기에 activation과 통신 버퍼까지 더하면 현실적으로 2~3개 노드 이상에 나눠 올려야 합니다. 바로 이 지점부터 Tensor Parallel이나 Pipeline Parallel이 등장합니다. 파라미터, 그래디언트, 옵티마이저, activation을 byte 단위로 정밀하게 계산하는 방법은 아래를 참고하세요.
- EleutherAI — Transformer Math 101: 트랜스포머의 파라미터, 옵티마이저, activation 메모리와 연산량을 공식으로 계산하는 가장 실용적인 가이드
- Hugging Face — Model Memory Anatomy (transformers 공식 문서): 학습 중 메모리가 어디에 얼마나 쓰이는지 항목별 분해
- ZeRO 논문 (Rajbhandari et al., arXiv:1910.02054): 혼합 정밀도 Adam의 “16 bytes/param” model-state 분해의 근거
- Reducing Activation Recomputation in Large Transformer Models (Korthikanti et al., arXiv:2205.05198): activation 메모리 공식과 activation checkpointing 효과
맺음말
여기까지가 분산 학습을 위해 ‘무엇을 고를까’의 첫 단계입니다. 1편의 핵심은 단순합니다. 분산 학습의 컴퓨트 선택은 가장 빠른 GPU를 찾는 문제가 아니라, 학습하려는 모델 규모에서 출발하는 문제입니다. 10B 이하라면 단일 p5/p6 인스턴스의 NVLink 도메인 안에서 끝내는 것이 가장 효율적이고, 그 이상으로 올라가면 여러 노드를 EFA로 묶어야 합니다. 노드 안 NVLink와 노드 사이 EFA 사이에는 한 자릿수 배수의 대역폭 격차가 있으므로, Tensor Parallel처럼 통신이 잦은 병렬화는 노드 안에 가두고 통신 빈도가 낮은 병렬화는 노드 사이로 펼치는 것이 정석입니다. 그리고 모델 메모리 요구량을 먼저 계산해 두어야 몇 장의 GPU가 필요한지 가늠할 수 있습니다.
다음 2편에서는 이 규모가 수천 장으로 커졌을 때 그 많은 GPU를 어떻게 하나의 학습으로 묶는지를 다룹니다. 울트라클러스터와 울트라서버라는 두 초대규모 아키텍처, 그리고 이런 고성능 인스턴스를 실제로 확보하는 전략이 주제입니다.