BlogLLM do hloubky
Umělá inteligenceProgramování

Mixture of Experts: proč model s 671 miliardami parametrů používá jen 37

9. 7. 2026 · 24 minut čtení

V kartách moderních open-source modelů narazíte na zvláštní dvojici čísel: DeepSeek-V3 má „671 miliard parametrů, 37 miliard aktivních“, gpt-oss-120b „117 miliard, 5,1 miliardy aktivních“. Jak může model většinu svých parametrů nepoužívat — a k čemu je pak vlastně má? Odpovědí je architektura Mixture of Experts (MoE), dnes de facto standard u velkých modelů. V článku rozebereme, jak MoE vrstva funguje, jak router rozhoduje, který expert dostane který token, proč se experti nespecializují tak, jak byste čekali — a hlavně co řídkost znamená prakticky: proč MoE model potřebuje paměť podle celkových parametrů, ale běží rychlostí těch aktivních, a jak toho využít při self-hostingu.

Ilustrace výběru správného člena týmu ze seznamu

Router dělá přesně tohle: pro každý token vybere ze seznamu expertů ty nejvhodnější. Ilustrace: Katerina Limpitsouni, unDraw (otevřená licence)

Co znamenají celkové a aktivní parametry

Začněme tím, co ta dvojice čísel přesně říká. Celkové parametry jsou všechny váhy, které model má uložené — to, co stahujete z Hugging Face a co musí bydlet v paměti. Aktivní parametry jsou ty, které se skutečně zapojí do výpočtu jednoho konkrétního tokenu. U klasického (dense, hustého) modelu jsou obě čísla stejná: Llama 3.1 70B protlačí každý token všemi 70 miliardami vah. U MoE modelu se liší, a to dramaticky — DeepSeek-V3 na každý token použije jen ~5,5 % svých vah, gpt-oss-120b dokonce jen ~4,4 %.

Důležité: která část vah se použije, se rozhoduje za běhu, pro každý token a každou vrstvu zvlášť. Není to tedy tak, že by se při startu vybrala nějaká výseč modelu a zbytek ležel ladem — během generování jedné odpovědi se postupně vystřídá velká část všech expertů, jen nikdy ne najednou.

Kde MoE mění Transformer

Abychom pochopili, co přesně se „řídne“, musíme vědět, kde váhy jsou. Každý blok Transformeru má dvě hlavní části: attention (míchá informace mezi tokeny) a feed-forward síť (FFN, zpracovává každý token samostatně — dvě lineární vrstvy s aktivací mezi nimi). Málo se ví, že v běžném LLM tvoří FFN vrstvy zhruba dvě třetiny všech parametrů; u gpt-oss-120b připadá na MoE/FFN části 114,7 z celkových 116,8 miliardy, tedy 98 % (attention má u něj jen ~1 miliardu díky úsporné konstrukci).

A přesně tady MoE zasahuje: nahradí jednu FFN v každém bloku sadou N nezávislých kopií („expertů“) a malým routerem, který pro každý token vybere k nejvhodnějších. Attention zůstává beze změny — proto MoE nešetří KV cache ani práci s kontextem, šetří výpočet v FFN. Výstupy vybraných expertů se sečtou vážené skóre routeru a pokračuje se dál jako v běžném Transformeru.

Dense model token „banka“ FFN všech ~44 mld. vah FFN počítá každý token výstup paměť = výpočet: 70B modelu = 70B na token Mixture of Experts token „banka“ router expert 1 spí expert 2 váha 0,7 expert 3 spí expert 4 váha 0,3 0,7×E2 + 0,3×E4 paměť podle všech expertů, výpočet jen podle vybraných (top-k)
MoE vrstva nahrazuje FFN: router pro každý token vybere top-k expertů (tady top-2) a jejich výstupy zkombinuje. Ostatní experti pro tento token nic nepočítají.

Router: jak token vybírá experty

Router je až směšně jednoduchý: jedna lineární vrstva. Vezme vektor tokenu (např. 4 096 čísel) a vynásobí ho maticí N × 4 096, kde N je počet expertů. Výsledkem je N skóre; z nich se vybere top-k, tedy k expertů s nejvyšším skóre. Jejich skóre se znormalizují (softmaxem nebo sigmoid gatingem) a použijí jako váhy při sčítání výstupů. Celý mechanismus v pseudo-PyTorchi:

Python
import torch
import torch.nn.functional as F

class MoELayer(torch.nn.Module):
    def __init__(self, dim: int, n_experts: int, top_k: int):
        super().__init__()
        self.router = torch.nn.Linear(dim, n_experts, bias=False)
        self.experts = torch.nn.ModuleList(
            [FeedForward(dim) for _ in range(n_experts)]
        )
        self.top_k = top_k

    def forward(self, x):                      # x: [tokeny, dim]
        skore = self.router(x)                 # [tokeny, n_experts]
        vahy, idx = torch.topk(skore, self.top_k, dim=-1)
        vahy = F.softmax(vahy, dim=-1)         # normalizace jen top-k

        vystup = torch.zeros_like(x)
        for i, expert in enumerate(self.experts):
            maska = (idx == i).any(dim=-1)     # ktere tokeny mne chteji
            if maska.any():
                w = vahy[maska][idx[maska] == i].unsqueeze(-1)
                vystup[maska] += w * expert(x[maska])   # pocita se JEN tady
        return vystup

Klíčový detail je v komentáři na předposledním řádku: expert počítá jen nad tokeny, které mu router přidělil. Tady vzniká celá úspora. A protože router je součást modelu, jeho váhy se učí společně se vším ostatním — nikdo mu neříká, jak má tokeny dělit; gradient ho tlačí k takovému rozdělení, které minimalizuje chybu.

Problém, který učený routing přináší: load balancing

Učený router má zákeřnou degenerativní smyčku: expert, který je na začátku tréninku o chlup lepší, dostává víc tokenů, takže se učí rychleji, takže dostává ještě víc tokenů… a skončíte s modelem, kde tři experti dělají všechno a zbytek je mrtvá váha. Klasické řešení je auxiliary loss — přidaná ztrátová funkce, která penalizuje nerovnoměrné vytížení (takto to dělá Switch Transformer i Mixtral). Má to ale cenu: optimalizujete něco jiného než kvalitu predikce. DeepSeek-V3 proto zavedl auxiliary-loss-free balancing: ke skóre každého experta se přičítá malý bias, který se dynamicky zvyšuje přetěžovaným expertům do mínusu a nevytíženým do plusu — vyrovnává provoz, aniž by kontaminoval gradient. Detail, ale přesně tenhle typ detailů rozhoduje, jestli trénink MoE konverguje.

Kolik expertů vybrat a čím je skórovat: top-k, softmax, sigmoid

Dvě zdánlivě drobná rozhodnutí v návrhu routeru mají překvapivě velké důsledky. První je hodnota k. Původní Shazeerův návrh (2017) používal top-k s k ≥ 2 s argumentem, že router potřebuje porovnávat alespoň dva experty, aby se měl podle čeho učit. Switch Transformer pak ukázal, že funguje i top-1 — a je levnější na výpočet i komunikaci. Mixtral se vrátil k top-2, jemnozrnné architektury šly na top-8. Zajímavý je návrat k top-1 u Llama 4: Maverick posílá každý token na shared experta plus jediného routovaného experta ze 128. Dává to smysl právě v kombinaci — shared expert garantuje, že každý token dostane nějaké „základní zpracování“, takže routovaný expert si může dovolit být úzce vyhraněný a stačí jeden. Odměnou je minimální výpočet na token (17B ze 400B) a poloviční objem komunikace mezi GPU oproti top-2.

Druhé rozhodnutí je skórovací funkce. Klasicky router skóre normalizuje softmaxem — ten ale všechny experty svazuje dohromady: skóre se musí sečíst na 1, takže když jeden expert posílí, ostatním nutně ubere. Při 256 expertech navíc softmax roztlačí většinu skóre k nule a rozdíly mezi kandidáty na hranici top-k jsou v šumu. DeepSeek-V3 proto přešel na sigmoid: každý expert dostane nezávislé skóre mezi 0 a 1 (normalizuje se až vybraná top-k množina), takže experti spolu „nesoutěží o rozpočet“ a gradient netlačí na potlačování konkurentů. Zní to jako kosmetika, ale teoretické analýzy naznačují, že sigmoid gating zmírňuje právě tu winner-take-all dynamiku, kterou jsme popsali u load balancingu.

Token choice vs. expert choice: kdo si koho vybírá

Všechno výše popsané je tzv. token choice routing: každý token si nezávisle vybere své top-k experty. Z toho plyne celý problém s balancováním — tokeny se na ničem nedomlouvají, takže se klidně všechny sesypou na jednoho experta. Google v roce 2022 navrhl elegantní obrácení: expert choice. Místo aby si tokeny vybíraly experty, každý expert si vybere top-c tokenů z batche, které chce zpracovat. Load balancing je tím vyřešen konstrukčně — každý expert zpracuje přesně c tokenů, žádná auxiliary loss není potřeba. Bonus navíc: počet expertů na token je proměnlivý, takže „těžké“ tokeny (které chce víc expertů) dostanou víc výpočtu a triviální tokeny míň. V experimentech to zrychlilo konvergenci tréninku víc než 2×.

Proč to tedy nepoužívají všichni? Expert choice má zásadní vadu pro generativní modely: expert vybírá tokeny napříč celým batchem najednou, takže rozhodnutí o jednom tokenu závisí na ostatních tokenech — včetně těch, které v autoregresivním generování ještě neexistují nebo patří jiným uživatelům. Při dekódování token po tokenu se mechanismus hroutí (není z čeho vybírat top-c) a při tréninku prosakuje informace z budoucnosti. Proto expert choice najdete v encoderech a výzkumných pracích, zatímco produkční LLM zůstávají u token choice a balancování řeší pomocnými mechanismy z předchozí kapitoly.

Shared expert a jemnozrnní experti

Novější MoE modely přidávají dvě vylepšení. Shared expert je expert, který dostane každý token bez ohledu na router — zachytává „společné“ znalosti (gramatiku, obecné vzory), takže routovaní experti se mohou diferencovat. DeepSeek-V3 má 1 shared + 256 routovaných, Kimi K2 podobně; Qwen3 a gpt-oss se obejdou bez něj. Jemnozrnné (fine-grained) expertství pak znamená místo 8 velkých expertů udělat 256 malých a vybírat top-8 místo top-2: kombinací malých expertů roste počet možných „sestav“ (u DeepSeeku je to 256 nad 8 ≈ 1014 kombinací na vrstvu), takže model může znalosti skládat mnohem flexibilněji.

Na čem se experti (ne)specializují

Intuice říká, že jeden expert bude „na medicínu“ a jiný „na Python“. Analýzy — už od Mixtral paperu — ukazují něco jiného: specializace je většinou syntaktická a tokenová, ne tematická. Expert se vyhraní na interpunkci, na čísla, na odsazení v kódu, na anglická slovesa — routing se totiž rozhoduje per token podle jeho vektoru, ne podle tématu dokumentu. Je to dobrá připomínka, že MoE není „výbor doktorů“, ale statistický trik na zvětšení kapacity: název Mixture of Experts je z roku 1991 a je spíš marketingově přežilý. Mimochodem — pod původním článkem Adaptive Mixtures of Local Experts je podepsán i Geoffrey Hinton, kterého znáte z našeho článku o sedmi osobnostech AI; myšlenka čekala na svůj čas přes 25 let, než ji Shazeer a spol. (2017) oživili uvnitř neuronových sítí a Mixtral (2023) zpopularizoval v open-source.

Trénink MoE: proč je křehčí než dense model

Zatím jsme MoE popisovali z pohledu hotového modelu. Trénink je ale kapitola sama pro sebe — a většina „divných“ konstrukcí, které jsme viděli (auxiliary loss, bias u DeepSeeku, shared expert), existuje právě kvůli tréninkovým patologiím. Pojďme si projít ty hlavní, protože vysvětlují, proč MoE dlouho zůstávalo doménou pár laboratoří s obřími rozpočty.

Capacity factor: když se tokeny nevejdou

Na GPU se špatně počítá s tenzory, jejichž tvar není znám předem. Router ale rozděluje tokeny dynamicky — jednou dostane expert 50 tokenů, podruhé 500. Klasické implementace (od GShard po Switch Transformer) to řeší tak, že každému expertovi přidělí pevný buffer:

Python
# kapacita experta = prumer na experta * rezerva
expert_capacity = (tokens_per_batch / num_experts) * capacity_factor
# capacity_factor byva 1.0 az 1.5

A tady přichází nepříjemné překvapení: co s tokeny, které se do bufferu přetíženého experta nevejdou? Zahodí se. Doslova — token expertem neprojde a do další vrstvy pokračuje jen přes reziduální spojení, nezpracovaný (technika známá jako token dropping). Switch Transformer uvádí, že s dobře fungujícím load balancingem se zahazuje pod 1 % tokenů, což trénink přežije. Vyšší capacity factor zahazování omezí, ale platí se za něj pamětí a výpočtem naprázdno: buffery se na pevnou velikost dopočítávají paddingem, i když jsou poloprázdné.

Zapamatujte si

Capacity factor je rezerva velikosti bufferu experta. Vyšší hodnota znamená méně zahozených tokenů, ale více paddingu, paměti a výpočtu naprázdno. Nízká hodnota šetří hardware, ale může odebírat tokenům odborné zpracování.

Capacity factor 1,0 — 8 tokenů, 4 experti → buffer 2 tokeny na experta t1 t2 t3 t4 t5 t6 t7 t8 router expert 1 t1 t4 buffer plný (2/2) expert 2 t2 t6 přetéká! t8 se nevejde expert 3 t3 1/2 — padding naprázdno expert 4 t5 t7 buffer plný (2/2) t8 zahozen → jen residual connection
Token dropping: expert 2 je nadprůměrně žádaný, jeho buffer přetekl a token t8 vrstvou projde nezpracovaný. Expert 3 mezitím počítá s poloprázdným bufferem — padding je čistá ztráta.

Že je tenhle kompromis zbytečný, ukázal až MegaBlocks (2022): přeformuloval výpočet MoE vrstvy jako block-sparse násobení matic, kde každý expert dostane přesně tolik řádků, kolik mu router přidělil. Žádné pevné buffery, žádné zahazování, žádný padding — tzv. dropless MoE — a přesto o desítky procent rychlejší trénink, protože block-sparse kernely jedou na moderních GPU skoro stejně efektivně jako husté násobení. Dnes je to standard: na MegaBlocks staví např. tréninkový stack Databricks a stejnou myšlenku používají fused MoE kernely ve vLLM, ke kterým se dostaneme za chvíli. Capacity factor tím ale nezmizel z povědomí — potkáte ho v konfiguračních souborech mnoha frameworků a starších modelů, tak teď víte, co znamená.

Router z-loss: souboj s numerikou

Druhá patologie je záludnější. Tým Googlu při škálování MoE narazil na trénink, který stovky tisíc kroků běžel v pořádku a pak se z ničeho nic rozpadl do NaN. Viníka popsali v paperu ST-MoE: logity routeru postupně rostou (nic je neomezuje — softmax je invariantní vůči posunu, takže model nemá důvod je držet malé), a protože se trénuje v bfloat16, velké hodnoty v exponenciále softmaxu způsobí zaokrouhlovací chyby. A router je jediné místo v Transformeru, kde drobná numerická chyba diskrétně přepne rozhodnutí — token jde k jinému expertovi, gradient skočí, nestabilita se řetězí. Řešení je opět skoro směšně jednoduché, tzv. router z-loss: k celkové ztrátě se přičte kvadrát logaritmu součtu exponenciál logitů, čímž se logity drží u nuly a softmax v numericky bezpečné zóně. Od té doby je z-loss standardní součást MoE receptů.

Proč MoE špatně snáší fine-tuning

Už Switch Transformer a po něm ST-MoE dokumentují, že MoE modely se při fine-tuningu na malých datasetech chovají hůř než dense modely: mají obrovský počet parametrů (kapacitu) vůči množství fine-tuning dat, takže snadno overfittují — ST-MoE popisuje případy, kdy sparse model dosáhl 100% přesnosti na trénovací sadě a přitom na validační zaostal za dense baseline. Křehký je i samotný router: rozložení tokenů ve fine-tuning datech je jiné než při pretrainingu, balancování se rozjede a specializace expertů se může rozpadnout. Doporučené protilátky z literatury: výrazně vyšší dropout uvnitř expertů (Switch používá 0,4 v expertech vs. 0,1 jinde), menší learning rate, případně fine-tunovat jen ne-expertní parametry. Pro praxi z toho plyne rada, kterou zopakujeme i v závěru: pokud plánujete vlastní dotrénování, sáhněte po dense modelu, nebo po LoRA adaptérech, které váhy expertů (a routeru) nechají na pokoji.

Upcycling: MoE z hotového dense modelu

Trénovat MoE od nuly je drahé a nestabilní. Existuje zkratka — sparse upcycling (Komatsuzaki et al., 2022): vezměte natrénovaný dense model, jeho FFN vrstvu N-krát zkopírujte jako výchozí stav expertů, přidejte náhodně inicializovaný router a pokračujte v tréninku. Experti startují identičtí a diferencují se až tím, že jim router začne posílat různé tokeny. Ušetříte většinu ceny pretrainingu — Qwen1.5-MoE (explicitně upcyklovaný z dense Qwen-1.8B na 14,3B celkových / 2,7B aktivních parametrů) uvádí ~25 % tréninkových nákladů oproti srovnatelnému dense 7B modelu. U Mixtralu 8x7B si komunita všimla, že architektura přesně kopíruje Mistral 7B a váhy expertů si byly nápadně podobné — Mistral to nikdy nepotvrdil, ale upcycling z Mistralu 7B je všeobecně přijímaná hypotéza. Limit téhle zkratky popisuje pozdější výzkum: upcyklovaní experti zůstávají v okolí společného výchozího bodu, takže se plné diverzity expertů trénovaných od nuly nedosáhne — při dostatečně velkém rozpočtu vyhrává trénink from scratch. Proto DeepSeek-V3 ani Kimi K2 upcycling nepoužívají.

Proč MoE výrobci používají: ekonomika škálování

Ze scaling laws víme, že kvalita modelu roste s počtem parametrů a s množstvím výpočtu. MoE tyhle dvě veličiny rozpojí: můžete zvětšovat kapacitu (celkové parametry, tedy kolik toho model „ví“), aniž by úměrně rostl výpočet na token (aktivní parametry, tedy jak dlouho a za kolik se počítá). DeepSeek-V3 se natrénoval za ~2,8 milionu GPU hodin — zlomek toho, co by stál dense model srovnatelné kvality. A při inference platíte (časem i penězi) za 37B výpočtu, i když model „zná“ 671B. Proto dnes MoE používají prakticky všechny velké modely — a proto poskytovatelé API dokážou nabízet obří modely za ceny malých.

Model Celkem Aktivních Experti Routing
Mixtral 8x7B (2023) 46,7 B 12,9 B 8 top-2
Llama 4 Maverick 400 B 17 B 128 + shared top-1
Qwen3-235B-A22B 235 B 22 B 128 top-8
gpt-oss-120b 117 B 5,1 B 128 top-4
gpt-oss-20b 21 B 3,6 B 32 top-4
DeepSeek-V3 671 B 37 B 256 + shared top-8
Kimi K2 1 000 B 32 B 384 + shared top-8
Tabulka 1: Přehled MoE modelů — celkové vs. aktivní parametry, počet expertů a routing

Všimněte si trendu v čase: od 8 velkých expertů s top-2 (Mixtral) k stovkám malých s top-4 až top-8 a extrémní řídkosti — Kimi K2 aktivuje 3,2 % modelu, gpt-oss-120b 4,4 %.

Kolik dense parametrů MoE vlastně odpovídá

Přirozená otázka zní: je gpt-oss-120b „stodvacítka“, nebo „pětka“? Akademickou odpověď dali Clark et al. (DeepMind, 2022) v práci o scaling laws pro routované modely: kvalita MoE se dá popsat mocninným zákonem ve dvou nezávislých proměnných (výpočet na token a počet expertů) a z něj odvodit Effective Parameter Count — velikost dense modelu, který by dosáhl stejné ztráty. Dvě zjištění stojí za zapamatování. Zaprvé přínos dalších expertů klesá logaritmicky — zdvojnásobení počtu expertů zdaleka nepřinese to, co zdvojnásobení aktivních parametrů; proto nikdo nestaví model s 10 000 experty. Zadruhé výhoda routingu se zmenšuje s rostoucí velikostí base modelu, byť extrapolace, kde přesně vyprchá, je podle samotných autorů velmi citlivá na naměřené koeficienty — a praxe zatím ukazuje, že u dnešních velikostí se MoE pořád bohatě vyplácí.

Komunita používá jednodušší empirické pravidlo: geometrický průměr celkových a aktivních parametrů, tedy √(celkové × aktivní). Pro gpt-oss-120b vychází √(117 × 5,1) ≈ 24B — čekejte tedy kvalitu zhruba dense ~24B modelu za výpočetní cenu 5B modelu. Je to heuristika stará jak Mixtral, žádný přírodní zákon; zajímavé ale je, že ji nezávisle podpořil novější empirický výzkum fine-tuningu: Qwen3-30B-A3B se při dotrénování chová jako dense model o ~8,5B parametrech, což je skoro přesně geometrický průměr (10,1B) a daleko od obou krajních hodnot. Pro rychlý odhad při výběru modelu je to nejlepší jednočíselná aproximace, jakou máme — jen nezapomeňte, že skutečné pořadí modelů vždy rozhodnou benchmarky na vaší úloze.

VRAM, self-hosting a distributed serving

A teď prakticky, v návaznosti na náš článek o hostování open-source LLM. Pro self-hosting platí dvě pravidla, která jdou proti sobě:

  • Paměť se řídí celkovými parametry. Router může pro příští token vybrat kteréhokoli experta, takže všechny váhy musí být připravené. Qwen3-235B-A22B ve 4bitové kvantizaci zabere ~125 GB, DeepSeek-V3 skoro 400 GB — bez ohledu na to, kolik parametrů je „aktivních“.
  • Rychlost se řídí aktivními parametry. Generování je limitované tím, kolik vah se musí na token přečíst a pronásobit. Qwen3-235B-A22B proto generuje zhruba rychlostí 22B modelu, gpt-oss-120b dokonce rychlostí 5B modelu — řádově rychleji, než by odpovídalo jejich velikosti.

Rychlý odhad hardwaru

Kapacitu VRAM a RAM počítejte z celkových parametrů a KV cache. Rychlost generování odhadujte podle aktivních parametrů, ale ověřte ji na cílovém batchi a délce promptu: v těchto režimech se výhoda řídkosti mění.

Paměť vs. výpočet na token (4bitová kvantizace) Llama 3.1 70B (dense) ~40 GB paměti 70 B vah na token → pomalé Qwen3-235B-A22B (MoE) ~125 GB 22 B na token → ~3× rychlejší než 70B dense gpt-oss-120b (MoE, MXFP4) ~64 GB → jedna 80GB GPU 5,1 B na token → velmi rychlé paměť (celkové parametry) výpočet na token (aktivní)
MoE obrací poměr: žere hodně paměti, ale málo výpočtu. Dense model naopak. (Hodnoty orientační, bez KV cache.)

Z toho plyne, na jakém hardwaru MoE dává smysl: všude tam, kde je paměti relativně dost, ale výpočtu málo. Typicky Mac s unified memory (128 GB RAM M-čipu utáhne Qwen3-235B-A22B, který by na GPU vyžadoval dvě H100 — a generuje svižně, protože na token čte jen 22B) nebo server s velkou RAM a jednou GPU. Naopak čistě GPU nasazení s malou VRAM je pro MoE nejméně příznivé: platíte drahou paměť za váhy, které většinu času spí.

Jak to řeší datacentra: expert parallelism a all-to-all

Když se model nevejde na jednu GPU, dense svět sahá po tensor parallelism (TP): každá matice vah se rozřeže mezi GPU a po každé vrstvě se dílčí výsledky slijí operací all-reduce.

U MoE to jde taky, ale je to plýtvání — řezali byste na osm dílů i experty, které pro daný token vůbec nepočítají, a malé matice jemnozrnných expertů se řezáním stanou neefektivními. Přirozenější je expert parallelism (EP), poprvé nasazený v GShard: experty mezi GPU nedělit po kouscích, ale po celých kusech. Při 256 expertech a 8 GPU má každá karta svých 32 expertů; token se po rozhodnutí routeru fyzicky pošle na kartu, kde jeho expert bydlí, tam se spočítá a výsledek se pošle zpět.

Cena za to je nový komunikační vzor: all-to-all. Každá GPU drží tokeny pro experty všech ostatních GPU, takže si v každé MoE vrstvě všechny karty vymění data se všemi — dvakrát (dispatch tokenů tam, combine výstupů zpět). To je řádově náročnější na síť než all-reduce a u velkých nasazení je právě latence all-to-all dominantní náklad; proto DeepSpeed-MoE zaváděl hierarchické all-to-all (nejdřív uvnitř uzlu přes NVLink, pak mezi uzly) a proto DeepSeek pro provoz V3 napsal vlastní komunikační knihovnu DeepEP. A je tu ještě jeden důsledek, který už známe: load balancing. U auxiliary loss z první poloviny článku nešlo jen o „mrtvé experty“ — při expert parallelismu nevyvážený provoz znamená, že jedna GPU počítá a sedm jich čeká. Balancování expertů je tedy i systémový problém, ne jen statistický.

Dva druhy paralelismu, dvě komunikace

  • Tensor parallelism: jedna váhová matice je rozdělená mezi GPU; výsledky se synchronizují pomocí all-reduce.
  • Expert parallelism: celé experty žijí na různých GPU; tokeny a jejich výstupy mezi nimi putují přes all-to-all.

Pokud MoE servírujete přes vLLM, většinu z toho dostanete hotové. MoE vrstvy počítají tzv. fused MoE kernely (Triton): místo smyčky přes experty, jako v naší pseudo-ukázce, se tokeny seskupí podle přiděleného experta a všechna expertní násobení proběhnou v jediném spuštění kernelu nad „naskládanou“ maticí vah — myšlenkově stejný trik jako block-sparse formulace MegaBlocks. Na jednom uzlu se experty standardně jen replikují v rámci TP; skutečný expert parallelism zapnete přepínačem --enable-expert-parallel a pro víceuzlová nasazení vLLM nabízí i DeepEP backend a EPLB (Expert Parallel Load Balancer), který za běhu přesouvá repliky přetížených expertů. Pro jednu GPU doma nic z toho řešit nemusíte — tam se hraje jiná hra.

Trik pro domácí hardware: experty do RAM

Řídkost umožňuje ještě jeden manévr, který u dense modelů nefunguje: rozdělit model mezi GPU a CPU podle rolí. Attention, embeddingy a KV cache (malé, používané pořád) nechat na GPU; váhy expertů (obrovské, každá použitá jen občas) odsunout do systémové RAM. llama.cpp na to má přímo přepínač:

Bash
# gpt-oss-120b na jedne RTX 4090 (24 GB): experty do RAM, zbytek na GPU
$ llama-server -m gpt-oss-120b-mxfp4.gguf --n-gpu-layers 999 --n-cpu-moe 30

# --cpu-moe        = vsechny experty na CPU
# --n-cpu-moe N    = experty prvnich N vrstev na CPU, zbytek na GPU

Proč to funguje? Na token se z RAM čtou jen váhy top-k expertů (u gpt-oss-120b ~3 GB místo 60), což pomalejší RAM zvládne v rozumném čase — a výpočetně náročný zbytek jede na GPU. Komunita takhle běžně provozuje 120B modely na jedné spotřebitelské kartě rychlostí kolem 20–30 tokenů/s. S dense 120B modelem by tentýž stroj generoval jednotky tokenů za minutu. Praktický postup ladění: začněte s vysokým --n-cpu-moe (klidně počet všech vrstev), sledujte volnou VRAM a číslo postupně snižujte — každá vrstva expertů, která se vejde na GPU, přidá na rychlosti.

Přepínač --n-cpu-moe je přitom jen pohodlná zkratka (do llama.cpp přibyla až v PR #15077, srpen 2025) nad obecnějším mechanismem -ot / --override-tensor, který umísťuje tenzory podle regulárního výrazu nad jejich názvy. Váhy routovaných expertů mají v GGUF souborech jména jako blk.7.ffn_up_exps.weight, takže:

Bash
# rucne totez, co --cpu-moe: vsechny expertni tenzory na CPU
$ llama-server -m model.gguf -ngl 999 -ot "\.ffn_(up|down|gate)_exps=CPU"

# experty vrstev 0-19 na CPU, zbytek nechat na GPU
$ llama-server -m model.gguf -ngl 999 -ot "blk\.(1?[0-9])\.ffn_.*_exps=CPU"

Jeden zrádný detail: modely se shared expertem mají kromě tenzorů _exps (routovaní) i tenzory _shexp (shared). Shared expert počítá každý token, takže patří na GPU — regex cílený jen na _exps ho tam správně nechá, ale pokud VRAM přeteče a začnete přesouvat agresivněji, přesně tohle je tenzor, který má jít na CPU jako poslední. Stejná logika platí obecně: na GPU držte všechno, co se používá při každém tokenu (attention, embeddingy, KV cache, shared expert), do RAM odsouvejte jen to, co se používá zřídka.

Prefill vs. decode: řídkost se chová dvakrát jinak

Inference LLM má dvě fáze s úplně jinou charakteristikou. Prefill je zpracování celého vstupního promptu; počítá stovky až tisíce tokenů naráz a obvykle jej omezuje výpočet, ne paměť.

Protože si každý token volí experty nezávisle, při tisícovce tokenů se skoro jistě aktivují všichni experti. Váhy se tak stejně čtou celé. Úspora MoE v prefillu tedy neplyne z menšího čtení paměti, ale z ušetřených FLOPs: každý token projde jen top-k experty.

Decode je následné generování po jednom tokenu. Pracuje s malými maticemi, omezuje jej paměťová propustnost a při batchi 1 se na token skutečně čtou jen váhy top-k expertů. Právě na tomhle stojí trik s experty v RAM: pomalou paměť trápí jen malé čtení v decode, zatímco výpočetně hladový prefill jede na GPU.

Z toho plyne i praktický důsledek pro konfiguraci s --n-cpu-moe: rychlost generování bývá překvapivě dobrá, ale prefill dlouhých promptů je citelně pomalejší než při plném GPU běhu — v prefillu potřebujete všechny experty, a ti leží v pomalé RAM u pomalého CPU. Pokud je váš workload „dlouhý dokument, krátká odpověď“ (RAG, sumarizace), bolí vás offload expertů víc, než ukazují benchmarky tokenů/s zaměřené na generování.

Tři upozornění, než se nadchnete

  • KV cache se nezmenšuje. MoE řídne jen v FFN; attention a jeho paměť na kontext zůstávají. Dlouhé kontexty stojí u MoE stejně jako u dense modelu stejné dimenze (některé modely to řeší jinými technikami — DeepSeek má MLA, gpt-oss sliding window u poloviny vrstev).
  • Dávkování mění matematiku. Úspora „čte se jen top-k expertů“ platí pro jeden požadavek. Při velkém batchi (server s desítkami souběžných uživatelů) se v každé vrstvě potká provoz pro většinu expertů, takže se stejně čte skoro celý model — výhoda se přesouvá z paměťové propustnosti do ušetřených FLOPs. Pro domácí použití (batch 1) je to ale čistá výhra.
  • Aktivní parametry nejsou kvalita. Model s 22B aktivními z 235B celkových není „jen 22B model“ — kapacita znalostí odpovídá spíš celku. Ale ani mu nevěřte jako dense 235B modelu; realita bývá u geometrického průměru (~72B), jak jsme rozebrali výše. Srovnávejte přes benchmarky, ne přes parametry.

Co s tím v praxi

  • Čtěte obě čísla. Paměť dimenzujte podle celkových parametrů (plus KV cache), rychlost odhadujte podle aktivních. „235B model“ může být provozně levnější než 70B dense.
  • Pro lokální běh na jedné GPU jsou dnes nejlepší volbou malé MoE (gpt-oss-20b do 16 GB, gpt-oss-120b s --n-cpu-moe na 24GB kartě) — rychlost dense modelu jednotek miliard, kvalita o třídu výš.
  • Mac s unified memory je pro MoE ideální: velká sdílená paměť pojme celek, nízká výpočetní náročnost na token sedne slabší GPU části.
  • Kvantizujte směle experty — snášejí 4 bity velmi dobře (gpt-oss je v MXFP4 dokonce trénovaný); citlivější jsou attention a embeddingy, ty nechte ve vyšší přesnosti (většina GGUF kvantizací to tak dělá sama).
  • Na serveru s velkým batchem počítejte s tím, že paměťová výhoda řídkosti slábne — dimenzujte podle FLOPs a propustnosti, ne podle historek z domácího provozu. Pro vLLM platí konfigurace z článku o hostování.
  • Fine-tuning MoE je těžší disciplína (overfitting velké kapacity na malých datech, rozbití balancování routeru — viz kapitola o tréninku) — pokud plánujete dotrénování, začněte s dense modelem nebo použijte LoRA jen na attention vrstvy.
  • U offloadu expertů na CPU myslete na prefill. Generování bude svižné, ale zpracování dlouhého promptu potřebuje všechny experty z pomalé RAM. Pro RAG a sumarizaci dlouhých dokumentů měřte time-to-first-token, ne jen tokeny/s.

Chcete si MoE osahat na vlastním železe?

V našem GPU Labu si můžete půjčit výkon a vyzkoušet, jak gpt-oss nebo Qwen3 běží naostro. Architektury neuronových sítí (včetně směrování expertů) rozebíráme v kurzu Machine learning a neuronové sítě. A pokud chcete jít do hloubky u LLM obecně, mrkněte na Umělá inteligence pro programátory, vědu a datovou analytiku nebo začněte článkem o hostování open-source LLM.

Vyzkoušet GPU Lab →

Zdroje a další čtení

← Zpět na blog