Nižší latence a vyšší propustnost s víceuuzlovým nasazením DeepSeek

Více-GPU nasazení současně zvyšuje výkon MoE modelu v oblasti rychlosti i škálování

AutořiPerplexity Research

Většina systémů se potýká s tím, že latence a propustnost jsou často protichůdné cíle, které vyžadují kompromisy při návrhu a nasazení. Například u hustých velkých jazykových modelů může zvětšení velikosti dávky zvýšit propustnost, ale také prodloužit latenci; zvětšení tenzorového paralelismu v rámci jednoho stroje může zkrátit latenci, ale snižuje počet replik, což vede k nižší propustnosti.

Modely typu Mixture of Experts (MoE), jako je DeepSeek-V3/R1, nedávno prokázaly vynikající schopnosti modelu a operační efektivitu. Například model DeepSeek-V3/R1 má celkem 671B parametrů, ale každý token využívá během inference pouze 37B parametrů. Tato architektura modelu přináší pro inferenční systémy jak výzvy, tak příležitosti.

Tento článek ukazuje, že na rozdíl od konvenčních systémů mohou modely MoE, jako je DeepSeek-V3/R1, ve většině případů současně dosáhnout vyšší propustnosti a nižší latence při využití více GPU ve víceuuzlových nasazeních.

Architektury nasazení

Jednonodové nasazení přes NVLink se zobrazením attention a expertní výpočty rozloženými mezi GPU.
Vícenodové nasazení přes InfiniBand, s skupinami GPU propojenými v rámci uzlů i napříč uzly.

Vzhledem k velkému počtu malých expertů, které model obsahuje, musí být nasazení rozprostřeno napříč více zařízeními. Zvažovali jsme jak jednouzlová nasazení na jednom uzlu s 8xH200 GPU, tak víceuuzlová nasazení na 8xH100 GPU.

Obě architektury nasazení využívají datový paralelismus, který je řízen prostřednictvím našeho vlastního plánovače požadavků. Implementace datového paralelismu zahrnuje spuštění několika instancí inferenčního enginu, z nichž každá pracuje nezávisle na obsluze a udržování požadavků. Plánovač požadavků, který s enginem komunikuje přes GRPC, zodpovídá za co nejrovnoměrnější distribuci požadavků a zároveň usnadňuje opětovné použití KV cache, přičemž požadavky s částečně odpovídající předponou odesílá na servery obsahující mezipaměť. Instance enginu nezahrnují více uzlů. Volitelně mohou využívat tenzorový paralelismus k rozdělení pozornosti (attention) na více zařízení. Instance jsou vzájemně propojeny přes NVLink v případě jednoho uzlu nebo přes InfiniBand ve víceuuzlovém případě, přičemž odesílají a shromažďují experty.

Jednouzlová konfigurace nasazení poskytuje vynikající latenci při malých velikostech dávek; výkon však za podmínek zvýšené zátěže rychle klesá.

Pro nasazení obslužného enginu spouštíme jeden pod na uzel, který hostuje více instancí enginu. Knihovna PyTorch zodpovídá za nastavení distribuované komunikace a sjednání inicializace NVSHMEM. Pro komunikaci spoléháme na vlastní jádra CUDA popsaná v dřívějším příspěvku na blogu. Implementace obou nasazení je prakticky totožná, přičemž model vybírá správná jádra k použití na základě struktury implementující paralelismus expertů.

Techniky paralelizace

Než se ponoříme do našeho srovnání výkonu, je nezbytné pochopit klíčové paralelizační strategie, díky nimž je nasazení masivních modelů MoE, jako je DeepSeek-V3/R1, možné.

Tenzorový paralelismus

Při inferenci LLM se tenzorový paralelismus (TP) obvykle používá ke snížení využití paměti a výpočtů na GPU, čímž se snižuje latence. Obvykle můžeme rozdělit Linear projekce v Attention a MLP vrstvách podél řádkových nebo sloupcových dimenzí a rozdělit operace Attention podél dimenze hlavy pozornosti.

S TP nemá architektura Llama-3 žádné duplicitní výpočty pro Linear projekci a operace Attention napříč GPU, což je ideální metoda shardingování. V modelech DeepSeek-V3/R1 toho však TP nemůže dosáhnout.

Modely DeepSeek-V3/R1 používají Multi-Latent Attention (MLA). Vrstva MLA nejprve použije Linear projekci kv_a_proj k výpočtu latentního vektoru a poté použije jinou Linear projekci kv_b_proj k jeho transformaci do prostoru každé hlavy pozornosti. Protože všechny hlavy pozornosti sdílejí stejný latentní vektor, TP nemůže latentní vektor rozdělit, takže všechny TP ranky musí replikovat parametry a výpočty kv_a_proj a kv_b_proj. Podobně, protože MLA ukládá latentní vektor do KV cache, každý TP rank ukládá identickou kopii KV cache.

Navzdory určité duplicitě v MLA poskytuje tenzorový paralelismus stále částečné snížení výpočetních nároků, což jej činí cenným pro scenáře vyžadující vysokou rychlost výstupu.

Paralelismus expertů

Modely DeepSeek-V3/R1 nahrazují MLP vrstvy vrstvami MoE. Vrstva MoE má 256 směřovaných expertů a jednoho sdíleného experta. Každý token je odeslán k 8 různým směřovaným expertům pro výpočet a výsledky jsou váženě sečteny. Každý token se rovněž počítá ve sdíleném expertovi a výsledek je přičten k výsledku od směřovaných expertů.

Paralelismus expertů (EP) slouží jako typický přístup k shardingování pro vrstvy MoE, přičemž každé GPU spravuje 256 / EP směřovaných expertů a zároveň udržuje kopii sdíleného experta. Ve srovnání s TP je výhodou EP to, že může distribuovat výpočty napříč více GPU, čímž snižuje výpočetní nároky a využití paměti na jedno GPU.

Před provedením výpočtů expertů musí všechna GPU provést komunikaci AllToAll za účelem odeslání tokenů na GPU, kde se nacházejí odpovídající experti; po výpočtu expertů je nutná další komunikace AllToAll k shromáždění výsledků výpočtů z různých GPU a provedení váženého součtu. Pomocí NVSHMEM jsme implementovali optimalizovanou verzi těchto dvou komunikačních jader AllToAll, Dispatch a Combine. V našem předchozím příspěvku na blogu jsme podrobně popsali implementaci a naše jádra byla open-sourcována na GitHubu.

Datový paralelismus

S EP můžeme distribuovat výpočty MoE napříč 128 nebo ještě více GPU. Výpočty MLA však nelze pomocí EP rozdělit. V tomto bodě můžeme zavést datový paralelismus (DP). Každá skupina DP má kompletní kopii vrstvy MLA. Každá skupina DP přijímá různé vstupy a provádí výpočty vrstvy MLA nezávisle.

DP a TP vrstvy MLA lze kombinovat, přičemž jedna skupina DP je rozdělena na několik TP ranků. EP vrstvy MoE lze kombinovat s DP/TP vrstvy MLA. EP = DP * TP. Například na 16 strojích znamená EP128 DP32 TP4 distribuci směřovaných expertů napříč 128 GPU, přičemž každé 4 GPU tvoří skupinu DP, celkem tedy 32 nezávislých skupin DP.

Jednouzlové vs. víceuuzlové

671 miliard parametrů modelu DeepSeek překračuje kapacitu paměti jednoho 8-GPU stroje H100 (80 GB * 8), ale jeden 8-GPU stroj H200 dokáže plně pojmout celý model (141 GB * 8). Při použití konfigurace EP8 DP8 TP1 využívá model přibližně 100 GB paměti na GPU, přičemž přibližně 40 GB zbývá pro KV cache a další meziprodukty. Jeden token zabírá 70 272 bajtů KV cache. Za předpokladu, že každý požadavek má 5 000 tokenů, každé GPU pojme přibližně 100 požadavků.

Chtěli jsme porozumět rozdílům ve výkonu mezi jednouzlovým a víceuuzlovým nasazením v různých konfiguracích. Pro jednouzlové nasazení jsme použili jeden stroj H200 a pro víceuuzlová nasazení až 16 strojů H100. Pro každé prostředí nasazení jsme použili kombinace TP 1, 2, 4, 8 a velikostí dávek na GPU 1, 2, 4, 8, 16, 32, 64, 128. Předpokládali jsme, že každý požadavek má délku KV cache 5 000 tokenů. Rovněž jsme předpokládali, že Multi-Token Prediction (MTP) předpovídá 1 další token (tzn. délka dotazu každého požadavku je 2), a konzervativně jsme předpokládali míru přijetí 60 %. Níže uvedený obrázek znázorňuje propustnost a výstupní rychlost pro různé konfigurace.

Paretofronty latence a propustnosti pro různé konfigurace expert-parallel.

Vodorovná osa představuje výstupní rychlost na požadavek v tokenech/s. Svislá osa používá logaritmickou stupnici k zobrazení propustnosti na stroj v tokenech/s. Paretovu hranici pro každou konfiguraci EP jsme označili čarami různých barev.

V případech s extrémně vysokými požadavky na výstupní rychlost může použití jednouzlového EP8 DP1 TP8 s velikostí dávky 1 dosáhnout výstupní rychlosti přesahující 100 tokenů/s, ale propustnost je extrémně nízká, což odpovídá výstupní rychlosti. V tomto scénáři má celá dávka pouze 2 tokeny, které lze odeslat na nejvíce 2*8=16 expertů, čímž se aktivuje celkem maximálně 57B parametrů.

V rozsahu výstupní rychlosti 40–80 tokenů/s platí, že s rostoucí propustností výstupní rychlost výrazně klesá. Naproti tomu EP128 dosahuje při stejné výstupní rychlosti přibližně 5krát vyšší propustnosti než jednouzlové nasazení.

Tento jev lze vysvětlit zkoumáním chování jednouzlového nasazení: zvětšení velikosti dávky přímo souvisí s nárůstem aktivovaných expertů. Když je velikost dávky 1, průměrný počet aktivovaných expertů na GPU je 2 * 8 / 8 = 2. Když je dávka dostatečně velká, jsou aktivováni všichni experti, což znamená, že každé GPU aktivuje 256 / 8 = 32 expertů. Aktivace většího počtu expertů znamená, že GPU musí číst z paměti více parametrů, což významně zvyšuje tlak na paměťovou propustnost. Vzhledem k tomu, že fáze dekódování u velkých jazykových modelů je již omezena paměťovou propustností, a nikoli výpočetním výkonem, zvětšení velikosti dávky v jednouzlovém nasazení výrazně snižuje výstupní rychlost.

Srovnání čtyř konfigurací víceuuzlového nasazení (EP16, EP32, EP64 a EP128) ukazuje, že vyšší hodnoty EP posouvají Paretovu hranici směrem k současnému zlepšení propustnosti a výstupní rychlosti.

Použití vyššího čísla EP znamená, že každému GPU je přiděleno méně expertů. Například EP128 znamená, že každé GPU zodpovídá za 256 / 128 = 2 experty, takže tlak na paměťovou propustnost je výrazně snížen. Jinými slovy, použitím většího čísla EP efektivně získáme větší paměťovou propustnost. Pokud je velikost dávky na GPU menší než 64, zvětšení velikosti dávky výrazně neovlivní rychlost výpočtu expertů, protože zvětšení počtu vstupů výrazně nezvyšuje tlak na paměťovou propustnost. Pozorujeme tedy, že při použití EP128 nezvětšení velikosti dávky neovlivňuje výstupní rychlost tak výrazně.

Je zajímavé, že při větších velikostech dávek (64 požadavků na GPU) jsme pozorovali nový jev: propustnost jednouzlového nasazení je o něco vyšší než u víceuuzlového nasazení. Částečně je to způsobeno tím, že vnitrouzlový NVLink má vyšší propustnost než mezuuzlový InfiniBand. Částečně je to také kvůli omezením v naší implementaci. Tento jev rozebereme podrobněji později.

Vzhledem k omezením kapacity paměti nemůže konfigurace EP8 DP8 TP1 dosáhnout velikosti dávky 128 na GPU, takže víceuuzlové nasazení zůstává lepší volbou ve scénářích usilujících o vyšší propustnost.

Překrývání výpočtů a komunikace

Jak bylo stručně uvedeno výše ohledně paralelismu expertů, GPU jsou během komunikace vrstvy MoE nečinná. Abychom omezili plýtvání a snížili latenci, musíme najít výpočetní úlohy nezávislé na datech, kterými tuto dobu nečinnosti vyplníme.

Plány výpočtu a komunikace bez překryvu, s překryvem dispatch a s pětistupňovým potrubím.

Horní část výše uvedeného obrázku znázorňuje výpočetní tok jedné vrstvy. Výpočet MoE závisí na operaci Dispatch a výpočet další vrstvy závisí na výsledku operace Combine.

Umístíme sdíleného experta na každé GPU. Tímto způsobem výpočet sdíleného experta nevyžaduje komunikaci AllToAll. Proto můžeme provést výpočet sdíleného experta ihned po odeslání Dispatch (Dispatch Send) a poté počkat na dokončení příjmu Dispatch (Dispatch Recv). Toto schéma překrývání nazýváme „Dispatch Overlap“.

Dispatch Overlap nabízí přímočarou implementaci a širokou použitelnost. Tato technika skrývá dobu výpočtu sdíleného experta napříč všemi velikostech EP a dávek.

Abychom dále zvýšili překrývání výpočtů a komunikace, použili jsme mikrodávkování zmíněné v technické zprávě DeepSeek k prolomení datové závislosti. Jak je znázorněno v dolní části obrázku, rozdělili jsme výpočet jedné vrstvy Transformer do 5 fází:

Fáze 1: InputNorm, QKVProj, AppendKV, BMM

Fáze 2: BMM, Attn, OProj, PostNorm, Gate

Fáze 3: Dispatch Send, sdílený expert

Fáze 4: Dispatch Recv, MoE, Combine Send

Fáze 5: Combine Recv

V prvních 3 hustých vrstvách Transformer používáme celou dávku. V následujících 58 vrstvách MoE Transformer rozdělíme dávku rovnoměrně na dvě mikrodávky. Obě mikrodávky se provádějí střídavě s posunem o 3 fáze. Jelikož mezi těmito dvěma mikrodávkami neexistuje žádná datová závislost, můžeme po operaci Dispatch Send a po operaci Combine Send přepnout na výpočet jiné mikrodávky.

Rozpad latence

Dále porovnáme vliv překrývání prostřednictvím experimentu a také porovnáme rozdíly ve výkonu mezi jednouzlovým nasazením EP8 a víceuuzlovým nasazením EP128. Pro usnadnění srovnání jsme pro následující experiment použili GPU H100. Použili jsme TP1, velikost dávky 128 na GPU, délku dotazu 2 na požadavek a délku KV cache 5 000.

Latence vrstev podle kernelu pro porovnávané konfigurace expert-parallel a překryvu.

Obrázek výše ukazuje celkový čas strávený na jedné vrstvě MoE Transformer a podíl latence různých typů jader. S výjimkou Dispatch, Combine a GroupGEMM by doba provádění ostatních jader měla být v sériích EP8, EP128 NoOverlap a EP128 DispatchOverlap stejná, protože velikost dávky je stejná.

Překrývání

Porovnejme nejprve účinky tří metod překrývání. NoOverlap trval celkem 2667 µs, DispatchOverlap trval 2651 µs, což představuje úsporu 16 µs neboli pouhých 0,6 %. MicroBatch ukázal velmi významné zlepšení, trval 1896 µs, což je zrychlení o 29 %. Čas pro Dispatch i Combine se výrazně zkrátil. Dispatch klesl z 593 µs na 367 µs a Combine z 1012 µs na 237 µs.

Všimněte si, že u výpočetních jader rozdělení dávky o velikosti 128 na dvě dávky o velikosti 64 zvyšuje celkovou dobu provádění. Ačkoli se tedy čas strávený komunikací zkrátil o 1001 µs, celkový čas se zkrátil pouze o 771 µs. Důvod vysvětlíme pomocí modelu Roofline v následující části.

Z tohoto důvodu mikrodávkování nezlepšuje výkon vždy.

Změny výstupní rychlosti a propustnosti na uzel s micro-batchingem, vykreslené vůči velikosti batch na GPU.

Obrázek výše ukazuje zvýšení výkonu Microbatch ve srovnání s DispatchOverlap pro velikosti dávek 4–128. Pokud je velikost dávky menší než 32, Microbatch snižuje výkon o 5 %–40 %. Pokud je velikost dávky větší nebo rovna 32, Microbatch může zlepšit výkon o 10 %–35 %.

EP8 vs. EP128

Vraťme se k předchozímu obrázku a porovnejme EP8 a EP128 Microbatch. EP8 trval celkem 1802 µs, což je o něco méně než 1896 µs u EP128. Kromě výše uvedeného prodloužení doby provádění jader způsobeného Microbatch jsou hlavní rozdíly v GroupGEMM používaném pro výpočet MoE a ve dvou komunikačních jádrech, Dispatch a Combine.

GroupGEMM u EP8 trvalo 555 µs, zatímco GroupGEMM u EP128 trvalo 270 µs, což představuje poloviční snížení. To je hlavní výhoda víceuuzlového nasazení.

Bohužel čas strávený komunikací se zvýšil o 213 µs, což do značné míry vyrovnalo výhodu GroupGEMM. V samostatných testech výkonu našich komunikačních jader jsme zjistili, že mohou dosáhnout pouze poloviny šířky pásma Infiniband. V optimalizaci našich komunikačních jader budeme pokračovat.

Dalším jádrem, které výrazně zaostává, je GEMM. Microbatch zvýšil GEMM o 95 µs. GEMM rozebereme podrobněji v níže uvedené části Roofline. Domníváme se, že současná implementace GEMM ještě nedosáhla optimálního výkonu.

Roofline

Model Roofline je dobrým nástrojem pro analýzu výkonu jader. Jeho vodorovná osa představuje aritmetickou intenzitu, což je poměr operací s plovoucí řádovou čárkou (FLOP) k bajtům vstupně-výstupních operací paměti. Hodnotu vodorovné osy lze vypočítat přímo sémantiky jádra. Svislá osa představuje dosažený výkon, vypočítaný vydělením FLOP latencí benchmarku.

Teoretická horní hranice výkonu jádra je přímo určena specifikacemi GPU. Špičkový výkon FP8 H100 je 1979 TFLOP/s, což je v modelu Roofline znázorněno jako vodorovná čára. Šířka pásma paměti H100 je 3,35 TB/s, což je znázorněno jako sklon čáry procházející počátkem. Obě čáry poskytují limity výkonu pro jádra omezená výpočetním výkonem (compute-bound) a pamětí (memory-bound).

Níže diskutujeme výkon jader GroupGEMM a GEMM.

GroupGEMM

Jádro GroupGEMM v MoE provádí následující výpočet: Existuje celkem g skupin, i-tá skupina má m_i tokenů a provádí násobení matic [m_i, k] x [k, n] -> [m_i, n]. Při testování výkonu předpokládáme, že počet tokenů v každé skupině je stejný, označený jako m_i = m. Potom je počet FLOP pro GroupGEMM 2 * g * m * k * n a bajty vstupně-výstupních operací paměti jsou g * (m * k + n * k + m * n).

V modelu DeepSeek-V3/R1 je 256 expertů a každý token je odeslán k 8 expertům pro výpočet. Za předpokladu velikosti dávky 128, délky dotazu 2 a použití konfigurace EP128 DP128 je průměrný počet tokenů přijatých každým expertem (tj. m) 128 * 2 * 8 * 128 / 256 = 1024. Podobně můžeme vypočítat m pro ostatní konfigurace a velikosti dávek.

Pro testování výkonu jsme použili implementaci GroupGEMM od DeepGEMM. Testovací body pokrývaly kombinace konfigurací EP8, EP16, EP32, EP64, EP128 s TP1 a velikostmi dávek 1–128.

Výkon GroupGEMM vzhledem k výpočetním roofline a roofline propustnosti paměti.

Obrázek výše ukazuje model Roofline pro GroupGEMM za různých konfigurací EP. Různá EP odpovídají různému počtu skupin. Obrázek znázorňuje téměř se překrývající výkonnostní křivky, což naznačuje, že výkon GroupGEMM je primárně dán celkovým počtem tokenů (označeným jako g * m).

Hvězdičky označují datové body odpovídající velikosti dávky 128 na GPU pro každou konfiguraci EP. Porovnáním těchto označených datových bodů vidíme, že s rostoucím EP (a současně rostoucím DP) se zvyšuje také počet tokenů na experta m. Při EP8 je m=128, zatímco při EP128 je m=2048.

S rostoucím m se zvyšuje také aritmetická intenzita. Ve většině konfigurací je GroupGEMM omezen paměťovou propustností, takže zvětšení m zlepšuje výkon.

GEMM

Jádro GEMM odpovídá Linear projekcím v modelu, jako je projekce Q/K/V/O. Pro násobení matic [m, k] x [k, n] -> [m, n] je počet FLOP 2 * m * k * n a bajty vstupně-výstupních operací paměti jsou m * k + n * k + m * n. Můžeme také otestovat latenci pro velikosti dávek 1–128.

Výkon GEMM vzhledem k výpočetním roofline a roofline propustnosti paměti.

Obrázek výše ukazuje model Roofline pro GEMM za různých konfigurací EP. Vidíme, že výkon GEMM je omezen paměťovou propustností. S rostoucí velikostí dávky se zvyšuje také aritmetická intenzita, čímž se zlepšuje výkon.

Mikrodávkování

Při použití mikrodávkování rozdělíme dávku rovnoměrně na dvě části. Z výše uvedených dvou obrázků vidíme, že když se m změní na m/2, účinnost násobení matic klesá. Proto provedení dvou násobení matic o velikosti m/2 trvá déle než provedení jednoho násobení matic o velikosti m.

Predikce více tokenů

V celém tomto článku jsme předpokládali použití predikce více tokenů (MTP) pro spekulativní dekódování. MTP mění délku dotazu na požadavek z 1 na 2. Pro násobení matic je to ekvivalentní změně m na m * 2, čímž se zvyšuje efektivita násobení matic. Na druhou stranu, pokud bychom nakreslili model Roofline pro MLA, zjistili bychom, že zvětšení délky dotazu výrazně zvyšuje efektivitu jádra MLA.

Proto hraje použití MTP důležitou roli v efektivitě modelu.

Implementace a optimalizace

V této části představíme některé podrobnosti implementace a optimalizace pro náš model DeepSeek-V3/R1.

Kvantování

Model DeepSeek-V3/R1 byl nativně trénován na FP8 s použitím schématu kvantování po blocích (per-block), přičemž váhy jsou kvantovány staticky a aktivace za chodu (on-the-fly). Namísto statického výpočtu faktoru škálování na kanál nebo matici se faktory škálování počítají napříč vektory o velikosti 128 prvků pro aktivace a dlaždicemi o velikosti 128x128 pro matice, což omezuje zhoršení přesnosti způsobené kvantováním.

V Perplexity spoléháme na kombinaci jader CUDA a Triton pro podporu inference, přičemž CUDA se používá pro jádra nejcitlivější na výkon a zřídka upravovaná (jako je attention a GEMM) a Triton implementuje širokou škálu jader pro aktivaci, normalizaci a pomocné funkce. Triton nám umožnil rychle přizpůsobit jádra schématu blokového kvantování.

Pro lineární a MoE vrstvy kombinujeme jádra Deep GEMM s našimi vlastními jádry Triton GEMM, protože jsme si všimli, že pro určité dimenze matic a nízké velikosti dávek poskytuje Split-K nižší latenci. Pokud nekvantovaná vrstva provádí násobení (M, K) x (K, N), vyžaduje pro blokové kvantování faktor škálování (M x ceil_div(K, 128)) x (ceil_div(K, 128), ceil_div(N, 128)). V případě blokového kvantování se faktory škálování pro aktivace počítají za chodu namísto předchozí kalibrace. Jelikož jsou faktory škálování aktivací agregovány pouze podél dimenze K a nikoli podél dimenze M, vyžadují jádra k podpoře tohoto schématu jen mírné úpravy.

Batched výpočet SiLU a násobení, zobrazující vstupní tenzory expertů, výstupní tenzory a škálovací faktory.

Aktivační funkce SiLU používaná v modelu DeepSeek-V3/R1 vyžadovala podstatné změny pro podporu grafů CUDA, blokového kvantování a dynamicky směřovaných počtů tokenů. Blokové kvantování může být problematické, protože zavádí horizontální redukce, avšak jádro již rozdělilo aktivace podél jejich skryté dimenze na bloky o velikosti 1024 prvků. V rámci jednoho bloku byl tenzor, který se má kvantovat, dále rozdělen na bloky o velikosti 128 za účelem výpočtu největší absolutní hodnoty, přičemž Triton generoval efektivní max redukce napříč warpem s minimální režijní tíží.

Aby bylo možné podporovat směřování MoE v rámci grafů CUDA, musí mít jádra přehled o informacích o směřování udávajících počet tokenů na experta, namísto plánování práce na základě velikosti vyrovnávacích pamětí, které byly alokovány tak, aby udržely horní mez počtu tokenů. Problém nemůžeme rozdělit na základě dimenzí vstupního tenzoru, takže spouštíme pevný počet trvalých jader, která čtou informace o směřování, aby určila, kolik tokenů je naplněno, a dynamicky mezi nimi rozdělují práci zpracování aktivací.

Některá naše jádra jsme již integrovali do projektu FlashInfer a v budoucnu budeme open-sourcovat další části našeho kódu.

Vrstva MLA

Pro výpočet MLA používáme FlashInfer. FlashInfer podporuje flexibilní nastavení tabulky stránek (Page Table) a extrémně vysoký výkon.

Sloučili jsme q_a_proj a kv_a_proj do jednoho qkv_a_proj. Latence klesla z 15,4 µs + 14,8 µs = 30,2 µs na 16,7 µs.

Rozložili jsme kv_b_proj na dvě matice, k_b_proj a v_b_proj. Napsali jsme jádro FP8 Block Quantized BMM pro výpočty související s těmito dvěma maticemi.

Graf Cuda

Graf Cuda může výrazně snížit režii při spouštění jader, což je pro výkon klíčové. Pro každou velikost dávky vytváříme graf Cuda.

Před vývojem našeho jádra AllToAll jsme pro komunikaci AllToAll používali torch.all_to_all_single(). Tato operace vyžaduje, aby všechna GPU používala stejnou velikost dávky. Různé skupiny DP však mohou spouštět různé velikosti dávek.

Abychom zajistili kompatibilitu all_to_all_single() s různými skupinami DP používajícími různé velikosti dávek, použili jsme před každým spuštěním modelu nejprve operaci allreduce() k získání maximální velikosti dávky mezi všemi skupinami DP. Poté jsme zajistili, že všechny skupiny DP spustily tuto velikost dávky.

Ačkoliv tento přístup zajišťuje, že můžeme používat graf Cuda, má tři nevýhody. Za prvé vyžaduje dodatečnou operaci allreduce(). Za druhé jsou skupiny DP s menšími velikostmi dávek nuceny používat zarovnávání (padding). Za třetí to činí náš implementační kód složitým.

Po implementaci našeho vlastního jádra AllToAll již nevyžadujeme, aby všechna GPU používala stejnou velikost dávky. Proto již nemusíme provádět dodatečné operace allreduce() ani zarovnávat velikosti dávek.

Směrovač MoE

Směrovač MoE je implementován v jazyce Triton a spoléhá na upravené řazení odvozené ze standardní knihovny, které rovněž sleduje indexy seřazených prvků. Implementace je sdílena napříč všemi modely MoE, protože směrování Mixtral je speciálním případem směrování DeepSeek, kde je skupina Top-K totožná se skupinou všech expertů. Řídká jádra spotřebovávají indexy a skóre Top-K přímo, zatímco schémata hustého odesílání/kombinace spoléhající na all-to-all vyžadují, aby byly informace o směřování agregovány pro každého experta zvlášť namísto na úrovni tokenů.

Budoucí práce

V budoucí práci plánujeme dále optimalizovat výkon modelu DeepSeek.

Nejvýznamnější příští optimalizací je dezagregace předběžného vyplnění (Prefill Disaggregation). Fáze předběžného vyplnění (Prefill) a fáze dekódování (Decode) modelu DeepSeek-V3/R1 mají velmi odlišné výpočetní charakteristiky. Obě mohou využívat jiné optimalizační strategie a schémata nasazení.

Pro vrstvu MLA používáme ve fázi dekódování absorpci matic (Matrix Absorption) ke snížení počtu FLOP výpočtu MLA. Ve fázi předběžného vyplnění by bylo výhodnější nejprve promítnout latentní vektor do prostoru K/V a poté provést výpočet ve formě Multi-Head Attention (MHA).

Pokud fáze předběžného vyplnění a dekódování běží na stejném GPU, používáme k omezení dopadu předběžného vyplnění na výstupní rychlost dekódování obvykle segmentované předběžné vyplnění (chunked prefill) k rozdělení dotazu na několik segmentů pro předběžné vyplnění. Protože KV cache ukládá latentní vektor, je obtížné převést MLA do formy MHA.

Pro vrstvu MoE používáme ve fázi dekódování co největší EP a DP ke zvýšení počtu vstupních tokenů na experta, čímž se zlepšuje výkon GroupGEMM. Ve fázi předběžného vyplnění je GroupGEMM již omezeno výpočetním výkonem, protože počet tokenů je již dostatečně velký. Proto pro předběžné vyplnění můžeme použít menší EP a DP.

Pokud předběžné vyplnění a dekódování běží na stejném GPU, tak dokud kterákoli skupina DP provádí předběžné vyplnění, latence vrstev MoE na všech GPU se zvýší, což výrazně ovlivní výstupní rychlost dekódování.

Kromě dezagregace předběžného vyplnění plánujeme optimalizovat také následující aspekty:

Výkon AllToAll: Naše jádro AllToAll dokáže v současnosti dosáhnout pouze 1/3 šířky pásma Infiniband. V optimalizaci tohoto jádra budeme pokračovat.

Spekulativní dekódování ve stylu EAGLE: Ve výše uvedených datech jsme předpokládali použití spekulativního dekódování k predikci 1 tokenu. EAGLE může použít stromovou strukturu k predikci více tokenů, což zlepšuje délku přijetí a může výrazně zvýšit výstupní rychlost.

Jádro GEMM: V dřívějším modelu Roofline můžeme vidět, že efektivita jádra GEMM je stále daleko od teoretického limitu. V optimalizaci tohoto jádra budeme pokračovat.

GB200 NVL72: V nejnovějším řešení GB200 NVL72 od společnosti NVIDIA je 72 GPU Blackwell propojeno prostřednictvím vysokorychlostního rozhraní NVLink. Pro modely s architekturou MoE je to velmi velká příležitost a výzva.

Závěr

Víceuuzlové nasazení modelů DeepSeek MoE dosahuje toho, co je u hustých LLM obvykle nemožné: současného zlepšení propustnosti i latence. Distribucí expertů napříč více GPU snižujeme tlak na paměťovou propustnost na zařízení, což umožňuje rychlejší zpracování a vyšší propustnost systému. Naše experimenty ukazují, že konfigurace EP128 dosahují až 5krát vyšší propustnosti při srovnatelných výstupních rychlostech ve srovnání s jednouzlovým nasazením.

Techniky překrývání výpočtů a komunikace, jako je mikrodávkování, významně snižují režii víceuuzlové komunikace, přičemž naše implementace vykazuje až 40% zrychlení. Naše vlastní komunikační jádra AllToAll a optimalizované implementace jader umožnily efektivní nasazení modelu s 671 miliardami parametrů.

Vzhledem k tomu, že architektury MoE získávají na oblibě pro své schopnosti, poskytují tyto strategie nasazení cenné poznatky pro efektivní škálování takových modelů.

Reference

Technická zpráva DeepSeek-V3

Přehled inferenčního systému DeepSeek-V3/R1

Megatron-LM: Trénink jazykových modelů s mnoha miliardami parametrů pomocí modelového paralelismu

EAGLE: Spekulativní vzorkování vyžaduje přehodnocení nejistoty prvků

Citace

BibTeX
@online{perplexity2025LowerLatencyAndHigherThroughputWithMultiNodeDeepseekDeployment,
  author = {{Perplexity} and Lequn Chen and Nandor Licker and Erin McKnight},
  title = {{Lower latency and higher throughput with multi-node DeepSeek deployment}},
  date = {2025-04-18},
  url = {https://perplexity.coolkeypoint.com/hub/blog/lower-latency-and-higher-throughput-with-multi-node-deepseek-deployment}
}