Distributing LLM inference in DwarfStar

Salvatore Sanfilippo

DwarfStar에서 LLM 추론 분산하기

고성능 NVIDIA 카드와 이를 구동하는 데 필요한 서버, 전력 비용은 매우 비쌉니다. 특히 초대형 모델을 돌릴 만큼의 VRAM을 확보하려 한다면 더욱 그렇죠. 지금까지 대안은 Apple 하드웨어나 DGX Spark 정도였습니다. DGX Spark는 메모리 대역폭 때문에 제약이 심하긴 해도 LLM의 프롬프트 처리(prefill) 정도는 충분히 빠르게 돌릴 수 있습니다. Mac Studio는 최대 512GB 통합 메모리를 제공했습니다. 메모리 대역폭은 평범한 수준이지만 Spark보다는 훨씬 낫고, 연산 성능도 현 상황을 감안하면 비교적 합리적인 가격에 제공되는 솔루션이었습니다.

예를 들어 DwarfStar에서 Mac Studio M3 Ultra 512GB 모델은 DeepSeek v4 PRO를 prefill 150t/s, 디코딩 약 10~13t/s로 구동할 수 있습니다. 훌륭한 속도는 아니지만 특정 용도에서는 충분히 쓸 만한 수준이죠. 2비트 양자화를 해도 DeepSeek v4 PRO는 성능 저하를 매우 잘 견뎌냅니다. 같은 양자화 수준의 Flash처럼요(오늘 PRO에게 C 컴파일러를 작성하게 해봤는데, 영상은 곧 공개하겠습니다). 약 1만 2천 달러 정도의 비용으로 프론티어 모델을 집에서 돌릴 수 있다는 건 결코 사소한 일이 아니라고 생각합니다.

앞으로 점점 더 나아지리라 기대할 수도 있겠지만, 전망은 그리 밝지 않아 보입니다. NVIDIA 구성의 가격이 내려갈 가능성은 거의 없고, 작은 회사조차 로컬 추론을 위해 소규모 데이터센터를 마련하고 운영하는 비용을 감당하기 어렵습니다. 동시에 RAM 공급 부족 때문에 M5 Ultra를 탑재한 Mac Studio, 예컨대 1.2T/s 메모리 대역폭과 더 강력한 연산을 갖춘 모델이 나오리라 기대하기도 어려운 상황입니다(M5 Max만 해도 이미 연산 성능은 더 빠르고, 각 GPU 코어 안에 특정 모델에 도움이 되는 Neural Accelerator가 들어 있습니다).

그래서 현재 로컬 추론 관점에서 가장 좋은 머신은 아마도 노트북일 겁니다. M5 Max 128GB 모델은 DeepSeek v4 Flash와 Mimo V2.5를 2비트 양자화로 꽤 괜찮은 prefill 및 디코딩 속도로 돌릴 수 있습니다. prefill 약 500t/s, 디코딩 약 35~40t/s 정도이며, 컨텍스트 길이가 늘어나도 성능 저하 폭이 매우 완만합니다. 구성에 따라 6천~7천 달러 정도의 비용으로, 현재로서는 가장 가성비가 좋은 선택 중 하나입니다.

이런 상황이라면 일반적인 로컬 추론 프로젝트나 특히 DwarfStart 입장에서는 분산 추론을 고민해 볼 만합니다. MacBook M5 Max가 두 대, 세 대, 네 대 있다면 무엇을 할 수 있을까요? 혹은 512GB RAM을 탑재한 M3 Ultra가 두 대 있다면요?

전통적으로 분산 추론을 하는 방식은 크게 두 가지가 있습니다. 하나는 메모리를 사실상 두 배로 쓰는 방식으로, 트랜스포머 레이어의 50%는 컴퓨터 A에, 나머지 50%는 컴퓨터 B에 나눠 올리고 추론을 순차적으로 실행하는 방법입니다. 이 경우 주고받아야 할 데이터는 활성화값(activations)뿐이라 개념적으로 매우 단순합니다. 약간의 마이크로배칭(micro-batching) 기법을 더하면 단순히 메모리를 두 배로 쓰는 것을 넘어 이론상으로는 프롬프트 처리 속도를 크게 높일 수도 있습니다(다만 디코딩은 그렇지 않습니다. 토큰 하나를 생성할 때마다 머신 A의 앞쪽 레이어, 이어서 머신 B의 나머지 레이어를 차례로 기다려야 하니까요. 그래도 발열이 줄어들어 지속적인 부하를 걸 수 있다는 장점은 있습니다). 결코 나쁘지 않은 방식이죠. 예를 들어 Mac Studio 512GB를 두 대 보유한 운 좋은 분이라면 DeepSeek v4 PRO의 풀 사이즈 모델을 돌릴 수 있습니다(물론 2비트 양자화 모델도 이미 매우 잘 동작하지만요). 마이크로배칭을 활용하면 prefill 속도까지 더 빨라지는 효과도 누릴 수 있습니다.

다른 접근법은 Apple RDMA를 이용해 두 머신에 걸쳐 실행을 병렬화하는, 이른바 수직 분할(vertical split) 방식입니다. 예를 들어 머신 A와 B에 동일한 2비트 양자화 모델을 각각 올려 두 머신 모두에 모든 라우티드 익스퍼트(routed experts)를 갖추도록 할 수 있습니다. 그런 다음 각 레이어마다 필요한 조율을 거쳐 익스퍼트의 절반은 머신 A에서, 나머지 절반은 머신 B에서 실행하는 식입니다(두 머신 모두 모든 익스퍼트를 가지고 있으므로 라우터가 어떤 결정을 내리든 연산의 50%를 다른 머신으로 넘길 수 있고, 이때 주고받는 활성화값은 매우 작습니다). 이 방식은 라우티드 익스퍼트 크기가 훨씬 큰 PRO 모델에서 더 현실적이어서 통신 오버헤드가 상대적으로 덜 민감합니다. 다만 이게 실제로 잘 동작할지는 아직 지켜봐야 할 문제입니다.

텐서 병렬화(tensor parallelism)도 있지 않냐고 생각하실 텐데, 맞습니다. 하지만 두 대의 Apple 컴퓨터나 DGX Spark 사이에서 확보할 수 있는 통신 속도로는 전혀 현실성이 없다고 봅니다(NVLink 속도를 한번 찾아보세요). 위에서 언급한 두 방식의 묘미는 주고받아야 할 데이터 양이 매우 적다는 데 있습니다.

자, 여기까지 읽으면 “이건 LLM을 병렬로 돌리는 데 대해 누구나 다 아는 뻔한 얘기 아니냐”고 생각하실 겁니다. 실제로 그렇습니다. 하지만 이 글은 바로 이 지점에 도달하기 위해 쓰였습니다. 두 대의 Mac이나 DGX를 완전히 다른 방식으로 병렬화할 수 있다면 어떨까요? 오픈 웨이트 모델은 지금 황금기를 맞고 있습니다. 선택지도 많고 성능도 매우 뛰어난 모델이 많죠. 128GB 환경의 2비트 양자화 모델만 해도 흥미로운 모델이 많습니다. Minimax M2.7, Mimo V2.5, DeepSeek v4 Flash 등 몇 가지를 꼽을 수 있죠. 한편 최근에는 LLM 앙상블(ensemble)(https://arxiv.org/abs/2502.18036)이 많이 연구되지 않은 가능성으로 주목받고 있습니다. 두 모델을 두 머신에서 완전히 공유 없이(shared-nothing) 각각 실행한 뒤, 마지막에 로짓(logits)을 결합하거나 더 나은 이어쓰기를 선택하는 방식입니다. 방법은 여러 가지가 있고, 두 모델의 어휘(vocabulary)가 달라도 동작합니다. 당혹도(perplexity)가 더 낮은 쪽의 이어쓰기를 고를 수도 있고(즉, 더 확신하는 모델을 고르는 것으로, 라우팅이 암시적으로 이루어지는 2-익스퍼트 MoE와 같습니다), 로짓을 결합해(물론 어휘가 달라서 복잡한 부분이 있습니다) 거기서 샘플링하는 것도 가능합니다. 더 최근 논문들은 두 기법을 섞는 것이 가장 좋은 접근이라고 제안합니다. 어쨌든 이런 기법들은 실제로 효과가 있는 것으로 보입니다. 모델들이 혼자일 때보다 더 나은 성능을 내는 것처럼 보이죠. 각자 다음에 할 말에 대해 서로 다른 관점을 보태면서 지식이 보완되는 느낌입니다.

아마도 이 방법이 앞의 두 가지 외에 시도해 볼 만한 가장 논리적인 세 번째 접근일지도 모르겠습니다. 앞으로 몇 달 안에 이 부분들을 더 실험해 볼 시간을 꼭 내고 싶습니다.

원문은 Salvatore Sanfilippo님이 에 게재했습니다.

이 글은 muse-spark-1.2-contributor 모델을 사용해 번역했습니다.