MoE na jednym GPU: wszystkie parametry kontra aktywne, offload i przepustowość pamięci
W modelu MoE wszystkie parametry kosztują pamięć, a aktywne kosztują przepustowość. Co to oznacza na jednej karcie 24 GB, jak offload modułów eksperckich do systemowej pamięci RAM zmienia sufit, dlaczego batching pomaga MoE mniej niż modelom dense i jak MoE wypadł w moim benchmarku agentowym.
- deep dive
- MoE
- inferencja
- llama.cpp
„35B-A3B” brzmi jak sprzeczność, dopóki nie rozbijesz kosztu na dwie liczby. Model MoE potrzebuje pamięci na wszystkie swoje parametry, ale każdy token czyta tylko niewielką ich część. Na jednym GPU te dwie liczby ciągną w przeciwne strony.
Wszystkie parametry kontra aktywne
W warstwie MoE blok feed-forward zostaje zastąpiony wieloma modułami eksperckimi (experts) i routerem. Dla każdego tokenu router wybiera kilka najwyżej ocenionych modułów eksperckich i uruchamiane są tylko one. Zatem:
- Wszystkie parametry decydują o pamięci: każdy moduł ekspercki musi być gdzieś załadowany.
- Aktywne parametry decydują o obliczeniach i, co przy dekodowaniu ważniejsze, o liczbie bajtów czytanych na token.
Weź Qwen3.6-35B-A3B przy mniej więcej 4,8 bita na wagę:
| Parametry | Bajty | |
|---|---|---|
| Do przechowania | 35B | ~21 GB |
| Czytane na token | ~3B | ~1,8 GB |
Model dense 27B czyta 17 GB na token, więc jego sufit przepustowości na RTX 4090 to około 59 przebiegów na sekundę. MoE czyta około 1,8 GB, co daje teoretyczny sufit liczony w setkach. W praktyce na długo przed tym górę biorą atencja, routing i narzut jąder. Ale to dlatego dekodowanie MoE wydaje się szybkie na skromnym sprzęcie.
Problem z pamięcią i offload
21 GB wag na karcie 24 GB zostawia mało miejsca na cache KV. Standardowa odpowiedź llama.cpp to przeniesienie wag modułów eksperckich do systemowej pamięci RAM i trzymanie całej reszty na GPU: --cpu-moe dla wszystkich modułów eksperckich albo --n-cpu-moe N dla pierwszych N warstw. Atencja i warstwy współdzielone zostają na GPU; moduły eksperckie są czytane z pamięci RAM.
Teraz bajty modułów eksperckich, których potrzebuje token, płyną z prędkością pamięci systemowej. Dwukanałowa pamięć DDR5 daje mniej więcej 80 GB/s. Jeśli z pamięci RAM czytane jest około 1,5 GB wag modułów eksperckich na token, sufit wynosi około 80 / 1,5 ≈ 53 tokeny na sekundę. To wciąż przyzwoity wynik i to dlatego modele MoE działają zaskakująco dobrze na kartach 8–16 GB z dużą ilością pamięci RAM. Częściowy offload, przy którym w pamięci RAM są moduły eksperckie tylko niektórych warstw, wypada pośrodku.
Batching pomaga mniej
W modelu dense batching jest prawie darmowy: każda sekwencja używa tych samych wag, czytanych raz (liczby są w notatce o batchingu). W MoE różne tokeny są kierowane do różnych modułów eksperckich. Gdy partia rośnie, rośnie też zbiór modułów eksperckich używanych w jednym przebiegu, a liczba bajtów na przebieg znów pnie się w stronę rozmiaru wszystkich wag. Pod obciążeniem przewaga MoE w pojedynczym strumieniu częściowo znika.
Co mówi mój benchmark
W amber-bench Qwen3.6-35B-A3B uzyskał 742,2, a w dyscyplinie pętli 65,9. Qwen3.6-27B w wersji dense uzyskał 816,2 i 89,0. MoE wykonał też 183 zmarnowane wywołania narzędzi, wobec 146 w modelu dense. To jeden harness i jeden przebieg, więc to przesłanka, a nie prawo. Ale pasuje do wzorca, który widzę w pracy z agentami: szybkie tokeny nie pomagają, jeśli agent zużywa je na kręcenie się w kółko.
Kiedy MoE to właściwy wybór
- Ograniczona pamięć VRAM i dużo systemowej pamięci RAM: offload sprawia, że duży MoE nadaje się do użytku tam, gdzie model dense o podobnej jakości by się nie zmieścił.
- Opóźnienie dla jednego użytkownika na skromnym sprzęcie: mało aktywnych bajtów oznacza szybkie dekodowanie.
- Agentowe używanie narzędzi: przetestuj MoE na własnym harnessie, zanim się na niego zdecydujesz. Na moim modele dense 27B były bardziej zdyscyplinowane niż MoE.
- Serwowanie przy dużej równoległości: rozbieżność w wyborze modułów eksperckich osłabia przewagę z batchingu, więc mierz pod realistycznym obciążeniem.
Zasady, których się trzymam
- Pamięć szacuj według wszystkich parametrów, a szybkość według aktywnych. Nigdy odwrotnie.
- Przenieś moduły eksperckie do pamięci RAM, zanim zmniejszysz kontekst. Przepustowość pamięci RAM to często lepszy kompromis niż mniejszy cache KV.
- Mierz model we własnej pętli. Dla agentów miarą nie jest szybkość, tylko liczba ukończonych zadań na godzinę.
Źródła: flagi offloadu pochodzą z llama.cpp (--cpu-moe, --n-cpu-moe). Liczby z benchmarku są z mojego rankingu amber-bench. Sufity przepustowości to rachunek na serwetce: 1008 GB/s dla RTX 4090, ~80 GB/s dla dwukanałowej pamięci DDR5.