병렬 처리 개요

병렬 처리 개요 (Parallelism Overview)

이 페이지는 SGLang Diffusion이 제공하는 여러 병렬 처리 전략을 설명해요. 각 전략은 DiT forward pass의 서로 다른 차원을 분할하며, 이것이 바로 결합할 수 있는 이유예요. 총 GPU 수는 정도의 곱이에요:

num_gpus = cfg_parallel_degree × tp_size × sp_degree
sp_degree = ulysses_degree × ring_degree

출처: 문서

본문

SGLang Diffusion은 여러 병렬 처리 전략을 제공해요. 각 전략은 DiT forward pass의 서로 다른 차원을 분할하며, 이것이 바로 결합할 수 있는 이유예요. 총 GPU 수는 정도의 곱이에요:

num_gpus = cfg_parallel_degree × tp_size × sp_degree
sp_degree = ulysses_degree × ring_degree

이 페이지는 지도예요 — 각 축이 무엇을 하는지, 어떤 결합이 합법적인지, 하나를 어떻게 고르는지요. 축별 심화는 Sequence Parallelism, Encoder Parallelism(텍스트/이미지 인코더는 자체 노브가 있는 별도 축), CLI reference에 있어요.

축 (The axes)

Strategy Splits Communication Flag
CFG parallel guidance 브랜치 디노이즈 스텝당 하나의 결합(combine) --cfg-parallel-size
Tensor parallel (TP) 가중치와 어텐션 헤드 트랜스포머 블록당 all-reduce --tp-size
Ulysses SP 어텐션 밖 시퀀스 ↔ 안쪽 헤드 어텐션당 두 번의 all-to-all --ulysses-degree
Ring SP 어텐션 안쪽 시퀀스 행 이웃 전용 K/V 회전, 컴퓨트와 중첩 --ring-degree
K/V-gather CP 어텐션 안쪽 시퀀스 행 어텐션당 한 번의 K/V all-gather --kv-gather-degree
Data parallel 요청 복제본 사이 통신 없음 --dp-size

두 전략은 서로 다른 차원을 분할할 때 결합돼요. TP와 Ulysses는 모두 헤드를 다루지만 직렬로 결합돼요 — TP가 프로젝션 가중치를 분할하고, 그다음 Ulysses가 TP-로컬 헤드의 활성화를 분할해요. Ring과 Ulysses는 ring이 행을 분할하고 Ulysses가 헤드를 분할하므로 결합돼요. Ring은 K/V-all-gather 스타일의 어텐션 병렬 처리와 결합이 없어요. 둘 다 같은 질문(랭크의 쿼리 행이 원격 K/V를 어떻게 보는가)에 답하므로 한 슬롯의 대안이지 보완이 아니에요.

형태에 일어나는 일 (What happens to the shapes)

tp_size = T, ulysses_degree = U, ring_degree = R에 대해 하나의 어텐션은 다음을 실행해요:

[B, S/(U·R), H/T, D]                     sequence-sharded activations
   │  Ulysses input all-to-all (inside each Ulysses group)
   ▼
[B, S/R, H/(T·U), D]                     full sequence of this ring block, few heads
   │  ring attention (R−1 neighbor hops; Q never moves, K/V rotate)
   ▼
[B, S/R, H/(T·U), D]
   │  Ulysses output all-to-all (inverse)
   ▼
[B, S/(U·R), H/T, D]

ring 병합(online softmax)은 ring 그룹의 모든 랭크가 서로 다른 행에 걸쳐 동일한 헤드를 보유하도록 요구하며, 그룹 구성이 이를 보장해요. K/V-gather(CP 스타일) 변형은 같은 슬롯을 다르게 채워요. R−1 중첩 홉 대신 K/V를 한 번 all-gather하고 로컬 Q 행을 전체 시퀀스에 대해 한 번에 계산해요 — 더 적고 더 큰 전송이지만, 랭크당 전체 K/V를 보유하는 대가를 치러요. ring처럼 행을 분할하므로 헤드 제약을 추가하지 않아요. SP 정도가 명시적으로 설정되지 않으면 sp_degree=2kv_gather_degree=2로 기본 설정되고(측정된 우위 영역), 더 높은 정도는 Ulysses로 기본 설정돼요. Ulysses 그룹은 연속 랭크에, ring 그룹은 strided 랭크에 배치되므로, 노드 우선 랭크 매핑에서 Ulysses 트래픽은 인트라노드 NVLink에 유지되고(all-to-all은 전체 이분 대역폭이 필요), ring 홉은 더 느린 인터커넥트를 건너는데 이웃 전용 전송이 컴퓨트와 중첩돼요. 잘못 매핑된 레이아웃은 수치적으로 정확하지만 조용히 성능을 잃는데, 샤딩 실행이 예상외로 느릴 때 확인할 만해요.

제약 (Constraints)

  • num_attention_heads % tp_size == 0 — TP는 프로젝션에서 헤드를 분할.
  • (num_attention_heads / tp_size) % ulysses_degree == 0 — Ulysses는 TP-로컬 헤드를 분할. H % U == 0만으로는 불충분: 56 헤드는 tp=2, ulysses=4(28 % 4)에서 통과하고 tp=4, ulysses=4(14 % 4)에서 실패해요.
  • Ring은 헤드 제약을 추가하지 않지만(행을 분할), 시퀀스 — 모델별 패킹 정렬 포함 — 가 ulysses × ring으로 나누어 떨어져야 해요. ring은 Ulysses의 내부 행 분할 위에 외부 행 분할을 추가하기 때문이에요.
  • Ring은 supports_ring_rotation()을 선언하는 어텐션 백엔드가 필요해요 — 홉별 병합에는 커널의 softmax LSE가 필요하기 때문이에요. fasage_attn이 이를 선언하고, 런처는 미설정 시 fa를 자동 선택해요.
  • USPAttention의 마스크/tail-padded 텍스트 경로와 replicated-prefix, -suffix, -kv-prefix 경로는 모두 ring을 지원해요. 샤딩된 K/V가 ring을 통해 회전하는 동안 tail-pad 또는 replicated 부분은 한 번 로컬로 어텐션되고 동일한 online-softmax 병합으로 ring 결과에 결합돼요. 이는 대부분의 모델(flux, flux_2, qwen_image, zimage, glm_image, ernie_image 등)이 사용하는 joint text+image 어텐션을 다뤄요.
  • ring 아래 여전히 NotImplementedError를 발생시키는 것: USPAttention의 일반 varlen 경로(HunyuanVideo가 사용하는 행당 여러 패킹된 세그먼트 — 아직 ring 인지 회전 없음)와 레거시 stacked-QKV UlyssesAttention 레이어(지금은 Wan의 VSA sparse-attention 변형 하나로 줄어듦. 병합할 softmax LSE가 없고 다른 커널 없이는 ring 지원을 얻을 수 없음).
  • 런처는 num_gpus를 정도의 곱과 검증하고 불일치 시 빠르게 실패해요.

Ulysses 전송 (The Ulysses transport)

all-to-all은 일반적으로 NCCL로 실행돼요. 정확히 2 GPU에서 peer-to-peer 접근이 있으면 CUDA-IPC 전송이 기본적으로 이를 대체해요. 각 랭크가 절반을 피어의 매핑된 스테이징 버퍼에 직접 쓰고, NCCL rendezvous 대신 GPU 측 시퀀스 카운터를 사용해요. all-to-all은 순열(permutation)이지 절대 감소(reduction)가 아니므로 전송은 결과를 바꿀 수 없어요 — 출력은 NCCL 경로와 비트 단위로 동일해요.

Environment variable Default Meaning
SGLANG_DIFFUSION_IPC_A2A 1 0으로 설정하면 NCCL 강제
SGLANG_DIFFUSION_IPC_A2A_TIMEOUT_MS 10000 피어 대기를 위한 데드락 백스톱; 만료 시 전송이 모든 랭크에서 은퇴하고 불완전한 데이터를 반환하는 대신 요청이 실패
SGLANG_DIFFUSION_IPC_A2A_MAX_BUFFERS 16 유지되는 스테이징 쌍; 많은 해상도 서빙에서 올림

전송과 독립적으로 기본 경로는 이미 세 개의 Q/K/V 입력 교환을 하나의 destination-major 집합 연산으로 패킹해요. 소수의 모델(예: LTX-2)은 대신 enable_packed_qkv_input_a2a를 선택하는데, 이는 하나의 페이로드로 병합하는 대신 전용 스트림에 걸쳐 세 개의 별도 교환을 파이프라인해요 — 기본에 대한 엄격한 업그레이드라기보다 다른 트레이드오프예요.

노드 간 통과를 견디는 축 (Which axes tolerate crossing nodes)

각 축은 고정된 통신 패턴을 가지며, 그 패턴 — 스텝당 볼륨, 발화 빈도, 컴퓨트 뒤에 숨길 수 있는지 — 이 축이 NVLink에서 인터노드 패브릭으로의 하락을 견디는지 결정해요. 크로스-노드 친화도가 높은 순서:

Axis Pattern Traffic per denoise step Cross-node verdict
Data parallel 복제본 사이 통신 없음 요청 경로에서 0 최고. 복제본은 시작 init과 제어 연산 fan-out만 공유; 빠른 인터커넥트가 전혀 필요 없음.
CFG parallel 하나의 브랜치 결합 잠재 크기 교환 한 번 좋은 후보. 스텝당 한 번, 작은 페이로드, 자연스럽게 데드라인 허용. 지금까지 노드 간 측정은 없음.
K/V-gather CP 어텐션당 K/V all-gather 한 번 K/V의 (R−1)/R, 중첩되지 않은 단일 버스트 Ulysses와 ring 사이: K/V만 이동(쿼리는 전혀 안 함)하지만 버스트를 컴퓨트 뒤에 숨길 수 없음 — 노드 간에는 ring을 선호하고, 단일 내에선 작은 정도로 gather 사용.
Ring SP 이웃 전용 K/V 회전 K/V ÷ ring_degree, (R−1) 홉, 어텐션 타일과 중첩 그것을 위해 설계됨. 메커니즘은 이제 대부분 모델의 joint 어텐션을 다룸(Constraints 참고). 실제 노드 간 end-to-end 교차는 MiniMax H3(Ulysses 인트라노드 × ring 크로스, 시퀀스 길이에 따라 순이익 증가)에서 검증됨; 다른 모델의 ring 지원은 지금까지 동일 노드 검증됨.
Ulysses SP all-to-all 어텐션당 두 번, 모든 레이어에서 전체 q/k/v 활성화 인트라노드 유지. All-to-all은 전체 이분 대역폭이 필요; 노드 간에는 수신자 incast가 있는 R² 흐름이 됨.
Tensor parallel all-reduce 트랜스포머 블록당 hidden 크기 감소 (qwen급 DiT에서 ×60 블록) 최악. 최고 빈도, 중첩 없음, 이미 NVLink에서 샤딩 커널 시간의 ~70%.

두 가지 주의사항이 이 지도를 약속이 아닌 지도로 유지해요. 크로스-노드 실행(--nnodes/--node-rank/--dist-init-addr)은 병합됐고, 모델별 ring 지원은 이제 넓지만(위 Constraints 참고) — 이 두 사실은 함께 "어떤 모델, 어떤 노드 수"로 합산되지 않아요. 실제 노드 간 end-to-end로 실행된 유일한 구성은 H3 레시피예요. 다른 모델의 ring 지원은 지금까지 동일 노드 검증됨이므로, 그들과 노드 간 교차는 금지된 것이 아니라 미테스트예요. 그리고 data-parallel 행은 설계를 설명해요. 현재 구현은 각 복제본의 ingress를 로컬 호스트에 바인딩하므로, 호스트를 넘는 복제본은 --dp-size가 노드당 하나의 복제본을 배치할 수 있으려면 먼저 복제본별 호스트 주소 지정이 필요해요.

구성 선택 (Choosing a configuration)

규칙이 아닌 측정된 안내 — 올바른 조합은 모델의 통신 프로파일과 하드웨어 토폴로지에 달려 있고, 합법적이 lace 이익이 되는 것을 의미하지 않아요:

  • 다중 브랜치(true-CFG) 모델: CFG 병렬 처리 우선. 브랜치가 전체 DiT를 독립적으로 실행하고 스텝당 한 번 결합해 레이어별 통신을 완전히 피해요.
  • 2 GPU의 단일 브랜치 이미지 모델: 모델에 따라 Ulysses와 TP가 자리를 바꿔요. 통신이 많은 DiT는 Ulysses로 더 빨리 측정됐고, 더 작은 DiT는 TP로 더 빨랐어요. 둘 다 측정하고 승자를 모델 간에 복사하지 마세요.
  • 긴 비디오 / 패킹된 시퀀스: Ulysses를 헤드 나눗셈 한계까지, 그다음 나머지 인자에 ring — 시퀀스 길이가 Ulysses 단독으로는 불가능한 헤드 수를 넘어 확장돼요.
  • Ulysses의 헤드 나눗셈이 필요한 정도를 막을 때(H/T가 대상 U로 나누어 떨어지지 않음): 행 분할 슬롯이 이를 우회해요 — 오늘은 ring, 또는 --kv-gather-degree(행을 분할하므로 헤드 제약도 추가하지 않음).
  • TP를 2 랭크 이상으로 하는 것은 이미지-DiT 지연을 거의 개선하지 못해요. 블록별 all-reduce가 GEMM 절감보다 랭크 수로 더 빠르게 커지기 때문이에요.

데이터 병렬 처리 (Data parallelism)

--dp-size Nnum_gpus / N GPU마다 N개의 전체 엔진 복제본을 실행하며, 각 복제본은 자체 ingress를 가져요. 생성 요청은 복제본 간에 round-robin되고, 실시간 세션은 상태를 보유한 복제본에 고정되며, 제어 연산(가중치, LoRA, 메모리 점유, 종료)은 모든 복제본에 적용돼요. 복제본은 요청 경로에서 어떤 것도 교환하지 않아요. 단일(monolithic) 서빙 전용이며, ingress는 현재 로컬 호스트에 바인딩되어 있어 노드당 하나의 복제본은 먼저 복제본별 호스트 주소 지정이 필요해요.

더 알아보기