Unified Sequence Parallelism
TL;DR
이 논문은 무엇에 관한 것인가? 이 논문은 매우 긴 입력 시퀀스(책 전체를 읽거나 몇 시간의 비디오를 처리하는 것과 같은)를 가진 대형 AI 모델을 훈련시키는 데 있어서의 중요한 문제를 해결합니다. 저자들은 “Ulysses”와 “Ring Attention”이라는 두 가지 기존 기술을 결합한 USP(Unified Sequence Parallelism)를 만들어 최대 208,000 토큰 길이의 시퀀스(약 400페이지 분량의 텍스트)로 AI 모델을 훈련할 수 있게 했습니다.
주요 기여:
- 통합 방법론: 두 가지 경쟁하는 접근 방식(Ulysses vs Ring) 중 하나를 선택하는 대신, USP는 둘을 지능적으로 결합하여 각각의 장점을 모두 얻습니다
- Paper Link: https://arxiv.org/pdf/2405.07719
Related Papers
통합된 방법론의 기반:
- DeepSpeed Ulysses - USP에서 통합된 Ulysses 방법
- Blockwise RingAttention - USP에서 통합된 Ring 방법
- Ring Self-Attention - 시퀀스 병렬화의 체계적 분석
하이브리드 병렬화:
- LoongTrain - 2D 어텐션을 활용한 하이브리드 접근법
- Tensor Parallelism - 텐서 병렬화와의 결합
- GPipe - 파이프라인 병렬화와의 통합
긴 시퀀스 처리:
- DISTFLASHATTN - 분산 어텐션 계산
- Striped Attention - 효율적인 시퀀스 분배
- Context Parallelism for Scalable Million-Token Inference - 추론 시 컨텍스트 병렬화
시스템 최적화:
- Reducing Activation Recomputation in Large Transformer Models - 메모리 효율적인 훈련
- Efficiently Scaling Transformer Inference - 효율적 추론 시스템
- 하드웨어 적응성: 사용 가능한 네트워크 하드웨어(빠른 NVLink vs 느린 PCIe 연결)에 따라 자동으로 성능을 최적화합니다
- 실용적 가이드라인: 실제 시스템에서 언제, 어떻게 다른 병렬화 전략을 사용할지에 대한 명확한 규칙을 제공합니다
- 획기적인 결과: 208K 토큰 시퀀스 훈련에서 47% 계산 효율성 달성 - 새로운 최고 수준
왜 이것이 중요한가: 이 연구 이전에는 매우 긴 시퀀스로 AI 모델을 훈련하는 것이 메모리 제한으로 인해 불가능하거나 극도로 비효율적이었습니다. USP는 훨씬 더 긴 맥락을 이해할 수 있는 모델을 훈련하는 것을 실용적으로 만들어, 전체 문서 분석, 긴 대화, 확장된 비디오 시퀀스와 같은 애플리케이션을 가능하게 합니다.
Takeaways
핵심 문제: 긴 시퀀스가 왜 어려운가
메모리 벽 도전
동기: 현대 AI 애플리케이션은 점점 더 긴 시퀀스를 처리해야 합니다. Claude는 100K 토큰을 처리할 수 있고, GPT-4는 128K를, Gemini 1.5 Pro는 1천만 토큰을 주장합니다. 하지만 근본적인 문제가 있습니다: 트랜스포머의 어텐션 메커니즘은 이차 메모리 복잡도를 가집니다.
구체적인 예시:
- 1,000 토큰 시퀀스: 어텐션에 약 1M 메모리 단위 필요
- 10,000 토큰 시퀀스: 약 100M 메모리 단위 필요
- 100,000 토큰 시퀀스: 약 10B 메모리 단위 필요
이러한 이차 증가는 긴 시퀀스를 처리할 때 단일 GPU가 빠르게 메모리 부족 상태가 된다는 의미입니다.
전통적인 해결책과 그 한계들:
논문은 기존 해결책들이 치명적인 결함을 가지고 있다고 식별합니다:
-
데이터 병렬화 (DP): 장치 간 데이터를 분할하지만 큰 배치 크기가 필요
# 문제: 긴 시퀀스에 대해 충분한 배치 크기가 없음 if batch_size < num_devices: raise Error("데이터 병렬화를 효과적으로 사용할 수 없음")
-
텐서 병렬화 (TP): 모델 가중치를 분할하지만 어텐션 헤드 수에 의해 제한됨
# 문제: 제한된 확장성 max_tp_degree = num_attention_heads # 종종 32-64개만 if required_devices > max_tp_degree: raise Error("헤드 수를 넘어서 확장할 수 없음")
-
기존 시퀀스 병렬화: 주요 제한사항을 가진 두 가지 경쟁 접근법:
- DeepSpeed-Ulysses: 빠르지만 어텐션 헤드 수에 의해 제한됨
- Ring-Attention: 확장 가능하지만 계산적으로 비효율적
USP 해결책: 두 세계의 장점
핵심 통찰: 왜 둘 다 안 되나?
논문의 핵심 통찰은 Ulysses와 Ring 어텐션이 상호 배타적이지 않다는 것입니다 - 그들은 함께 작동할 수 있습니다. 이것은 빠른 자동차와 연료 효율적인 자동차 중 하나를 선택할 필요가 없다는 것을 깨닫는 것과 같습니다; 빠르면서 동시에 효율적인 하이브리드를 설계할 수 있습니다.
USP 방법 설명
1단계: 프로세스 그룹 조직
def setup_usp_groups(total_devices, ulysses_degree, ring_degree):
"""
장치들을 2D 메시로 조직:
- 행: Ulysses 그룹 (고대역폭 AllToAll)
- 열: Ring 그룹 (P2P 통신)
"""
assert total_devices == ulysses_degree * ring_degree
# 예시: 8개 장치 = 2×4 메시
# 장치 배치:
# [0, 1, 2, 3] <- Ring 그룹 0
# [4, 5, 6, 7] <- Ring 그룹 1
# | | | |
# Ulysses 그룹 (열)
for ring_id in range(ring_degree):
for ulysses_id in range(ulysses_degree):
device_id = ring_id * ulysses_degree + ulysses_id
assign_device(device_id, ulysses_group=ulysses_id, ring_group=ring_id)
2단계: 인과 어텐션을 위한 로드 밸런싱
def balance_causal_workload(sequence_tokens, num_devices):
"""
문제: 인과 어텐션에서 초기 토큰들은 더 적은 토큰에 어텐션함
- 토큰 0은 [0]에 어텐션 (1개 연산)
- 토큰 1은 [0,1]에 어텐션 (2개 연산)
- 토큰 15는 [0,1,2...15]에 어텐션 (16개 연산)
해결책: 각 장치가 동일한 작업을 갖도록 토큰을 재분배
"""
# 원래 할당 (불균형):
# 장치 0: 토큰 [0,1,2,3] → 1+2+3+4 = 10 연산
# 장치 3: 토큰 [12,13,14,15] → 13+14+15+16 = 58 연산
# 로드 밸런싱된 할당:
# 장치 0: 토큰 [0,1,14,15] → 1+2+15+16 = 34 연산
# 장치 3: 토큰 [6,7,8,9] → 7+8+9+10 = 34 연산
reordered_tokens = []
chunk_size = len(sequence_tokens) // (2 * num_devices)
for device in range(num_devices):
# 각 장치는 시작과 끝에서 하나씩 청크를 받음
start_chunk = sequence_tokens[device * chunk_size:(device + 1) * chunk_size]
end_chunk = sequence_tokens[-(device + 1) * chunk_size:-device * chunk_size]
reordered_tokens.extend(start_chunk + end_chunk)
return reordered_tokens
3단계: 통합 어텐션 알고리즘
def usp_attention(Q, K, V, ulysses_group, ring_group):
"""
두 접근법을 결합한 완전한 USP 어텐션 메커니즘
입력: 시퀀스 차원으로 분할된 Q,K,V 텐서
출력: 동일한 분할을 가진 어텐션 출력
"""
# 단계 1: Ulysses AllToAll (시퀀스 → 헤드)
print(f"Ulysses 이전: Q 형태 = {Q.shape}") # [batch, seq/N, heads, dim]
Q_heads = all_to_all_4d(Q, scatter_seq=True, gather_heads=True, group=ulysses_group)
K_heads = all_to_all_4d(K, scatter_seq=True, gather_heads=True, group=ulysses_group)
V_heads = all_to_all_4d(V, scatter_seq=True, gather_heads=True, group=ulysses_group)
print(f"Ulysses 이후: Q 형태 = {Q_heads.shape}") # [batch, seq, heads/M, dim]
# 단계 2: P2P 통신을 가진 Ring 어텐션
O_ring = ring_attention_with_p2p(Q_heads, K_heads, V_heads, ring_group)
# 단계 3: 역 Ulysses AllToAll (헤드 → 시퀀스)
O_final = all_to_all_4d(O_ring, scatter_heads=True, gather_seq=True, group=ulysses_group)
print(f"최종 출력: O 형태 = {O_final.shape}") # [batch, seq/N, heads, dim]
return O_final
def ring_attention_with_p2p(Q, K, V, ring_group):
"""P2P를 통해 장치 간에 K,V 블록을 전달하는 Ring 어텐션"""
output = torch.zeros_like(Q)
# 각 장치는 자신의 K,V 블록으로 시작
my_K, my_V = K.clone(), V.clone()
for step in range(ring_group.size()):
# 현재 K,V 블록으로 어텐션 계산
attention_scores = torch.matmul(Q, my_K.transpose(-2, -1))
attention_weights = F.softmax(attention_scores, dim=-1)
partial_output = torch.matmul(attention_weights, my_V)
# 결과 누적
output += partial_output
# 링의 다음 장치로 K,V 전달 (마지막 단계 제외)
if step < ring_group.size() - 1:
next_device = (ring_group.rank() + 1) % ring_group.size()
prev_device = (ring_group.rank() - 1) % ring_group.size()
# 동시 송수신
ring_group.send(my_K, dst=next_device)
ring_group.send(my_V, dst=next_device)
my_K = ring_group.recv(src=prev_device)
my_V = ring_group.recv(src=prev_device)
return output
구체적인 예시: 4개 장치, 64 토큰, 16 헤드로 USP를 추적해보겠습니다:
# 초기 상태: 각 장치가 16 토큰, 모든 16 헤드를 가짐
장치_0: Q[batch, 16, 16, 64] # 토큰 0-15
장치_1: Q[batch, 16, 16, 64] # 토큰 16-31
장치_2: Q[batch, 16, 16, 64] # 토큰 32-47
장치_3: Q[batch, 16, 16, 64] # 토큰 48-63
# Ulysses AllToAll 이후 (ulysses_degree=2): 시퀀스 분산, 헤드 분할
장치_0: Q[batch, 32, 8, 64] # 토큰 0-31, 헤드 0-7
장치_1: Q[batch, 32, 8, 64] # 토큰 0-31, 헤드 8-15
장치_2: Q[batch, 32, 8, 64] # 토큰 32-63, 헤드 0-7
장치_3: Q[batch, 32, 8, 64] # 토큰 32-63, 헤드 8-15
# Ring 어텐션 (ring_degree=2): 각 쌍 내에서 P2P 통신
# 장치 0&2가 헤드 0-7에 대한 링 형성
# 장치 1&3이 헤드 8-15에 대한 링 형성
# 역 Ulysses 이후: 시퀀스 분할로 복귀
장치_0: O[batch, 16, 16, 64] # 토큰 0-15에 대한 최종 출력
장치_1: O[batch, 16, 16, 64] # 토큰 16-31에 대한 최종 출력
장치_2: O[batch, 16, 16, 64] # 토큰 32-47에 대한 최종 출력
장치_3: O[batch, 16, 16, 64] # 토큰 48-63에 대한 최종 출력
중요한 가정과 성공 조건
논문은 USP가 효과적으로 작동하기 위해 충족되어야 하는 몇 가지 중요한 가정을 드러냅니다:
수학적 요구사항:
def validate_usp_configuration(seq_len, num_heads, ulysses_degree, ring_degree):
"""만족되어야 하는 중요한 조건들"""
# 조건 1: 헤드 분할 가능성
assert num_heads % ulysses_degree == 0, \
f"헤드 {num_heads}는 Ulysses 차수 {ulysses_degree}로 균등분할되어야 함"
# 조건 2: 시퀀스 분할 가능성
total_sp_degree = ulysses_degree * ring_degree
assert seq_len % total_sp_degree == 0, \
f"시퀀스 길이 {seq_len}는 총 SP 차수 {total_sp_degree}로 분할되어야 함"
# 조건 3: 장치당 메모리 제약
memory_per_device = estimate_memory(seq_len // ring_degree, num_heads // ulysses_degree)
assert memory_per_device < available_gpu_memory, "GPU 메모리 부족"
# 조건 4: 통신 대역폭 요구사항
ulysses_bandwidth_needed = estimate_alltoall_bandwidth(ulysses_degree)
ring_bandwidth_needed = estimate_p2p_bandwidth(ring_degree)
return True
하드웨어 토폴로지 요구사항:
- Ulysses를 위한 높은 대역폭: AllToAll 연산은 NVLink 수준의 연결(400GB/s+)이 필요
- Ring을 위한 낮은 대역폭도 가능: P2P는 PCIe나 이더넷 연결에서도 작동 가능
- 네트워크 토폴로지 인식: USP는 Ulysses 그룹이 고대역폭 도메인에 매핑될 때 최고 성능을 발휘
내 분석: 논문의 강점은 이러한 가정들을 명시적으로 만드는 것입니다. 이전 연구들은 종종 이상적인 네트워크 조건을 가정했지만, USP는 실제 하드웨어 제한을 인정하고 그에 따라 적응합니다.
실험 결과: 숫자들이 실제로 의미하는 것
주요 성능 결과
구성 | 하드웨어 | 시퀀스 길이 | MFU | 내 해석 |
---|---|---|---|---|
LLAMA3-8B | 2×8xA800 | 208K 토큰 | 47% | 획기적: 극한 시퀀스 길이에서 생산 수준 효율성을 달성한 첫 번째 사례 |
LLAMA3-8B | 2×8xA800 | 120K 토큰 | 49% | 최적점: 메모리와 계산의 최적 균형 |
LLAMA2-7B | 1×8xA800 | 64K 토큰 | 50% | 확장성 검증: 단일 노드 성능이 기준선 확립 |
이러한 결과에 대한 내 생각:
- 208K에서 47% MFU는 놀랍다 - 대부분의 시스템이 이런 규모에서 >30% 효율성을 유지하는 데 어려움을 겪음
- 49%에서 47%로의 약간의 효율성 감소는 USP가 알고리즘적 병목보다는 하드웨어 한계에 접근하고 있음을 시사
- 일관된 47-50% 범위는 USP가 안정적인 성능 특성을 가지고 있음을 나타냄
절제 연구: USP vs 개별 방법들
하드웨어 유형 | 시퀀스 | SP-Ulysses | SP-Ring | USP-통합 | 승자 | 왜? |
---|---|---|---|---|---|---|
8xL20 PCIe | 32K | 28.6 iter/s | 62.8 iter/s | 62.8 iter/s | Ring/USP | 낮은 대역폭이 P2P를 선호 |
8xL20 PCIe | 128K | 3.2 iter/s | 5.5 iter/s | 5.5 iter/s | Ring/USP | +71% 개선 |
8xA100 NVLink | 32K | 136.4 iter/s | 133.0 iter/s | 136.4 iter/s | Ulysses/USP | 높은 대역폭이 AllToAll 가능하게 함 |
8xA100 NVLink | 128K | 2.8 iter/s | 2.9 iter/s | 2.8 iter/s | Ulysses/USP | 미미한 차이 |
내 분석의 핵심 통찰:
- 하드웨어-알고리즘 매칭: 최고의 접근법은 전적으로 네트워크 토폴로지에 달려있음 - 범용 승자는 없음
- PCIe 시스템은 Ring을 강하게 선호: 71% 개선은 P2P 통신이 낮은 대역폭에 훨씬 더 적합함을 보여줌
- NVLink 시스템은 Ulysses를 약간 선호: AllToAll 연산이 높은 대역폭에서 빛나지만, 장점이 예상보다 작음
- USP의 가치: 항상 최고의 개별 방법과 일치하여, 수동 알고리즘 선택의 필요성을 제거
로드 밸런싱 영향 분석
방법 | 시퀀스 길이 | 기준선 | 로드 밸런싱 | 개선 | 내 분석 |
---|---|---|---|---|---|
Ring 어텐션 | 32K | 28.6 iter/s | 32.8 iter/s | +14.8% | 중간 길이에서 적당한 이득 |
Ring 어텐션 | 128K | 3.2 iter/s | 4.2 iter/s | +31.6% | 긴 시퀀스에서 엄청난 이득 |
왜 이것이 중요한가 (내 해석):
- 개선이 시퀀스 길이와 함께 증가 - 이는 로드 밸런싱이 USP가 목표로 하는 가장 긴 시퀀스에서 중요해진다는 것을 시사
- 31.6% 개선은 엄청나다 - 이 단일 최적화가 많은 알고리즘적 발전보다 더 많은 속도 향상을 제공
- 핵심 기여를 검증 - 로드 밸런싱은 단순히 좋은 기능이 아니라 USP 성공에 필수적
메모리 vs 통신 트레이드오프
방법 | 통신 볼륨 | 메모리 효율성 | 최적 사용 사례 | 내 평가 |
---|---|---|---|---|
데이터 병렬 | 높음 (AllReduce 그래디언트) | 우수 (A/N) | 짧은 시퀀스, 큰 배치 | 적용 가능할 때 여전히 황금 표준 |
SP-Ulysses | 매우 높음 (8×AllToAll) | 좋음 (A/N) | 높은 대역폭, 헤드가 많은 모델 | 통신 병목이 확장을 제한 |
SP-Ring | 중간 (4×P2P) | 좋음 (A/N) | 낮은 대역폭, 메모리 제약 | 대부분의 시나리오에서 예상보다 좋음 |
USP-통합 | 적응형 | 좋음 (A/N) | 모든 하드웨어 토폴로지 | 최고의 범용 솔루션 |
TP-sp | 높음 (10×AllGather) | 최고 (αA, α<1) | 메모리 중요 시나리오 | 극한 메모리 제약에서 여전히 필요 |
내 전략적 분석:
- USP가 모든 것을 대체하지는 않음 - TP-sp는 여전히 극한 규모에서 중요한 메모리 장점을 가짐
- 통신 적응성이 USP의 킬러 기능 - 다른 방법은 하드웨어에 맞게 자동 최적화하지 않음
- 메모리 효율성은 “충분히 좋다” - USP는 주요 요구사항인 중요한 A/N 확장을 달성
수렴 검증: 숨겨진 영웅
방법 | 훈련 손실 | 수렴 속도 | 수치적 안정성 |
---|---|---|---|
데이터 병렬 | 2.45 (기준선) | 정상 | 안정적 |
USP | 2.45 (동일) | 동일 | 안정적 |
이 결과가 중요한 이유 (내 관점):
- 완벽한 수렴 매칭은 USP가 훈련 아티팩트를 도입하지 않음을 증명
- 동일한 곡선은 로드 밸런싱과 시퀀스 재정렬이 학습에 영향을 주지 않음을 검증
- 이 결과는 실용적 채택을 가능하게 함 - 수렴 검증 없이는 누구도 프로덕션에서 USP를 신뢰하지 않을 것
내 전체 평가: 이 논문이 실제로 달성한 것
전략적 돌파구
이 논문은 단순히 또 다른 최적화를 제안하는 것이 아니라 근본적인 시스템 문제를 해결합니다. 이 분야는 두 가지 경쟁하는 접근법(Ulysses vs Ring)을 가지고 있었고, 자연스러운 경향은 편을 선택하는 것이었습니다. 저자들의 이들을 결합하는 통찰은 연구자들이 데이터와 모델 병렬성 중 하나를 선택하는 대신 결합할 수 있다는 것을 깨달았던 획기적인 순간과 유사합니다.
실제 영향
USP 이전: 긴 맥락 모델 훈련은 각 하드웨어 설정에 대해 올바른 병렬화 전략을 선택하는 전문 지식이 필요했습니다. 팀들은 구성을 튜닝하는 데 몇 주를 보냈습니다.
USP 이후: 자동으로 적응하는 하나의 통합 접근법. 이는 분산 시스템 전문 지식이 없는 팀들을 위해 긴 맥락 훈련을 민주화합니다.
기술적 우아함
로드 밸런싱 솔루션은 특히 우아합니다 - 인과 어텐션 작업 부하를 완벽하게 균형 맞추는 간단한 재정렬입니다. 이는 기본 수학적 구조에 대한 깊은 이해를 보여줍니다.
한계와 미래 연구
- 여전히 고급 하드웨어 필요 - USP는 값비싼 GPU 클러스터의 필요성을 제거하지 않음
- 통신 오버헤드 여전히 존재 - 짧은 시퀀스에 대해 데이터 병렬화보다 여전히 높음
- 메모리 효율성 격차 - TP-sp는 메모리 중요 시나리오에서 장점을 유지
더 넓은 의미
이 연구는 시퀀스 병렬화가 실험적 기술에서 프로덕션 준비 기술로 성숙했음을 나타냅니다. 208K 토큰에서 47% MFU는 단순한 벤치마크가 아니라 긴 맥락 AI가 이제 규모에서 실용적이라는 증명입니다.
내 예측: USP는 혼합 정밀도 훈련이 보편적으로 채택된 것처럼 긴 맥락 훈련의 표준 접근법이 될 것입니다. 자동 하드웨어 적응이 채택의 주요 장벽을 제거합니다.
Leave a comment