Osiem razy siedem to pięćdziesiąt sześć. Tyle że model nazywa się „8x7B", a waży czterdzieści siedem miliardów parametrów — nie pięćdziesiąt sześć. I zanim zdążysz się z tym pogodzić, ktoś dorzuca, że aktywnych jest tylko trzynaście. Trzy liczby, z których żadna nie klei się z sąsiednią. Ściągasz GGUF-a, plik ma dwadzieścia kilka giga w Q4, a gość w komentarzach pisze, że „chodzi jak siódemka". No to jak? Duży jak czterdziestka, szybki jak trzynastka, a nazwany jak pięćdziesiątka szóstka?
To nie literówka i nie marketing. To Mixtral 8x7B1 — i cała ta trójca liczb bierze się z jednego pomysłu architektonicznego, który nazywa się Mixture of Experts. Jak go raz zrozumiesz, przestaniesz się dziwić, czemu model „na 13B" i tak każe ci kupić kartę pod model „na 47B". Rozłóżmy to na części.
Trzy liczby, jeden trik
Klasyczny model językowy jest gęsty (dense): na każdy token przepycha wszystkie swoje wagi. Wrzucasz słowo, przechodzi przez każdą warstwę, w każdej warstwie dotyka każdego neuronu. Prosto, uczciwie, drogo — bo im więcej parametrów, tym więcej roboty na literkę.
Mixtral robi inaczej. Bierze architekturę zwykłego Mistrala 7B, ale w każdej warstwie podmienia jeden blok — ten feedforwardowy (FFN), czyli tę część, która „przetwarza" token po tym, jak uwaga (attention) już popatrzyła na kontekst. Zamiast jednego takiego bloku wstawia osiem równoległych. To są właśnie „eksperci".1 Osiem kopii tej samej maszynerii, każda wytrenowana ciut inaczej.
I teraz clou: dla danego tokena nie odpalają się wszyscy. Przed blokiem eksperckim stoi mały router (sieć bramkująca, gating network), który patrzy na token i wybiera z ósemki tylko dwóch ekspertów — top-2.1 Ich wyjścia miesza ważoną sumą (wagi bierze z softmaxu) i jedzie dalej. Sześciu pozostałych w tej warstwie, dla tego tokena, w ogóle nie rusza. Śpią.
Stąd rozjazd liczb. Parametrów całkowitych (total) jest 46,7 miliarda — potocznie ~47B. Ale na przejście jednego tokena aktywnych (active) jest tylko 12,9 miliarda, czyli ~13B.2 Płacisz obliczeniami za trzynastkę, a nosisz na barana czterdziestkę siódemkę.
Skąd 47, a nie 56?
No dobra, ale skoro to „8x7B", to czemu nie wychodzi 56 miliardów? Bo mnożenie „osiem razy siedem" jest po prostu błędne. Powielona jest tylko ta część FFN. Cała reszta — warstwy uwagi, embeddingi, normalizacje — siedzi w modelu raz i jest współdzielona przez wszystkich ekspertów i wszystkie tokeny.2 Nie mnożysz jej przez osiem ani w sumie, ani w liczbie aktywnej. Dlatego total ląduje na 46,7B (a nie 56B), a active na 12,9B (a nie na jednej ósmej z 56).
Zajrzyj zresztą do config.json na karcie modelu — tam to stoi czarno na białym:
num_local_experts: 8, num_experts_per_tok: 2, przy hidden_size: 4096
i num_hidden_layers: 32.3 Osiem ekspertów na warstwę, dwóch na token, trzydzieści
dwie warstwy. Mnożenie odpala się w każdej z tych 32 warstw z osobna.
I tu druga rzecz, która ludziom umyka: wybór ekspertów nie jest stały. Router decyduje oddzielnie dla każdego tokena i dla każdej warstwy.1 Słowo „kot" w warstwie 3 może trafić do ekspertów 1 i 5, a to samo „kot" w warstwie 4 — do 2 i 7. A następne słowo w tym samym zdaniu pojedzie zupełnie inną trasą. To nie jest tak, że model „wybiera dwóch specjalistów na cały prompt" i tyle. To osiem tysięcy mikro-decyzji na akapit, każda robiona w locie.
To czemu nie zajmuje tyle co trzynastka?
I tu dochodzimy do pułapki, na którą łapie się pół internetu. Skoro na token aktywne jest tylko ~13B, to model „zajmuje tyle co trzynastka", nie? Odpalę na karcie pod 13B i będzie grało?
Nie będzie. I to jest najważniejsze zdanie w całym tym wpisie.
Router wybiera ekspertów dopiero w trakcie przejścia przez daną warstwę, osobno dla każdego tokena. Znaczy: z góry nie wiesz, którzy eksperci będą potrzebni. Następne słowo może chcieć dowolnej pary z ósemki, w dowolnej z 32 warstw. Więc żeby model w ogóle mógł ruszyć, wszystkie 47 miliardów wag musi siedzieć w pamięci naraz — cała ósemka ekspertów w każdej warstwie, gotowa do wezwania.4 Oszczędność z MoE dotyczy obliczeń (compute, latencji), nie pamięci. Mistral mówi to wprost: model „przetwarza wejście i generuje wyjście z taką samą szybkością i kosztem jak model 12,9B".2 Szybkością i kosztem obliczeń — nie apetytem na VRAM.
Zapamiętaj to jedno rozróżnienie, a przestaniesz się przejeżdżać na MoE: aktywne parametry liczą się do prędkości, całkowite — do pamięci. Mixtral 8x7B liczy jak trzynastka, ale ważyć musisz go jak czterdziestkę siódemkę. Do samej inferencji w Q4 potrzebujesz około 25–30 GB na wagi, zanim jeszcze dołożysz KV-cache i kontekst. Karta pod 13B tego nie udźwignie — a naiwne „mało aktywnych = mało VRAM-u" to najczęstsza wpadka przy planowaniu sprzętu. Ile realnie wchodzi na wagi, liczyliśmy tutaj.
Zbierzmy to w tabelce, bo dwie kolumny mówią więcej niż akapit:
| Co porównujemy | Model gęsty (dense) | Mixtral 8x7B (MoE) |
|---|---|---|
| Parametry całkowite | tyle, ile aktywnych | 46,7B (~47B) |
| Parametry aktywne na token | wszystkie | 12,9B (~13B) |
| Ekspertów w warstwie FFN | 1 | 8 |
| Ekspertów na token | 1 | 2 (top-2) |
| Co decyduje o prędkości | parametry (= wszystkie) | parametry aktywne |
| Co decyduje o VRAM | parametry (= wszystkie) | parametry całkowite |
Po co ten cały cyrk, skoro pamięć i tak trzeba mieć całą? Bo za cenę pamięci klasy 47B dostajesz jakość, która w benchmarkach dorównuje albo bije Llamę 2 70B i GPT-3.5 — przy koszcie obliczeniowym trzynastki.1 To jest ten deal: płacisz VRAM-em jak za dużego, liczysz jak za małego, a mądrość dostajesz bliżej tego dużego. Dla kogoś, kto ma dość RAM-u, ale mało cierpliwości do tokenów na sekundę — świetny interes.
Zrób to sam (a przynajmniej zaplanuj)
MoE to architektura, nie kompresja. Łatwo pomylić to z kwantyzacją czy pruningiem, ale to inna bajka: MoE od początku trenuje się jako rzadko aktywowaną sieć, a kwantyzacja ściska wagi już po treningu — i spokojnie łączysz jedno z drugim (kwantyzowany GGUF Mixtrala to codzienność). Jak działają same nazwy kwantyzacji, rozgryzaliśmy tu — ta sama logika oszczędzania pamięci działa i na kwantyzowanym Mixtralu, tyle że na innym piętrze niż samo MoE.
W praktyce llama.cpp daje ci pod to dedykowaną flagę. Skoro attention i embeddingi są
„zawsze aktywne", a bloki eksperckie odpalają się wybiórczo, to najwięcej ugrasz, trzymając
te zawsze-aktywne komponenty na GPU, a same wagi ekspertów spychając do RAM-u. Od tego jest
--n-cpu-moe N — „trzymaj wagi MoE z pierwszych N warstw na CPU" — albo --cpu-moe, które
przenosi wszystkie.4 Kroisz VRAM kosztem szybkości — właśnie dlatego, że pamięć musi
pomieścić całość, a nie tylko aktywną ścieżkę.
Najprościej — cały model na kartę, jak wejdzie:
llama-cli -m mixtral-8x7b-instruct-v0.1.Q4_K_M.gguf -ngl all -c 8192 -fa on -cnv
Nie wchodzi (a przy 47B na przeciętnej karcie do gier nie wejdzie)? Zostaw wszystkie warstwy na GPU, ale wypchnij eksperckie FFN-y z części z nich do RAM-u:
llama-cli -m mixtral-8x7b-instruct-v0.1.Q4_K_M.gguf \
-ngl all --n-cpu-moe 12 -c 8192 -fa on -ctk q8_0 -ctv q8_0 -cnv
Które flagi co robią i w jakiej kolejności się nimi ratować przy „out of memory", rozpisaliśmy w poradniku o flagach llama.cpp. Sam Mixtral 8x7B (base i Instruct) jest na licencji Apache 2.01 — ściągasz, odpalasz, kombinujesz bez proszenia nikogo o zgodę.
Jedno ostrzeżenie na koniec, żebyś nie wpadł w drugą pułapkę. To „liczy jak 13B" obowiązuje, gdy generujesz jeden strumień token po tokenie. Gdy walisz batchem — wiele sekwencji naraz — różne tokeny w paczce wybierają różnych ekspertów, więc w danej warstwie i tak zwykle rozgrzewa się większość albo cała ósemka jednocześnie. Teoretyczne przyspieszenie topnieje. MoE lubi pojedynczego użytkownika przy biurku bardziej niż zatłoczony serwer.
Wyobraź sobie warsztat z ośmioma fachowcami przy każdym stanowisku. Do każdej śrubki brygadzista woła tylko dwóch — akurat tych, co się na niej znają. Reszta stoi i pije kawę. Robota idzie szybko, jakbyś płacił za dwóch. Ale wypłatę i tak wystawiasz całej ósemce, bo nigdy nie wiesz, która śrubka przyjdzie następna i kogo do niej trzeba będzie zawołać. I to jest cały Mixtral: tempo dwójki, lista płac ósemki. Twoja karta nie płaci za tych, co pracują — płaci za tych, co czekają w gotowości.
Przypisy · źródła
Jiang i in., Mixtral of Experts, arXiv:2401.04088 — abstrakt i sekcja architektury: 8 ekspertów na warstwę FFN, routing top-2, wynik dorównujący/bijący Llamę 2 70B i GPT-3.5, licencja Apache 2.0. arxiv.org/abs/2401.04088. ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎
Mistral AI, oficjalne ogłoszenie Mixtral of Experts — dokładne liczby 46,7B total / 12,9B active, mechanizm routera (8 grup parametrów, wybór 2, addytywne łączenie wyjść), stwierdzenie, że koszt i szybkość odpowiadają modelowi 12,9B. mistral.ai/news/mixtral-of-experts. ↩︎ ↩︎ ↩︎
config.jsonmodelumistralai/Mixtral-8x7B-v0.1—num_local_experts: 8,num_experts_per_tok: 2,hidden_size: 4096,num_hidden_layers: 32. huggingface.co/mistralai/Mixtral-8x7B-v0.1/raw/main/config.json. ↩︎llama.cpp, definicje flag
-cmoe/--cpu-moe(„keep all Mixture of Experts (MoE) weights in the CPU") oraz-ncmoe/--n-cpu-moe N(„keep the Mixture of Experts (MoE) weights of the first N layers in the CPU") — sam mechanizm istnieje właśnie dlatego, że wag ekspertów nie da się usunąć z pamięci; można je jedynie przenieść z VRAM-u do RAM-u. common/arg.cpp. ↩︎ ↩︎