Decode
Jak działa
W fazie decode model wykonuje jeden przebieg forward na jednym tokenie (ostatnio wygenerowanym). Dla warstw uwagi nowy token oblicza swój wektor zapytania (Q) i wykonuje uwagę względem kluczy i wartości wszystkich poprzednich tokenów pobranych z KV cache; jego własne K, V dopisuje się do cache. Reszta warstw (MLP, projekcje) przetwarza pojedynczy wektor. Model produkuje rozkład następnego tokenu, próbkuje go i powtarza krok, aż do tokenu końca lub limitu długości. Ponieważ operacje dotyczą jednego tokenu (małe mnożenia macierz-wektor), jednostki obliczeniowe są słabo wykorzystane, a czas kroku zdominowany przez odczyt wag i KV cache z pamięci (memory-bound). Batching wielu zapytań i większe KV cache zwiększają arytmetyczną intensywność i przepustowość.
Rozwiązany problem
Po zbudowaniu kontekstu w fazie prefill model musi generować kolejne tokeny sekwencyjnie, bo każdy token zależy od poprzednich. Faza decode realizuje to efektywnie: zamiast przeliczać uwagę dla całej sekwencji, korzysta z zapisanego KV cache i przetwarza tylko jeden nowy token na krok. Ponieważ na każdy token trzeba wczytać z pamięci wszystkie wagi modelu i cały KV cache, przy jednym zapytaniu faza jest ograniczona przepustowością pamięci, a nie mocą obliczeniową.
Kluczowe mechanizmy
Mocne strony i ograniczenia
Komponenty
Przebieg forward na pojedynczym tokenie, generujący rozkład następnego tokenu; operacje typu macierz-wektor o niskiej intensywności arytmetycznej.
Uwaga nowego tokenu względem wszystkich zapisanych kluczy i wartości; dopisanie własnych K, V do cache w każdym kroku.
Wybór następnego tokenu z rozkładu (greedy, top-k, top-p, temperatura) i podanie go jako wejście kolejnego kroku.
Implementacja
Przy jednym lub kilku zapytaniach operacje macierz-wektor słabo obciążają jednostki obliczeniowe, marnując potencjał FLOPs GPU.
KV cache rośnie liniowo z długością sekwencji i liczbą zapytań, co przy długich kontekstach staje się wąskim gardłem pamięci.
Ewolucja
Upowszechnienie generatywnych transformerów uwidacznia memory-bound charakter fazy decode i rolę KV cache.
Continuous batching (Orca, vLLM) i speculative decoding zwiększają przepustowość oraz redukują opóźnienia fazy decode.
Hiperparametry (konfigurowalne osie)
Liczba równoczesnych zapytań; większa amortyzuje odczyt wag i podnosi przepustowość.
Strategia i parametry wyboru tokenu: temperatura, top-k, top-p.
Złożoność obliczeniowa
Złożoność czasowa: O(N d) na token (uwaga po KV cache) + O(d^2) projekcje. Złożoność przestrzenna: O((N + t) x L x d) na rosnacy KV cache.
Przy pojedynczym zapytaniu teoretyczna górna granica prędkości decode to (przepustowość pamięci) / (rozmiar wag + KV cache na token); np. model 13B w FP16 (~26 GB) na karcie o przepustowości ~1 TB/s daje rzędu kilkudziesięciu tokenów/s. Continuous batching może zwiększyć łączną przepustowość systemu wielokrotnie, amortyzując odczyt wag na wiele równoczesnych zapytań.
Wąskie gardło obliczeniowe
Każdy krok decode musi wczytać z pamięci wszystkie wagi modelu i cały KV cache przy niewielu operacjach, więc przepustowość pamięci wyznacza prędkość.
Paradygmat wykonania
Wszystkie warstwy i ścieżki obliczeń są aktywne dla każdego generowanego tokenu.
Decode wykonuje gęsty przebieg forward na jednym tokenie bez warunkowego routingu (chyba że model jest MoE).
Równoległość
Tokeny generowane są sekwencyjnie (każdy zależy od poprzedniego); równoległość uzyskuje się między zapytaniami przez batching, nie w obrębie jednej sekwencji.
Wymagania sprzętowe
GPU o wysokiej przepustowości pamięci (HBM) są preferowane, bo faza decode jest memory-bound; przepustowość pamięci, nie FLOPs, wyznacza szybkość generacji.
Decode działa na CPU (np. llama.cpp), ale niska przepustowość pamięci RAM ogranicza liczbę tokenów na sekundę.