Szybszy silnik wygrał krótki test i spowolnił długą rozmowę dwunastokrotnie

MJ

Mateusz JanotaCEO & Founder

Przez jeden dzień stroiliśmy duży model językowy na pojedynczym laptopie M4 Max. W tle stoi pytanie, które zadaje nam coraz więcej klientów: czy praca na własnym sprzęcie to poważna opcja, czy zabawa dla hobbystów?

Użyteczna odpowiedź nie jest liczbą tokenów na sekundę. Jest nią jedna decyzja konfiguracyjna: silnik, który wygrywał benchmark krótkiego promptu, zostawił drugą turę długiej rozmowy dwunastokrotnie wolniejszą, bo skasował ponowne użycie już przetworzonego promptu. Do tego sprostowanie wcześniejszej tezy o rozmiarze bloku, błędnej w każdym elemencie, łącznie z tym, któremu dokumentowi ją przypisaliśmy.

Jak czytać te liczby

Wartości bezwzględne nie są czyste: przez cały czas na maszynie działały inne procesy korzystające z GPU, a sprzęt był rozgrzany. Przebieg kontrolny na identycznych ustawieniach zdryfował o 34 procent. Wiarygodne są więc tylko stosunki mierzone przeplataniem, wariant A i wariant B na przemian, z mediany, bo dryf uderza wtedy w oba warianty i skraca się w stosunku.

Pomiary pochodzą z dwóch sesji na dwóch checkpointach, czyli zapisanych kopiach wag tego samego modelu o różnej precyzji (kwantyzacja zapisuje wagi na mniejszej liczbie bitów, kosztem utraty wierności). Wynik o cache prefiksów pochodzi z kopii 4-bitowej, którą wdrożyliśmy, a sweep rozmiaru bloku i długi kontekst z wcześniejszej, 8-bitowej. Nie zapisaliśmy też wersji MLX, biblioteki obliczeniowej Apple pod jej własne układy, a to w niej siedzi przyczyna efektu rozmiaru bloku.

Maszyna i model

M4 Max, 40 rdzeni GPU, 128 GB RAM, 546 GB/s przepustowości pamięci, serwer oMLX 0.6.4, klient opencode. Model to mixture of experts: zamiast jednej dużej sieci trzyma wiele mniejszych podsieci, a router wybiera kilka z nich na każdy token, więc z 35 miliardów parametrów aktywne dla danego tokena jest około 3 miliardów.

Decyzja, która miała znaczenie: szybszy silnik skasował cache prefiksów

Dekodowanie spekulatywne w jednym akapicie. Dekodowanie jest wolne, bo jest sekwencyjne: jeden token to jeden pełny odczyt wag. Dokłada się więc mały model draftujący, który zgaduje kilka tokenów naraz, a duży model sprawdza całą propozycję w jednym przebiegu i przyjmuje ją do pierwszej rozbieżności. Wynik jest identyczny jak bez spekulacji, więc to czysta sztuczka na prędkość. Rozmiar bloku to liczba tokenów proponowanych w jednej rundzie, a accept length to średnia liczba tych, które przechodzą.

Serwer daje dwa sposoby. DFlash uruchamia osobny model draftujący, ładowany własnym pipeline'em. MTP, czyli multi-token prediction, korzysta z małej dodatkowej głowicy wtrenowanej w sam model i działa wewnątrz głównego silnika.

Na krótkich promptach DFlash po prostu wygrywa: 137 wobec 100 tokenów na sekundę, pojedyncze przebiegi. Wybierając po tym benchmarku, wybierasz DFlash. Sprawdziliśmy jednak kształt obciążenia, które faktycznie mamy: jeden prompt o długości 33 tysięcy tokenów i dwie tury pod rząd. Testowaną rzeczą jest cache prefiksów, czyli mechanizm, w którym serwer zachowuje policzony stan początku rozmowy, żeby druga tura nie liczyła promptu od zera.

Konfiguracjatura 1tura 2tokeny z cache
DFlash włączony46,1 s55,9 s0
DFlash wyłączony40,4 s4,7 s32 768

Druga tura bez szybszego silnika jest 12x szybsza. Z DFlashem każda tura płaci pełny prefill od zera, a serwerowy licznik cached_tokens pokazuje zero.

Przyczyna jest strukturalna, nie konfiguracyjna. DFlash wnosi własny pipeline ładowania i prywatny cache odcięty od głównego, a MTP działa wewnątrz silnika wsadowego, więc cache prefiksów zostaje nietknięty. Nie ma też ustawienia pośredniego. Dlatego pracujemy na MTP z wyłączonym DFlashem, świadomie przegrywając izolowany benchmark.

To fakt o oMLX 0.6.4, a nie o dekodowaniu spekulatywnym i nie o Apple Silicon. Przenośna jest metoda: ścieżka spekulacji i cache prefiksów to dwa osobne mechanizmy, które da się zbudować tak, że się nie składają, a benchmark jednej tury tego nie zobaczy.

Okno kontekstu podnieśliśmy przy okazji do 262144 tokenów. Prefill idzie w tempie około 350 tok/s, więc okno naprawdę działa, ale kolejne tury są tanie wyłącznie przy wyłączonym DFlashu.

Promptczas całkowityuwagi
4 178 tokenówokoło 9 s razem z 600 tokenami wyjściacodzienna praca
40 116 tokenów58,2 s
147 143 tokenów420,5 szweryfikowane, odpowiedź poprawna

Spekulacja bije kwantyzację, ale obie się składają

Pomiar przeplatany, mediana z czterech rund, prompt kodowy, 800 tokenów wyjścia, checkpointy 4- i 6-bitowy.

Precyzja wagspekulacja wyłączonaspekulacja włączonazysk ze spekulacji
6-bit42,0 tok/s107,1 tok/s2,55x
4-bit53,8 tok/s126,4 tok/s2,35x
4-bit wobec 6-bit1,28x1,18x

Spekulacja jest warta od 2,35x do 2,55x, a całe zejście z 6 bitów na 4 od 18 do 28 procent. Jeśli wdrażasz tylko jedno, to nie kwantyzację. Obie się jednak łączą: z 6 bitów bez spekulacji do 4 bitów ze spekulacją wychodzi 3,01x wobec naiwnego iloczynu 3,26x, czyli 92 procent. Warto mieć obie, w tej kolejności.

Mechanizm ubytku widać w ostatnim wierszu. Sprawdzenie kilku kandydatów w jednym przebiegu korzysta z jednego odczytu wag, więc spekulacja zdejmuje dekodowanie z ograniczenia przepustowością pamięci, a wtedy zmniejszanie wag daje mniej. Sprawdzenie szerokiego bloku nie jest za to darmowe: na MLX z wagami skwantyzowanymi koszt przebiegu rośnie szybciej niż liczba sprawdzanych tokenów.

Rozmiar bloku: sprostowanie i trzy źródła, które mieszaliśmy

Wcześniejsza wersja szła pod tytułem „rekomendacja z papieru działa odwrotnie”, przypisywała tę rekomendację plikowi README, a przytoczona tabela nie pochodziła z żadnego z tych dwóch miejsc. Co naprawdę mówi każde ze źródeł:

Papier. arXiv 2602.06036, DFlash: Block Diffusion for Flash Speculative Decoding, Chen, Liang, Liu. Nie zawiera żadnej rekomendacji rozmiaru bloku dla współbieżności 1, czyli dla serwera obsługującego jedno żądanie naraz. Jego własna ablacja mówi coś odwrotnego niż to, o co go oskarżyliśmy: duże bloki podnoszą koszt sprawdzania tam, gdzie wąskim gardłem są obliczenia.

Karta modelu. Tabela benchmarków pochodzi z karty modelu z-lab/Qwen3.6-35B-A3B-DFlash na Hugging Face, zmierzonej na NVIDIA B200 pod SGLang. Karta podaje blok 8 jako rekomendowany domyślny, a o 16 pisze tylko tyle, że daje dłuższe accept length i dobrą przepustowość przy współbieżności 1. Przykładowa komenda na tej samej karcie używa bloku 8.

README repozytorium. To źródło faktycznie opisuje nasz przypadek, a znaleźliśmy je już po postawieniu tamtej tezy. z-lab/dflash, README w commicie 07ebd93db9f4 z 18 sierpnia 2026, trzy tygodnie przed naszymi pomiarami: „For quantized targets or drafts, use block_size <= 5: MLX's current quantized matmul kernel becomes less efficient at larger verify widths”. Czyli: jeśli model albo draft są skwantyzowane i pracujesz na MLX, trzymaj blok na 5 lub niżej.

My uruchomiliśmy skwantyzowany model na MLX. Wskazówka upstreamu dla dokładnie naszego przypadku już wcześniej wskazywała poniżej 8. Nasz pomiar jest z nią zgodny i niczego nie odwraca.

Konfiguracjatok/swobec DFlash wyłączony
DFlash wyłączony76,31,00x
block=8, verify=adaptive137,21,80x
block=16, verify=adaptive113,81,49x
block=16, verify=dflash105,71,39x
block=16, verify=ddtree58,10,76x

Ograniczenia: checkpoint 8-bitowy, nie 4-bitowy, który wdrożyliśmy, jeden prompt, 1200 tokenów wyjścia, jeden przebieg na konfigurację. Blok 16 wypadł o 17 procent gorzej niż blok 8, ale ta różnica jest mniejsza niż dryf maszyny, więc twierdzimy tylko tyle, że kierunek zgadza się z upstreamem. Przy obu rozmiarach biegł wyłącznie tryb adaptive, a bloków 5, 4 i 2 nie testowaliśmy.

Czym nasz pomiar różni się od tabeli upstreamu

OśKarta modelu upstreamuMy
Sprzęt1x NVIDIA B200, GPU serwerowelaptop M4 Max, 40 rdzeni GPU
Stos serwującySGLangoMLX 0.6.4
Precyzjabf16, 16 bitów na wagę, tak jak wydano modelMLX 8-bit
Próbkowaniegreedytemperatura 0,6
Liczebność próby5 zestawów zadań, 5 niezależnych przebiegów na konfigurację1 prompt, 1 przebieg
Maksymalna długość wyjścia4096 tokenów1200 tokenów

Propozycja draftu jest przyjmowana tylko wtedy, gdy zgadza się z tym, co wybrałby główny model, więc sama zamiana dekodowania greedy na próbkowanie zmienia mierzoną wielkość. Nic w tym porównaniu nie izoluje sprzętu.

Błędny był też mechanizm, który podaliśmy. Tłumaczyliśmy efekt zapasem mocy obliczeniowej B200 wobec Maca, a to była hipoteza bez pomiaru. Upstream przypisuje efekt kernelowi mnożącemu skwantyzowane macierze w MLX, czyli przyczynie programowej, którą da się naprawić wydaniem poprawkowym. Kasujemy więc zbudowane na tym uogólnienie, że benchmarki dekodowania spekulatywnego z centrów danych nie przenoszą się na Apple Silicon. Do tego z-lab dystrybuuje własnego forka oMLX pod DFlasha, a my pracowaliśmy na standardowym.

Accept length: tam jest realna przestrzeń

Z telemetrii serwera: acceptance rate 0,547 przy 2,21 zaakceptowanych tokenach na rundę, a łącznie dla 41 żądań 0,618 przy 2,62. Późniejszy odczyt dał 3,53, więc wartość zależy od promptu. To 2,2 do 3,5 wobec 5,35 raportowanego przez upstream dla bloku 8 na HumanEval, a przyczyny różnicy nie wyizolowaliśmy.

Gdyby accept length wynosił 5 czy 6, sufit byłby blisko i własny draft nie dałby nic. Przy 2,2 luka jest realna, a każdy dodatkowy zaakceptowany token na rundę mnoży się wprost na przepustowość. To argument za trenowaniem własnego draftu, ale nie plan: opublikowane przepisy wymagają sprzętu NVIDII. I uczciwie: dla ścieżki MTP, na której pracujemy, accept length nie został zmierzony.

Dryf maszyny skasował nam jeden wynik

Testowaliśmy jeszcze dwa parametry runtime: tryb dekodowania i to, czy prefill jest dzielony na porcje. Cztery przebiegi tego samego testu, w odstępach kilkudziesięciu minut:

Ustawieniezimny prefill 33kdekodowanie
A34,2 s103,8 tok/s
B71,4 s64,4 tok/s
C49,7 s74,5 tok/s
A ponownie, jako kontrola47,2 s68,1 tok/s

Ostatni wiersz przywraca ustawienia z pierwszego, a liczby nie wróciły nawet blisko 34,2 s i 103,8 tok/s. Cały efekt był dryfem nagrzewającej się maszyny. Testując blokami, mielibyśmy tu pewny siebie akapit rekomendujący dwie zmiany ustawień, i byłby nieprawdziwy.

Stąd metoda przy każdym porównaniu: A, B, A, B na przemian, mediana zamiast średniej i zawsze przebieg kontrolny wracający do konfiguracji wyjściowej. Porównanie 6-bit z 4-bit pokazuje, że działa: wariant 6-bitowy spadał w kolejnych rundach ze 123 do 104, a 4-bitowy wygrywał w każdej rundzie z osobna.

Konfiguracja, na której zostaliśmy

  • MoE 35B z około 3 miliardami aktywnych parametrów, 4-bit, wersja przypięta

  • Draft MTP z domyślnym rozmiarem bloku, DFlash wyłączony świadomie

  • Cache prefiksów w RAM 24 GB, write-through. Był ustawiony na zero, czyli szedł wyłącznie przez SSD

  • Kontekst 262144 po stronie serwera, 65536 po stronie klienta, wyjście 8192

  • Próbkowanie: temperatura 0,6, top_p 0,95, top_k 20

  • Tryb dekodowania i chunked prefill: wartości domyślne, kwestia nierozstrzygnięta

Czego nie zmierzyliśmy

  • Wersji MLX. Skoro przyczyną efektu rozmiaru bloku jest kernel, każde zdanie o nim zależy od wersji.

  • Rozmiarów bloku poniżej 8, mimo że upstream mówi 5 lub mniej dla skwantyzowanego modelu na MLX.

  • Powtórzeń w sweepie rozmiaru bloku: jeden przebieg na konfigurację, brak miary wariancji.

  • Accept length na ścieżce MTP, czyli tej, którą wdrożyliśmy.

  • Jakości wyjścia w 4 bitach w realnej pracy.

Co z tego wynika, jeśli rozważasz własny sprzęt

Optymalizuj liczbę tokenów na przebieg, zanim zaczniesz optymalizować rozmiar wag. Spekulacja dała nam ponad 2x, kwantyzacja kilkanaście do dwudziestu kilku procent.

Mierz dwie tury, nie jedną. Konfiguracja, która wygrywała benchmark krótkiego promptu, zostawiła drugą turę rozmowy na 33 tysiącach tokenów 12x wolniejszą, a widać to dopiero po odczytaniu licznika cache'u.

Zanim spojrzysz na główną tabelę, znajdź wskazówkę dla swojego przypadku. Nasza była opublikowana trzy tygodnie przed pomiarem, w README, a nie na karcie modelu.

Jeśli rozważasz inferencję na własnym sprzęcie i chcesz, żeby ktoś zmierzył ją na Twoim obciążeniu, a nie na cudzym, odezwij się.

Najczęściej Zadawane Pytania

Masz projekt w głowie?

Napisz do nas

Porozmawiajmy o tym, jak możemy pomóc w realizacji Twoich pomysłów.

Zanek

Nie nadążasz za zmianami w świecie AI?

Pozwól, że weźmiemy to na siebie. Co tydzień destylujemy najważniejsze wydarzenia ze świata AI w skupiony, 5-minutowy przegląd - żebyś był na bieżąco bez szumu.

Dowiedz się więcej
Tygodnik AIonline
Wyselekcjonowane wiadomości AI do porannej kawy. Co tydzień.
Wyślij mi swój email, żeby się zapisać.