Przewodnik po inżynierii LLM: 45 pojęć dla systemów produkcyjnych

Tłumaczenie automatyczne

Ten artykuł został automatycznie przetłumaczony z angielskiego oryginału.

To materiał referencyjny dla inżynierów, którzy znają podstawy ML i systemów, a chcą powiązać objaw w produkcji z odpowiednią częścią stosu. Obejmuje 45 pojęć z zakresu sprzętu, inferencji, treningu, wdrażania, aplikacji i operacji. Każdy wpis opisuje mechanizm, jego wpływ na działający system oraz warunek, w którym przytoczony wynik jest prawdziwy. Jeśli zaczynasz od objawu, na przykład wolnego pierwszego tokena albo OOM pod obciążeniem, skorzystaj z poniższej tabeli objawów, aby znaleźć wpisy do przeczytania.

CzęśćTematySekcje
I — Podstawy sprzętoweModel roofline, pamięć GPU, słownik pojęć sprzętowych1–3
II — Podstawy inferencjiOpóźnienie, przepustowość, KV cache, attention, kwantyzacja4–9
III — Optymalizacje inferencjiKernele CUDA, FlashAttention, batching, PagedAttention, speculative decoding10–17
IV — Architektura modeluBudowa transformera, modele decoder-only, MoE, tokenizacja, okna kontekstu18–22
V — Trening i alignmentPretraining, LoRA, trening mieszanej precyzji, ZeRO, prawa skalowania, RLHF/DPO/GRPO, destylacja23–32
VI — Skalowanie i wdrażanieParallelism, frameworki serwujące, wybór GPU, routing33–36
VII — AplikacjeEmbeddings, RAG, agenci, inżynieria promptów37–40
VIII — Operacje produkcyjneRate limiting, tryby awarii, monitorowanie, koszty, planowanie pojemności41–45

Zacznij od objawu

Każdy wiersz wskazuje wpisy do przeczytania najpierw oraz to, co zmierzyć, zanim zmienisz stos.

Objaw lub decyzjaZacznij odCo zmierzyć przed zmianą stosu
Pierwszy token pojawia się wolnoPrefill i decode, TTFTCzas w kolejce, długość promptu, czas prefill i P99 TTFT
Tokeny napływają wolnoRoofline, TPOTTPOT w zależności od współbieżności, przepustowość pamięci i kształt batcha
Długie konteksty powodują wywłaszczanie lub OOMKV cache, PagedAttentionZajętość KV, długości żądań, straty alokatora i liczba wywłaszczeń
Model nie mieści się w budżecieKwantyzacja, Wybór GPUJakość, przepustowość kernela, rezerwa pamięci i goodput przy docelowym SLO
Wybór środowiska serwującegoFrameworki serwujące, ParallelismPrzepustowość i opóźnienie P99 przy docelowym SLO na własnych promptach
Żądania przekraczają limit czasu pod obciążeniemTryby awarii, Rate limitingGłębokość kolejki, wywłaszczenia, częstość ponowień i długości odpowiedzi
Trening się nie mieściLoRA i QLoRA, ZeRO, FSDPPamięć stanu modelu, komunikacja, przepustowość i jakość na zbiorze wydzielonym
Koszty rosnąRouting, optymalizacja kosztówKwalifikowalność ruchu, błędy jakości, współczynnik trafień cache i dane z faktur

Dalsze przewodniki według decyzji

Jeśli decydujesz…Zacznij odNastępnie przeczytaj
Jak serwować wiele dostrojonych adapterówPodstawy inferencji i wdrażaniePrzewodnik po serwowaniu LoRAX
Czy kwantyzowaćKwantyzacjaPrzewodnik po kwantyzacji modeli
Jak podzielić model między GPUParallelismSkalowanie dużych modeli językowych
Czy robić fine-tuningTrening i alignmentPrzewodnik po fine-tuningu LLM
Jak wyszukiwanie wpisuje się w aplikacjęEmbeddings i RAGMetryki ewaluacji RAG
Jak działają systemy agentoweAgenci i inżynieria promptówPętle rozumowania agentów AI
Jak rankingować wyniki wyszukiwaniaEmbeddings i rerankingStos rankingu wyszukiwania

Część I — Podstawy sprzętowe

Intensywność arytmetyczna, hierarchia pamięci GPU i pojęcia sprzętowe z tej części wyjaśniają wiele wyborów w dalszej części przewodnika.

1. Ograniczenie pamięcią a ograniczenie obliczeniami oraz model roofline

Punktem wyjścia dla wydajności LLM jest intensywność arytmetyczna: ile użytecznych obliczeń GPU wykonuje na każdy bajt danych wczytany z pamięci? Ten stosunek decyduje, czy operacja jest ograniczona obliczeniami (czeka na jednostki obliczeniowe), czy ograniczona pamięcią (czeka na wczytanie danych).

Każde GPU ma „krytyczną intensywność”, przy której jego szczytowa wydajność obliczeniowa równa się przepustowości pamięci. Dla NVIDIA H100 SXM z gęstymi rdzeniami Tensor w BF16 lub FP16 (989 TFLOPS; specyfikacja 1979 TFLOPS zakłada rzadkość strukturalną):

989 TFLOPS3.35 TB/s≈295 FLOPs/byte\frac{989 \text{ TFLOPS}}{3.35 \text{ TB/s}} \approx 295 \text{ FLOPs/byte}

Poniższy wykres roofline pokazuje osiągalną wydajność obliczeniową w funkcji intensywności arytmetycznej. Nachylona linia to obszar ograniczony pamięcią, w którym limit wyznacza przepustowość; pozioma linia to pułap obliczeniowy; zagięcie między nimi to próg 295 FLOPs/byte.

Wykres roofline dla H100 SXM: dach rośnie wzdłuż nachylenia wyznaczonego przepustowością do punktu zagięcia przy około 295 FLOPs na bajt, a potem pozostaje płaski na poziomie 989 TFLOPS. Decode przy batchu o rozmiarze jeden leży na nachylonej części przy około 1 FLOP na bajt; prefill w batchu leży na płaskiej części.Wykres roofline dla H100 SXM: dach rośnie wzdłuż nachylenia wyznaczonego przepustowością do punktu zagięcia przy około 295 FLOPs na bajt, a potem pozostaje płaski na poziomie 989 TFLOPS. Decode przy batchu o rozmiarze jeden leży na nachylonej części przy około 1 FLOP na bajt; prefill w batchu leży na płaskiej części.

Decode przy batchu o rozmiarze jeden oraz długi lub dostatecznie zbatchowany prefill zwykle leżą po przeciwnych stronach tego progu:

  • Decode jest ograniczony pamięcią. Generowanie tokenów jeden po drugim oznacza wczytywanie z pamięci wielogigabajtowej macierzy wag, aby pomnożyć ją przez jeden nowy token. W uproszczonej analizie dla gęstego modelu 16-bitowego i batcha o rozmiarze jeden operacja ma około 1 FLOP/byte, czyli mniej więcej 295 razy poniżej progu roofline H100. Ta różnica wyjaśnia, dlaczego w tym reżimie decode nie może zbliżyć się do szczytowej wydajności obliczeniowej.
  • Długi lub dostatecznie zbatchowany prefill jest często ograniczony obliczeniami. Przetwarzanie wielu tokenów promptu ponownie wykorzystuje wagi w dużych mnożeniach macierzy, co może podnieść intensywność arytmetyczną powyżej progu roofline. Krótkie prompty i małe batche mogą być natomiast ograniczone ruchem pamięci lub narzutem uruchamiania kerneli.

Aby więc przyspieszyć decode, popracuj nad przepustowością pamięci: zmniejsz wagi przez kwantyzację, zmniejsz narzut pamięci KV dzięki GQA i PagedAttention, a intensywność podnieś przez batching. W długich lub dobrze zbatchowanych prefillach pomóc może szybsze mnożenie macierzy i obliczenia w niższej precyzji; obciążenia z krótkim prefillem profiluj osobno.

2. Hierarchia pamięci GPU

GPU ma cztery warstwy pamięci ułożone jak piramida: duża, ale wolna pamięć główna (HBM) na dole oraz maleńkie, ale bardzo szybkie rejestry na górze. Przenoszenie danych między tymi warstwami to jedno z głównych ograniczeń wydajności. Rysunek pokazuje cztery poziomy H100, od rejestrów przypisanych do wątków na górze po 80 GB HBM3 u podstawy.

Hierarchia pamięci H100 narysowana jako piramida: rejestry na wątek, do 228 KB pamięci współdzielonej na SM, pamięć podręczna L2 o rozmiarze 50 MB oraz 80 GB HBM3 o przepustowości około 3,35 TB/s, która przechowuje wagi i KV cache.Hierarchia pamięci H100 narysowana jako piramida: rejestry na wątek, do 228 KB pamięci współdzielonej na SM, pamięć podręczna L2 o rozmiarze 50 MB oraz 80 GB HBM3 o przepustowości około 3,35 TB/s, która przechowuje wagi i KV cache.

Od najszybszej do najwolniejszej w H100:

  1. Rejestry to najszybsza pamięć, podłączona bezpośrednio do wątków obliczeniowych. W instrukcji WGMMA architektury Hopper macierz A może pochodzić z rejestrów lub pamięci współdzielonej, a macierz B pochodzi z pamięci współdzielonej.
  2. SRAM (pamięć współdzielona) to szybka pamięć robocza na chipie, lokalna dla każdego SM.
  3. Pamięć podręczna L2 to 50 MB warstwa współdzielona. Może udostępniać dane wykorzystywane ponownie przez wiele SM bez kolejnego pobrania z HBM.
  4. HBM3 to 80 GB pamięci głównej, która przechowuje wagi modelu i KV cache, z przepustowością ~3,35 TB/s.

Różnica między poziomami na chipie i poza nim jest duża. W A100 artykuł o FlashAttention szacuje przepustowość SRAM na chipie na około 19 TB/s, wobec 1,5–2,0 TB/s dla HBM (Dao et al., 2022), czyli mniej więcej 10-krotną różnicę. FlashAttention i fuzja kerneli zmniejszają ruch do HBM, ponieważ zachowują lub łączą pośrednie wyniki na chipie. PagedAttention rozwiązuje inny problem: mapuje logiczne bloki KV na nieciągłe fizyczne bloki pamięci GPU, co zmniejsza fragmentację i umożliwia współdzielenie bloków.

3. Słownik pojęć sprzętowych GPU

Poniższe pojęcia pojawiają się w całej reszcie przewodnika.

HBM (High Bandwidth Memory) układa w stos warstwy DRAM połączone przelotkami krzemowymi (TSV) obok układu GPU. Generacje to HBM2e (A100, 2 TB/s), HBM3 (H100, 3,35 TB/s) i HBM3e (H200/B200, 4,8–8 TB/s). Przepustowość HBM bezpośrednio ogranicza TPOT w reżimach decode ograniczonych pamięcią.

GDDR (Graphics DDR) to tradycyjna pamięć graficzna stosowana w GPU konsumenckich i stacjach roboczych, takich jak RTX 4090 i L40S. Ma mniejszą przepustowość niż HBM, ale kosztuje mniej za GB. GDDR6X w RTX 4090 zapewnia około 1 TB/s wobec 3,35 TB/s HBM3 w H100.

SM (Streaming Multiprocessor) to podstawowy blok obliczeniowy GPU NVIDIA. Każdy SM zawiera rdzenie CUDA, rdzenie Tensor, pamięć współdzieloną i planistę warpów. H100 ma 132 SM; A100 ma ich 108.

Rdzenie Tensor to wyspecjalizowane jednostki mnożenia i akumulacji macierzy wewnątrz każdego SM. Przyspieszają mnożenia macierzy o mieszanej precyzji, które dominują w obliczeniach transformera. Rdzenie Tensor H100 SXM zapewniają 494,5 TFLOPS TF32 w trybie gęstym lub 989 w rzadkim; porównując tę wartość, zawsze podawaj precyzję i tryb rzadkości.

Rdzenie CUDA to uniwersalne jednostki zmiennoprzecinkowe i całkowitoliczbowe. Obsługują operacje element po elemencie, funkcje aktywacji i inne obliczenia niemacierzowe, podczas gdy rdzenie Tensor wykonują obsługiwane operacje macierzowe.

Warp to grupa 32 wątków wykonywanych w jednym rytmie na SM, co czyni go najmniejszą jednostką szeregowania w NVIDIA. Specjalizacja warpów przypisuje różne warpy do przesyłania danych i do obliczeń, aby te zadania mogły się nakładać.

NVLink to szybkie połączenie NVIDIA między GPU w obrębie węzła. NVLink 4.0 w H100 zapewnia dwukierunkową przepustowość 900 GB/s; NVLink 5.0 w B200 osiąga 1,8 TB/s. Ta przepustowość ma znaczenie dla tensor parallelism, ponieważ GPU wymieniają częściowe wyniki w każdej warstwie transformera.

InfiniBand to szybka sieć do komunikacji między węzłami. Karty InfiniBand klasy ConnectX stanowią sieć międzywęzłową dla ruchu pipeline parallelism lub treningu rozproszonego; przepustowość zależy od karty i konfiguracji portów.

RDMA (Remote Direct Memory Access) pozwala urządzeniu uzyskać dostęp do pamięci innej maszyny bez kierowania ścieżki danych przez którykolwiek z CPU. GPUDirect RDMA obsługuje bezpośrednie transfery między GPU w różnych węzłach, w tym transfery KV cache w serwowaniu zdezagregowanym.

NVMe (Non-Volatile Memory Express) to interfejs SSD używany do odciążania KV cache oraz parametrów w ZeRO-Infinity, gdy pamięci GPU i CPU nie wystarczają. Przepustowość sekwencyjna zależy od dysku i obciążenia i pozostaje daleko poniżej przepustowości HBM.

TFLOPS i PFLOPS to biliony i biliardy operacji zmiennoprzecinkowych na sekundę. Jeden TFLOPS to 101210^{12} FLOPS. H100 osiąga 989 TFLOPS TF32 w trybie rzadkim, a FlashAttention-3 raportuje około 1,2 PFLOPS w FP8; te wartości dotyczą różnych formatów i nie należy ich porównywać jak jednej metryki.


Część II — Podstawy inferencji

Inferencja zmienia model w usługę widoczną dla użytkownika. Poniższe pojęcia rozdzielają pracę opóźniającą pierwszy token od pracy spowalniającej każdy kolejny token i pokazują limity pamięci stojące za oboma.

4. Opóźnienie: TTFT, TPOT i percentyle

Time to First Token (TTFT) to opóźnienie od wysłania żądania do pierwszego tokena wyjściowego, mierzone end-to-end. Obejmuje kolejkowanie, tokenizację, szeregowanie, przebieg prefill, który tworzy pierwszy token, oraz dostarczenie przez sieć. Popularne silniki serwujące próbkują pierwszy token wyjściowy z logitów przebiegu forward w prefill, więc przed nim nie działa osobny krok decode. Dłuższe prompty zwykle zwiększają składnik prefill, ale dowolny z tych etapów może dominować. Cele zależą od produktu; MLPerf Inference v5.0 stosuje limit P99 TTFT ≤\leq 450 ms w scenariuszu interaktywnym dla Llama 2 70B.

Time Per Output Token (TPOT) to średni odstęp między kolejnymi tokenami po pierwszym. Odpowiada fazie decode. Decode przy batchu o rozmiarze jeden lub o niskiej intensywności jest zwykle ograniczony przepustowością pamięci, natomiast dostatecznie duże batche mogą stać się ograniczone obliczeniami:

TPOT=E2E Latency−TTFTOutput Tokens−1\text{TPOT} = \frac{\text{E2E Latency} - \text{TTFT}}{\text{Output Tokens} - 1}

Ta definicja wymaga co najmniej dwóch tokenów wyjściowych; dla odpowiedzi jednotokenowej TPOT jest niezdefiniowany.

Szybkość czytania wyznacza najwolniejsze użyteczne tempo strumieniowania. Przeciętna szybkość cichego czytania dorosłych po angielsku to około 238 słów na minutę dla tekstów niefabularnych (Brysbaert, 2019), czyli około 4 słów na sekundę. Jeden token to w przybliżeniu trzy czwarte angielskiego słowa (OpenAI), co daje około 5 tokenów na sekundę, czyli 200 ms na token. TPOT wyraźnie poniżej 200 ms sprawia, że strumieniowany tekst wyprzedza czytelnika. Interaktywny scenariusz MLPerf stosuje znacznie ostrzejszy limit P99 TPOT ≤\leq 40 ms. Własny cel ustal na podstawie testów produktu.

Opóźnienie P50 a P99 ma znaczenie, ponieważ mediana ukrywa ogon. System z dobrym P50 i złym P99 może mieć problemy z batchingiem, wywłaszczaniem, kolejkowaniem lub nierównym rozkładem obciążenia; do ich rozróżnienia potrzebne są ślady (traces).

5. Przepustowość: tokeny na sekundę i kompromis z opóźnieniem

Przepustowość mierzy się w tokenach wyjściowych na sekundę dla równoległych żądań. Same żądania na sekundę to słabsza miara, ponieważ odpowiedź 10-tokenowa i 1000-tokenowa mają bardzo różne koszty. Publikowane wyniki benchmarków zależą od modelu, precyzji, sprzętu, długości promptów i odpowiedzi, współbieżności oraz SLO. vLLM, SGLang i TensorRT-LLM porównuj jednym zestawem testowym, zamiast zestawiać ich nagłówkowe wyniki.

Kompromis wygląda tak: przy niskiej współbieżności każde żądanie ma świetne opóźnienie, ale GPU jest niedociążone. Zwiększanie rozmiaru batcha podnosi przepustowość niemal liniowo, dopóki obliczenia się nie nasycą, po czym opóźnienie gwałtownie rośnie. Goodput, czyli liczba żądań na sekundę spełniających cele SLO, łączy surową przepustowość z tym, czego faktycznie doświadczają użytkownicy.

6. KV cache: pamięć rosnąca z każdym tokenem

Podczas generowania autoregresyjnego każdy nowy token odwołuje się do wszystkich poprzednich tokenów. KV cache przechowuje projekcje Key i Value każdego tokena w każdej warstwie, aby uniknąć ponownych obliczeń o złożoności O(n2)O(n^2). Bez niego wygenerowanie tokena nn wymagałoby ponownego przepuszczenia przez model wszystkich n−1n-1 poprzednich tokenów.

KV cache może stać się dominującym zmiennym obciążeniem pamięci przy dużej długości sekwencji lub wysokiej współbieżności, ponieważ rośnie liniowo wraz z długością sekwencji, rozmiarem batcha i liczbą warstw:

KVcache=2×L×hkv×dh×s×B×bytesKVcache = 2 \times L \times h_{kv} \times d_h \times s \times B \times \text{bytes}

gdzie:

  • LL = liczba warstw
  • hkvh_{kv} = liczba głowic KV
  • dhd_h = wymiar głowicy
  • ss = długość sekwencji
  • BB = rozmiar batcha
  • bytes\text{bytes} = liczba bajtów na przechowywany element, wyznaczona przez precyzję KV cache

Konkretne przykłady dla FP16 i batcha o rozmiarze 1: Llama 3.1 8B przy 8192 tokenach zużywa ~1,07 GB (1 GiB) KV cache; przy 128K tokenów to 16 GiB. Llama 3.1 70B przy 128K tokenów potrzebuje 40 GiB (około 43 GB) dla jednej sekwencji, czyli około połowy 80 GB H100. Przy wysokiej współbieżności lub długim kontekście KV cache może przekroczyć pamięć wag modelu; wynik zależy od długości sekwencji, liczby aktywnych sekwencji w batchu, precyzji KV i liczby głowic KV. Naiwne implementacje marnują 60–80% przydzielonej pamięci KV na fragmentację, i właśnie ten problem miał rozwiązać PagedAttention.

Główne optymalizacje to GQA (mniej głowic KV), kwantyzacja KV cache (FP8/INT8), PagedAttention (alokacja blokowa z <4% strat) oraz odciążanie KV cache do CPU lub NVMe.

Aby odpowiedzieć na pytanie „ile sekwencji mieści się w moim budżecie KV?” dla innego modelu, odczytaj z jego config.json trzy liczby: num_hidden_layers, num_key_value_heads i wymiar głowicy (hidden_size / num_attention_heads). Poniższa funkcja stosuje ten wzór; asercje odtwarzają powyższe liczby oraz przykład pojemności w sekcji 45.

def kv_cache_bytes(layers, kv_heads, head_dim, seq_len, batch=1, bytes_per_elem=2):
    """Bytes of KV cache: a key and a value per layer, KV head, and token."""
    return 2 * layers * kv_heads * head_dim * seq_len * batch * bytes_per_elem

GiB = 2**30

# Llama 3.1 8B: 32 layers, 8 KV heads, head dimension 128, FP16 cache.
llama_8b = kv_cache_bytes(32, 8, 128, seq_len=8_192)
print(f"8B at 8K tokens: {llama_8b / 1e9:.2f} GB")  # 1.07 GB
assert llama_8b == 1 * GiB

# Llama 3.1 70B: 80 layers, 8 KV heads, head dimension 128.
assert kv_cache_bytes(80, 8, 128, seq_len=131_072) == 40 * GiB

# How many 4K-token sequences fit in a 40 GiB KV budget?
per_4k = kv_cache_bytes(80, 8, 128, seq_len=4_096)
print(f"70B at 4K tokens: {per_4k / GiB:.2f} GiB per sequence")  # 1.25 GiB
print("4K sequences in 40 GiB:", 40 * GiB // per_4k)  # 32
assert 40 * GiB // per_4k == 32

# An FP8 KV cache halves the size per sequence and doubles the count.
assert 40 * GiB // kv_cache_bytes(80, 8, 128, 4_096, bytes_per_elem=1) == 64

Wynik jest górną granicą. Środowisko uruchomieniowe potrzebuje też pamięci na aktywacje, narzut alokatora i zapas na zmienność długości żądań.

7. Prefill a decode: dwie fazy, dwa wąskie gardła

Faza prefill przetwarza prompt wejściowy równolegle i wypełnia KV cache. Długie lub dostatecznie zbatchowane prefille często stają się ograniczone obliczeniami, ponieważ używają dużych mnożeń macierzy; krótkie prefille mogą pozostać ograniczone ruchem pamięci lub narzutem uruchamiania kerneli. Prefill składa się na czas do pierwszego tokena (TTFT) obok kolejkowania, tokenizacji, szeregowania i dostarczenia przez sieć; jego przebieg forward tworzy też pierwszy token wyjściowy. Faza decode generuje po jednym tokenie. Każdy krok wczytuje wagi modelu i KV cache z HBM, przez co decode przy batchu o rozmiarze jeden jest ograniczony przepustowością pamięci i jest głównym czynnikiem czasu na token wyjściowy (TPOT).

Rysunek przypisuje każdą fazę do metryki, na którą wpływa: prefill kończy się pierwszym tokenem, więc mieści się w TTFT, a każdy kolejny krok decode zwiększa TPOT.

Prefill przetwarza prompt równolegle i emituje pierwszy token, co kończy TTFT; decode generuje następnie po jednym tokenie na krok, wczytując wagi i KV cache z HBM, a każdy kolejny krok zwiększa TPOT.Prefill przetwarza prompt równolegle i emituje pierwszy token, co kończy TTFT; decode generuje następnie po jednym tokenie na krok, wczytując wagi i KV cache z HBM, a każdy kolejny krok zwiększa TPOT.

Chunked prefill dzieli prompt na fragmenty stałego rozmiaru zamiast przetwarzać go w całości. Planista może przeplatać te fragmenty z pracą decode, aby jeden długi prompt nie blokował całej iteracji. Sarathi-Serve raportuje lepsze kompromisy między przepustowością a opóźnieniem w testowanych obciążeniach, ale zysk zależy od modelu, sprzętu, rozkładu długości żądań, rozmiaru fragmentu i punktu odniesienia. Dodatkowe szeregowanie i mniejsze kernele mogą zwiększyć TTFT nowego żądania.

Serwowanie zdezagregowane umieszcza prefill i decode w osobnych pulach GPU, dzięki czemu każda pula może celować w inne wąskie gardło. Wzorzec opisują Splitwise i DistServe. Pule przesyłają dane KV cache szybkim połączeniem, takim jak RDMA, więc koszt komunikacji staje się częścią projektu.

Rysunek pokazuje pierwsze dwa harmonogramy jako oś czasu: jeden długi prompt nadchodzi, gdy inne żądania są w fazie decode.

Dwie osie czasu kroków decode na jednym GPU. Bez dzielenia jeden długi prefill zajmuje około pięciu kroków, a działające decode czekają. Przy chunked prefill każdy krok wykonuje jeden fragment promptu razem z decode.Dwie osie czasu kroków decode na jednym GPU. Bez dzielenia jeden długi prefill zajmuje około pięciu kroków, a działające decode czekają. Przy chunked prefill każdy krok wykonuje jeden fragment promptu razem z decode.

8. GQA i MQA: zmniejszanie KV cache

Standardowy Multi-Head Attention (MHA) daje każdej głowicy zapytań własne głowice K i V. Multi-Query Attention (MQA) współdzieli jedną głowicę KV między wszystkie głowice zapytań, co jest redukcją skrajną. Grouped-Query Attention (GQA) to praktyczny kompromis: grupy głowic zapytań współdzielą jedną głowicę KV. Rysunek przedstawia osiem głowic zapytań i głowice KV, które zachowuje każdy wariant; KV cache maleje proporcjonalnie do liczby głowic KV.

Trzy panele po osiem głowic zapytań. MHA zachowuje osiem głowic KV, po jednej na głowicę zapytań. MQA zachowuje jedną głowicę KV współdzieloną przez wszystkie osiem. GQA zachowuje dwie głowice KV, a każda jest współdzielona przez cztery głowice zapytań.Trzy panele po osiem głowic zapytań. MHA zachowuje osiem głowic KV, po jednej na głowicę zapytań. MQA zachowuje jedną głowicę KV współdzieloną przez wszystkie osiem. GQA zachowuje dwie głowice KV, a każda jest współdzielona przez cztery głowice zapytań.

Llama 3 70B używa 64 głowic zapytań, ale tylko 8 głowic KV, co daje 8-krotne zmniejszenie KV cache w porównaniu z tą samą architekturą z jedną głowicą KV na głowicę zapytań. Llama 3.1 405B używa 128 głowic zapytań i 8 głowic KV, czyli 16-krotnej redukcji według tego samego rachunku (Meta, 2024). Ainslie et al. raportują jakość GQA zbliżoną do MHA w testowanych modelach przy szybkości zbliżonej do MQA. Mniejszy KV cache może obsłużyć większe batche, ale rzeczywisty zysk w opóźnieniu i przepustowości nadal zależy od kernela i obciążenia.

9. Kwantyzacja: wymiana bitów na szybkość i pamięć

Kwantyzacja zmniejsza precyzję wag i/lub aktywacji modelu. Podstawowe kompromisy:

FormatBityPamięć wag (model 7B)Uwaga o jakości
FP16/BF1616~14 GBPunkt odniesienia do porównań
FP88~7 GBNatywny sprzętowo na Hopper; oceń model
INT88~7 GBZależy od kalibracji i kernela
INT44~3,5 GBNajwiększa kompresja; oceniaj ostrożnie

AWQ (Activation-Aware Weight Quantization) wskazuje istotne kanały wag na podstawie wielkości aktywacji i stosuje skalowanie na kanał, aby je chronić. Wymagania kalibracyjne zależą od modelu i konfiguracji; w jednym porównaniu OPT-6.7B INT3-g128 AWQ użył 16 sekwencji kalibracyjnych, a GPTQ 192. W powtarzalnej konfiguracji podawaj zarówno liczbę sekwencji, jak i ich długość. GPTQ wykorzystuje przybliżone informacje drugiego rzędu do kwantyzacji warstwa po warstwie. bitsandbytes potrafi kwantyzować podczas ładowania modelu, bez osobnego przebiegu przygotowawczego; jego format NF4 napędza fine-tuning QLoRA. FP8 na sprzęcie klasy Hopper zmniejsza o połowę pamięć wag względem FP16/BF16, ale jakość i szybkość nadal zależą od modelu, kalibracji i kernela.

Tabela przypisuje każdą metodę do zadania, do którego zwykle pasuje. Przewodnik po kwantyzacji modeli opisuje każdą metodę dogłębnie.

MetodaDane kalibracyjneTypowe zastosowanie
AWQ lub GPTQ (INT4 tylko wagi)Tak, mała próbkaSerwowanie dużego modelu na GPU z ograniczoną pamięcią przez obsługiwany kernel INT4
bitsandbytes NF4NieFine-tuning QLoRA i szybkie eksperymenty
FP8Mała próbka lub skalowanie dynamiczneSerwowanie na GPU Hopper lub nowszych, z kontrolą jakości na zadaniu docelowym
INT8 (W8A8)Tak, dla skal aktywacjiGPU bez FP8, takie jak A100 lub A10G, gdy kernel serwujący to obsługuje

Kernel serwujący może mieć takie samo znaczenie jak algorytm kwantyzacji. Sekcja 10 podaje ograniczony wynik dla Marlin i wyjaśnia, dlaczego zysk zależy od konfiguracji serwowania.


Część III — Optymalizacje inferencji

Optymalizacje z tej części rozwiązują różne ograniczenia. FlashAttention zmniejsza ruch attention do HBM; PagedAttention poprawia alokację KV; continuous batching zapobiega zajmowaniu pojemności batcha przez zakończone sekwencje.

10. Kernele CUDA i fuzja kerneli

Kernel CUDA to funkcja napisana dla GPU, wykonywana równolegle na tysiącach wątków. Gdy CPU wywołuje kernel, GPU rozdziela pracę między swoje SM: każdy SM uruchamia wiele warpów po 32 wątki, a każdy wątek przetwarza fragment danych. Każda operacja w inferencji LLM, od mnożenia macierzy po próbkowanie tokenów, jest w ostatecznym rozrachunku uruchomieniem kernela. Pojedynczy przebieg forward przez model 70B wywołuje setki do tysięcy uruchomień kerneli, a różnica między naiwnym a zoptymalizowanym kernelem może przesądzić, czy system spełni swoje SLO opóźnienia.

Główne kategorie kerneli w serwowaniu LLM:

  • Kernele GEMM do mnożenia macierzy, które dominują w obliczeniach zarówno prefill, jak i decode.
  • Kernele attention, takie jak FlashAttention, które dzielą obliczenia na kafelki, aby pozostać w SRAM zamiast przelewać dane do HBM.
  • Kernele fuzyjne, które łączą wiele operacji (na przykład add + layer norm lub projekcję QKV) w jedno uruchomienie, aby pominąć pośrednie przejścia przez HBM.
  • Kernele próbkowania, które zamieniają logity na identyfikatory tokenów przez próbkowanie top-k, top-p lub z temperaturą.

Jakość kernela może przesądzić, czy skompresowane wagi dają przyspieszenie. Artykuł o Marlin raportuje do 2,8-krotnego przyspieszenia end-to-end względem bazowego FP16 dla testowanych konfiguracji vLLM z kwantyzacją INT4 samych wag. Wynik dotyczy modeli, GPU, rozmiarów batcha i konfiguracji serwowania z artykułu, więc nie jest uniwersalnym zyskiem z INT4.

Triton obniża próg wejścia w pisanie własnych kerneli, udostępniając programowanie GPU przez Pythona zamiast surowego CUDA C++, dzięki czemu optymalizacja na poziomie kerneli staje się osiągalna dla inżynierów ML, a nie tylko dla specjalistów od GPU. Większość optymalizacji z dalszej części tego rozdziału (FlashAttention, kernele fuzyjne, PagedAttention) to albo lepsze kernele, albo mądrzejsze sposoby orkiestracji ich uruchamiania.

Fuzja kerneli łączy kolejne operacje w jeden kernel GPU i pomija pośrednie zapisy do HBM. Typowe fuzje to projekcja QKV, attention z softmaxem, add z RMSNorm (FlashNorm) oraz aktywacja SwiGLU (DeepFusionKernel). Dokładne zyski w liczbie uruchomień i wykorzystaniu zależą od grafu modelu, kompilatora, GPU i frameworka serwującego, więc profiluj wdrożony stos zamiast opierać się na uniwersalnym procencie.

11. FlashAttention: attention dzielone na kafelki, aby mieściło się w SRAM

Standardowe attention materializuje w HBM pełną macierz attention N×NN \times N, co kosztuje pamięć O(N2)O(N^2) i generuje duży ruch pamięci. Pomysł FlashAttention polega na tym, aby tej macierzy w ogóle nie materializować. Dzieli macierze Q, K, V na bloki mieszczące się w SRAM, liczy częściowe attention wewnątrz każdego kafelka i scala wyniki za pomocą softmaxu online (przyrostowo śledzi bieżące maksimum i sumę między blokami). Pamięć spada z O(N2)O(N^2) do O(N)O(N), a odczyty z HBM maleją o rząd wielkości.

Każda wersja celuje w wąskie gardło swojej generacji GPU:

  • FlashAttention v1 (A100, 2022) udowodnił, że idea kafelkowania z softmaxem online działa. Artykuł raportował 2–4-krotne przyspieszenie względem standardowego attention, ale tylko 25–40% wykorzystania GPU, ponieważ planowanie kerneli pozostawiało wiele SM bezczynnych.
  • FlashAttention v2 (A100, 2023) przebudował równoległość tak, aby dzielić pracę po wymiarze sekwencji, a nie po batchu i głowicach. Osiągnął 50–73% wykorzystania na A100, czyli mniej więcej 2 razy szybciej niż v1.
  • FlashAttention v3 (H100 Hopper, 2024) dodał specjalizację warpów (osobne warpy do przesyłania danych i do obliczeń) oraz potokowanie GEMM i softmaxu, aby nakładać wczytywanie z pamięci na obliczenia. Artykuł raportuje do 740 TFLOPS/s w FP16 (75% wykorzystania) i blisko 1,2 PFLOPS/s w FP8 na H100.
  • FlashAttention v4 (B200 Blackwell, 2026) adresuje nowe wąskie gardło: na Blackwell przepustowość rdzeni tensor rośnie tak szybko, że ograniczeniem stają się operacje niemacierzowe (wykładnicze w softmaxie, przeskalowania). FA4 programowo emuluje wykładniczą za pomocą aproksymacji wielomianowych na jednostkach FMA, stosuje warunkowe przeskalowanie, by zmniejszyć narzut, i przechowuje wyniki pośrednie w dedykowanej pamięci tensorowej Blackwell (TMEM) zamiast w rejestrach. Artykuł raportuje około 1,6 PFLOPS na B200 w BF16, 1,3 raza szybciej niż cuDNN 9.13 i 2,7 raza szybciej niż Triton w jego testach.

12. FlashDecoding: zrównoleglenie wąskiego gardła decode

Standardowy FlashAttention utrzymuje zajętość GPU, dzieląc pracę po rozmiarze batcha i długości zapytania. Podczas decode model generuje dokładnie 1 token naraz (długość zapytania = 1). Jeśli rozmiar batcha pomnożony przez liczbę głowic attention jest mniejszy niż łączna liczba SM w GPU (108 w A100), większość GPU stoi bezczynnie, podczas gdy kilka jednostek sekwencyjnie przetwarza historię tokenów.

FlashDecoding rozwiązuje to, dodając nowy wymiar zrównoleglenia: samą długość sekwencji KV. Tnie KV cache na mniejsze fragmenty i rozdziela je między wszystkie bezczynne procesory GPU, by liczyć je równolegle, a następnie scala ich częściowe wyniki redukcją log-sum-exp.

W benchmarku Stanforda dla CodeLlama-34B przy batchu o rozmiarze jeden, z długościami sekwencji od 512 do 64K tokenów, FlashDecoding osiągnął do 8-krotnego przyspieszenia end-to-end względem testowanych punktów odniesienia i utrzymał niemal stałe opóźnienie attention aż do 64K. Wynik jest ograniczony do tego sprzętu i benchmarku, a nie jest ogólną gwarancją dla decode.

13. Continuous batching a static batching

Static batching czeka, aż skończą się wszystkie sekwencje w batchu, zanim zacznie następny, więc krótkie sekwencje marnują cykle GPU, bezczynnie czekając po osiągnięciu końca sekwencji. Continuous batching (wprowadzony w artykule o Orca, OSDI 2022) działa z ziarnistością pojedynczej iteracji: w każdym kroku decode zakończone sekwencje są usuwane, a nowe wstawiane. Rysunek pokazuje cztery sloty batcha w dziesięciu krokach decode przy każdej z polityk.

Dwie siatki czterech slotów batcha w dziesięciu krokach decode. W static batching sloty żądań B, C i D stoją bezczynnie po ich zakończeniu, aż skończy się żądanie A, czyli 17 z 40 slotokroków. W continuous batching nowe żądania E, F i G zajmują każdy zwolniony slot w następnym kroku.Dwie siatki czterech slotów batcha w dziesięciu krokach decode. W static batching sloty żądań B, C i D stoją bezczynnie po ich zakończeniu, aż skończy się żądanie A, czyli 17 z 40 slotokroków. W continuous batching nowe żądania E, F i G zajmują każdy zwolniony slot w następnym kroku.

W benchmarku Anyscale dla OPT-13B zoptymalizowany static batching osiągnął 4-krotność naiwnego punktu odniesienia, continuous batching 8-krotność, a vLLM z continuous batching i PagedAttention 23-krotność (Anyscale, 2023). Continuous batching zwiększa też presję na alokację KV, dlatego często łączy się go z zarządzaniem pamięcią stronicowaną.

14. PagedAttention: pamięć wirtualna dla KV cache

PagedAttention z vLLM stosuje do zarządzania KV cache ideę pamięci wirtualnej z systemów operacyjnych. KV cache dzieli się na bloki stałego rozmiaru (zwykle 16 tokenów), bloki są przydzielane na żądanie w miarę generowania tokenów, a pozycje logiczne (sekwencyjne) są mapowane na fizyczne (rozproszone) miejsca w pamięci przez tablice bloków. Wiele żądań ze wspólnym prefiksem (prompty systemowe, beam search) może wskazywać te same bloki fizyczne. Rysunek pokazuje tablicę bloków dla dwóch żądań ze wspólnym promptem systemowym.

Żądanie A ma bloki logiczne A0 do A2, a żądanie B ma B0 i B1. Tablica bloków mapuje je na rozproszone bloki fizyczne w pamięci GPU; A0 i B0 oba wskazują blok fizyczny 7, który przechowuje wspólny prompt systemowy. Bloki 0, 2, 4 i 6 są wolne.Żądanie A ma bloki logiczne A0 do A2, a żądanie B ma B0 i B1. Tablica bloków mapuje je na rozproszone bloki fizyczne w pamięci GPU; A0 i B0 oba wskazują blok fizyczny 7, który przechowuje wspólny prompt systemowy. Bloki 0, 2, 4 i 6 są wolne.

Wcześniejsze systemy marnowały 60–80% pamięci KV cache na fragmentację i prealokację. PagedAttention obniża to do <4%, co pozwala podnieść przepustowość 2–4 razy przy tym samym opóźnieniu i do 24 razy względem HuggingFace Transformers (vLLM Blog, 2023).

15. Speculative decoding: wiele tokenów w jednym przebiegu forward

W speculative decoding mały model szkicowy (draft) generuje KK tokenów-kandydatów, a następnie duży model docelowy ocenia wszystkie KK pozycji w jednym przebiegu forward. Dekoder akceptuje tokeny szkicu od lewej do prawej z prawdopodobieństwami wyprowadzonymi z rozkładów modelu docelowego i szkicowego. Po pierwszym odrzuceniu próbkuje korektę z rozkładu rezydualnego modelu docelowego i odrzuca pozostałe tokeny szkicu. Ten zmodyfikowany krok próbkowania z odrzucaniem zachowuje rozkład wyjściowy modelu docelowego z dokładnością do numeryki sprzętu; samo dokładne dopasowanie tokenów tego nie zapewnia. Rysunek pokazuje jedną rundę szkicowania i weryfikacji.

Przepływ speculative decoding, w którym model szkicowy proponuje K tokenów, model docelowy ocenia wszystkie w jednym przebiegu, a próbkowanie z odrzucaniem zachowuje zaakceptowany prefiks, przy pierwszym odrzuceniu próbkuje jedną korektę i odrzuca resztę.Przepływ speculative decoding, w którym model szkicowy proponuje K tokenów, model docelowy ocenia wszystkie w jednym przebiegu, a próbkowanie z odrzucaniem zachowuje zaakceptowany prefiks, przy pierwszym odrzuceniu próbkuje jedną korektę i odrzuca resztę.

Zysk jest najbardziej prawdopodobny przy małych batchach serwowania i krótkich szkicach, gdy ocena szkicu jest zdominowana ruchem wag, KV cache lub komunikacji, a nie obliczeniami dodatkowego tokena. Oryginalny artykuł o speculative sampling raportował 2–2,5-krotne przyspieszenie dekodowania dla testowanej konfiguracji Chinchilla 70B; EAGLE-3 raportował do 6,5 raza w swoich testach. Warianty to m.in. Medusa (dodatkowe głowice predykcji, bez osobnego modelu), prompt lookup decoding (dopasowywanie n-gramów do wejścia bez osobnego przebiegu forward modelu szkicowego) i EAGLE (ekstrapolacja na poziomie cech).

Przy dużych batchach dodatkowa praca szkicowania i weryfikacji może zniwelować zysk. Speculative decoding jest najbardziej obiecujący, gdy batch serwowania jest dość mały, a akceptacja szkicu wysoka; benchmarkuj całą pętlę serwowania, a nie samą weryfikację w kernelu.

16. Prefix caching i ponowne użycie KV cache

Zamiast wyrzucać KV cache po zakończeniu żądania, prefix caching zachowuje go do ponownego użycia dla nowych żądań o tych samych tokenach prefiksu. Zmniejsza to zbędny prefill dla promptów systemowych, przykładów few-shot, kontekstu RAG i historii rozmów wieloturowych.

Automatic Prefix Caching w vLLM haszuje bloki KV i używa globalnej tablicy haszy do wyszukiwania. RadixAttention w SGLang utrzymuje drzewo radix zbuforowanych tensorów KV z ziarnistością na poziomie tokena. Oba rozwiązania zależą od powtarzających się prefiksów identycznych co do tokenów, więc obok opóźnienia lub przepustowości raportuj współczynnik trafień.

17. Streaming w praktyce

Streaming wysyła tokeny do klienta w miarę ich generowania, zamiast czekać na całą odpowiedź. Wiele frameworków serwujących udostępnia go przez Server-Sent Events: klient otwiera długotrwałe połączenie HTTP, a serwer wypycha każdy token lub paczkę tokenów jako zdarzenie data:. TTFT określa, kiedy użytkownik po raz pierwszy widzi wynik; TPOT współdecyduje o tym, jak płynnie to wygląda. Cel ustal na podstawie testów produktu i wybranego modelu interakcji.

Po stronie klienta streaming wymusza decyzje o buforowaniu. Renderowanie token po tokenie może powodować drgania obrazu, zwłaszcza przy markdownie lub blokach kodu, które do poprawnego formatowania potrzebują kontekstu wielu tokenów. Typowe wzorce to buforowanie na poziomie słów (akumulacja tokenów do granicy białego znaku), buforowanie na poziomie linii (czekanie na znak nowej linii przed renderowaniem) i buforowanie adaptacyjne (natychmiastowe renderowanie prozy, buforowanie bloków kodu). W OpenAI Chat Completions API opcja stream_options: {"include_usage": true} dodaje końcowy fragment z użyciem tokenów przed komunikatem data: [DONE]. Serwery zgodne z OpenAI mogą się różnić, więc zweryfikuj wybraną implementację.

Chunked prefill to jeden ze sposobów, by długie prefille nie wstrzymywały dostarczania tokenów współbieżnym użytkownikom. Szeregowanie z priorytetem dla decode może chronić żądania w toku, a serwowanie zdezagregowane izoluje prefill i decode w osobnych pulach GPU.


Część IV — Architektura modelu

Architektura wyznacza zapotrzebowanie na pamięć, zachowanie attention i dynamikę treningu, wokół których pracują sekcje o serwowaniu i treningu.

18. Podstawy architektury transformera

Nowoczesny transformer decoder-only (GPT, Llama) to stos identycznych warstw, z których każda ma dwa podbloki: attention i feed-forward. Każdy podblok jest opleciony połączeniem rezydualnym i normalizacją. Rysunek pokazuje jedną warstwę w stylu Llama, w tym dwie ścieżki omijające podblok; komponenty opisano pod nim.

Jedna warstwa dekodera, powtórzona 32 razy w Llama 3 8B: RMSNorm, grouped-query attention z 32 głowicami zapytań i 8 głowicami KV, potem dodawanie, które otrzymuje także wejście warstwy; drugi RMSNorm, sieć feed-forward SwiGLU zawierająca około 81 procent wag projekcji oraz drugie dodawanie, które otrzymuje także wynik attention.Jedna warstwa dekodera, powtórzona 32 razy w Llama 3 8B: RMSNorm, grouped-query attention z 32 głowicami zapytań i 8 głowicami KV, potem dodawanie, które otrzymuje także wejście warstwy; drugi RMSNorm, sieć feed-forward SwiGLU zawierająca około 81 procent wag projekcji oraz drugie dodawanie, które otrzymuje także wynik attention.

Kluczowe komponenty:

Multi-Head Attention pozwala każdemu tokenowi ważyć informacje z tokenów widocznych w masce attention. Wejście jest rzutowane na trzy macierze: Queries (czego szukam?), Keys (co zawieram?) i Values (jaką informację niosę?). Wyniki attention oblicza się następnie jako:

Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V

Iloczyn skalarny QKTQK^T mierzy podobieństwo każdej pary tokenów. Dzielenie przez dk\sqrt{d_k} zapobiega zbytniemu wzrostowi iloczynów skalarnych (co wepchnęłoby softmax w obszary o zanikających gradientach). Softmax zamienia wyniki na prawdopodobieństwa, a mnożenie przez VV daje ważoną kombinację wektorów wartości. Równoległe wykonanie tego w wielu głowicach pozwala modelowi zwracać uwagę na różne zależności jednocześnie (jedna głowica na składnię, inna na koreferencję i tak dalej).

Sieć feed-forward (FFN) przekształca reprezentację każdego tokena niezależnie, po tym jak attention wymieszało informacje między tokenami. Nowoczesne LLM często używają SwiGLU zamiast pierwotnej dwumacierzowej FFN z ReLU:

SwiGLU(x)=(Swish(xWgate)⊙xWup)Wdown\text{SwiGLU}(x) = \left(\text{Swish}(xW_{gate}) \odot xW_{up}\right)W_{down}

SwiGLU ma trzy macierze wag, wobec dwóch w FFN z ReLU, i używa gładkiej funkcji Swish. Korzystają z niego Llama, Mistral i Qwen; Gemma używa przybliżonego GeGLU. Znana reguła dwóch trzecich dotyczy konwencjonalnego bloku z pełnym MHA przy dff≈4dd_{ff} \approx 4d: jego dwie macierze FFN wnoszą około 8d28d^2 parametrów, wobec około 4d24d^2 dla attention. Nie jest to ogólne oszacowanie dla architektur SwiGLU/GQA. W Llama 3 8B d=4,096d=4{,}096, dff=14,336d_{ff}=14{,}336, a osiem głowic key/value sprawia, że FFN ma 3d×dff≈1763d \times d_{ff} \approx 176M parametrów na warstwę, wobec około 42M parametrów projekcji attention: około 81% tych wag projekcji, nie licząc embeddings i normalizacji.

Połączenia rezydualne dodają wyjście każdego podbloku z powrotem do jego wejścia: Output=Input+Sublayer(Input)\text{Output} = \text{Input} + \text{Sublayer}(\text{Input}). Ścieżka pomijająca poprawia propagację sygnału i gradientu przez głębokie stosy.

RMSNorm jest powszechny w nowoczesnych rodzinach LLM. LayerNorm centruje przez odjęcie średniej i skaluje przez odchylenie standardowe. RMSNorm pomija odejmowanie średniej i tylko skaluje; jego artykuł raportuje 7–64% przyspieszenia w testowanych modelach bez utraty wydajności w tych eksperymentach. Umieszczenie pre-norm, czyli normalizacja przed attention lub FFN, jest również powszechne, ponieważ poprawia stabilność gradientów.

Szacowanie liczby parametrów modelu decoder-only:

Total≈V×d+12×L×d2\text{Total} \approx V \times d + 12 \times L \times d^2

gdzie VV to rozmiar słownika, dd to wymiar ukryty, a LL to liczba warstw. Składnik V×dV \times d to macierz wejściowych embeddings; składnik 12×d212 \times d^2 przybliża wagi attention i FFN w każdej warstwie. Dla Llama 3 8B (V=128,256V=128{,}256, d=4,096d=4{,}096, L=32L=32) oszacowanie wynosi około 0.53B+6.44B=6.97B0.53B + 6.44B = 6.97B parametrów. Opublikowana łączna liczba 8,03B jest wyższa, ponieważ przybliżenie pomija szczegóły architektury, takie jak dokładna szerokość FFN i osobna projekcja wyjściowa.

19. Modele decoder-only do generowania ogólnego przeznaczenia

Oryginalny Transformer (2017) miał zarówno enkoder, jak i dekoder. Od tamtej pory dziedzina podzieliła się na trzy rodziny architektur, a jedna z nich stała się domyślną dla generatywnej AI.

RodzinaAttentionCel treninguDziś używana doPrzykłady
Encoder-onlyDwukierunkowePrzewidywanie zamaskowanych tokenówEmbeddings, rerankery, klasyfikatoryBERT, RoBERTa
Encoder-decoderDwukierunkowy enkoder; przyczynowy dekoder z cross-attentionSekwencja na sekwencję (span corruption, T5)Tłumaczenie, rozpoznawanie mowyT5, BART, Whisper
Decoder-onlyPrzyczynowePrzewidywanie następnego tokenaGenerowanie tekstu ogólnego przeznaczenia, czat, kodGPT, Llama

Modele encoder-only używają dwukierunkowego attention: każdy token odwołuje się do każdego innego tokena w obu kierunkach. Daje to bogate reprezentacje do zadań rozumienia, ale nie pozwala generować tekstu autoregresyjnie, więc takie modele służą dziś głównie jako rdzeń modeli embeddings, rerankerów i lekkich klasyfikatorów (na przykład routerów opartych na BERT w RouteLLM).

Modele encoder-decoder oddzielają rozumienie od generowania. Enkoder przetwarza całe wejście z dwukierunkowym attention, a dekoder generuje wyjście autoregresyjnie, odwołując się do reprezentacji enkodera przez cross-attention. Pasuje to do zadań, w których wejście i wyjście są różnymi sekwencjami, takich jak tłumaczenie i rozpoznawanie mowy.

Modele decoder-only (GPT, Llama, Mistral, Gemini) używają przyczynowego (jednokierunkowego) attention: każdy token odwołuje się tylko do poprzednich tokenów. Cztery właściwości uczyniły je domyślnym wyborem do generowania ogólnego przeznaczenia:

  • Ponowne użycie KV cache. Przy przyczynowym attention wcześniejsze tokeny nigdy nie odwołują się do późniejszych, więc ich klucze i wartości pozostają ważne w miarę generowania nowych tokenów. Jeden cache na sekwencję rośnie przez dopisywanie (sekcja 6). Encoder-decoder przechowuje dodatkowo stan cross-attention nad wyjściem enkodera.
  • Trening na surowym tekście. Przewidywanie następnego tokena nie wymaga sparowanego wejścia i wyjścia, więc dowolny korpus tekstu jest danymi treningowymi.
  • Jeden powtarzany blok. Model to stos identycznych warstw dekodera, bez osobnego stosu enkodera ani ścieżki cross-attention do zbudowania, podzielenia i zoptymalizowania.
  • Uczenie w kontekście. Instrukcje, przykłady few-shot i zapytanie są tokenami w jednym prefiksie, więc jeden model może przejąć nowe zadanie z samego promptu.

20. Mixture of experts

MoE zastępuje gęstą FFN w każdej warstwie transformera wieloma mniejszymi ekspertami FFN oraz lekkim routerem bramkującym. Router oblicza wynik dla każdego eksperta (zwykle softmax po wyuczonych projekcjach liniowych) i wybiera top-kk ekspertów na token. Obliczenia wykonują tylko aktywowani eksperci, więc model może mieć ogromną całkowitą pojemność przy niskim koszcie na token. To rzadkie obliczenia warunkowe: łączna liczba parametrów określa, co model może reprezentować, a liczba parametrów aktywnych określa, ile kosztuje jego uruchomienie. Rysunek śledzi jeden token w warstwie MoE z sześcioma ekspertami routowanymi i współdzielonym ekspertem.

Router wybiera dwóch z sześciu ekspertów routowanych dla jednego tokena; eksperci 2 i 5 działają, a pozostała czwórka stoi bezczynnie. Współdzielony ekspert działa dla każdego tokena. Trzy wyjścia są dodawane z wagami wynikającymi z ocen routera.Router wybiera dwóch z sześciu ekspertów routowanych dla jednego tokena; eksperci 2 i 5 działają, a pozostała czwórka stoi bezczynnie. Współdzielony ekspert działa dla każdego tokena. Trzy wyjścia są dodawane z wagami wynikającymi z ocen routera.

ModelParametry łącznieParametry aktywneEksperci (routowani + współdzieleni)Top-kk
Mixtral 8x7B47B~13B8 + 02
DeepSeek-V3671B37B256 + 18

Współdzielony ekspert w DeepSeek-V3 jest aktywowany dla każdego tokena. Dostarcza bazową reprezentację, na której mogą się specjalizować eksperci routowani.

Trening MoE ma trzy powtarzające się problemy: nierównomierne obciążenie, zapadanie się ekspertów (expert collapse) i narzut komunikacji dla expert parallelism. Tradycyjne modele MoE dodają pomocniczą stratę karzącą niezrównoważony routing, ale ta strata może konkurować z głównym celem. DeepSeek-V3 stosuje przede wszystkim strategię na poziomie batcha, bez pomocniczej straty: człony przesunięcia poza propagacją wsteczną obniżają wynik przeciążonych ekspertów i podnoszą wynik tych niedociążonych. Dodaje też niezwykle małą uzupełniającą stratę równoważenia na poziomie sekwencji, aby zapobiec skrajnej nierównowadze w obrębie sekwencji. Artykuł raportuje lepsze zrównoważenie routingu bez głównego kompromisu związanego ze stratą pomocniczą w jego konfiguracji.

21. Tokenizacja: BPE, SentencePiece i tiktoken

LLM nie widzą tekstu. Widzą sekwencje całkowitoliczbowych identyfikatorów tokenów. Tokenizer dzieli surowy tekst na tokeny (fragmenty podsłów) i mapuje każdy na identyfikator. Wybór tokenizera wpływa na jakość modelu, szybkość inferencji i sprawiedliwość wielojęzyczną.

Byte Pair Encoding (BPE) to popularny algorytm. Iteracyjnie scala najczęstsze sąsiadujące pary w korpusie treningowym. Uproszczony przykład:

  1. Zacznij od słownika na poziomie znaków: [l, o, w, e, r, _]
  2. Najczęstsza para to (l, o) → scal w lo → słownik: [l, o, w, e, r, _, lo]
  3. Następna najczęstsza para to (lo, w) → scal w low → słownik zyskuje low
  4. Kontynuuj, aż słownik osiągnie docelowy rozmiar (np. 128K tokenów)

Częste słowa, takie jak „the”, stają się pojedynczymi tokenami, a rzadkie, takie jak „defenestration”, są dzielone na fragmenty podsłów, np. ["def", "en", "est", "ration"]. Kompromis dotyczy rozmiaru słownika względem długości sekwencji.

Trzy implementacje tokenizerów obejmują większość zastosowań produkcyjnych:

  • SentencePiece trenuje bezpośrednio na surowym tekście Unicode, bez pretokenizera specyficznego dla języka. Zachowuje białe znaki za pomocą metasymbolu ▁ i opcjonalnie może się cofnąć do tokenów bajtowych UTF-8. Obsługuje modele BPE i unigram i jest używany przez Llama 1/2, T5 i Mistral.
  • tiktoken to tokenizer OpenAI napisany w Rust, używający BPE na poziomie bajtów. W opublikowanym benchmarku GPT-2 działał 3–6 razy szybciej niż testowana konfiguracja GPT2TokenizerFast. Llama 3 przeszła z SentencePiece na algorytm tiktoken.
  • Hugging Face Tokenizers to szeroko używana biblioteka napisana w Rust, obsługująca BPE, WordPiece i Unigram.

Rozmiar słownika bardzo się różni między rodzinami modeli:

ModelTokenizerRozmiar słownika
GPT-2Byte-level BPE50,257
Llama 2SentencePiece BPE32,000
Llama 3BPE w stylu tiktoken128,256
GPT-4otiktoken o200k_base200,019

Większy słownik zwykle oznacza mniej tokenów dla tego samego tekstu, ale większą macierz embeddings (składnik V×dV \times d w sekcji 18).

Fertility mierzy, ile tokenów tokenizer tworzy na słowo lub inną wybraną jednostkę tekstu. Zależy od konkretnego tokenizera, języka, pisma, normalizacji, domeny i próbki. Mierz ją na reprezentatywnym ruchu, zamiast ekstrapolować z jednego tokenizera lub języka.

22. Okna kontekstu i kodowania pozycyjne

Okno kontekstu to maksymalna liczba tokenów, które model może przetworzyć w jednym przebiegu forward. Mocno urosło:

ModelOkno kontekstuRok
Llama 12,0482023
Llama 3.1128K2024
GPT-4.11,047,5762025
Gemini 2.5 Pro1,048,5762025

Attention porównuje każdą parę widocznych tokenów, ale nic w tym porównaniu nie mówi, jak daleko od siebie leżą. Bez informacji o pozycji enkoder reprezentowałby „the cat sat on the mat” i „the mat sat on the cat” w ten sam sposób. Maska przyczynowa dekodera daje pewien sygnał kolejności, ponieważ każdy token widzi tylko swój prefiks, ale nie koduje odległości. Kodowania pozycyjne dodają pozycję i względną odległość jawnie.

Trzy popularne podejścia to:

  • RoPE (Rotary Position Embeddings) obraca wektory zapytań i kluczy o kąty zależne od pozycji, tak aby ich iloczyn skalarny zależał od pozycji względnej. O wyniku attention nadal decyduje treść tokena; RoPE dodaje informację o pozycji bez wyuczonych bezwzględnych embeddings pozycji. Używają go otwarte rodziny modeli, w tym Llama, Mistral i Qwen.

  • ALiBi (Attention with Linear Biases) pomija modyfikacje embeddings i dodaje karę bezpośrednio do wyników attention: im dalej od siebie leżą dwa tokeny, tym większe ujemne obciążenie. Nie ma wyuczonych parametrów pozycyjnych. W oryginalnym artykule model 1,3B trenowany na sekwencjach 1024-tokenowych osiągał przy 2048 tokenach wyniki porównywalne z modelem z pozycjami sinusoidalnymi trenowanym na 2048. Zachowanie poza modelami i długościami testowanymi w artykule zależy od modelu.

  • YaRN (Yet another RoPE extensioN) rozszerza model RoPE poza jego kontekst treningowy. Grupuje wymiary częstotliwości w trzy kategorie i skaluje każdą inaczej. Artykuł raportuje 10 razy mniej tokenów fine-tuningu i 2,5 raza mniej kroków treningu niż jego punkt odniesienia z interpolacją pozycji.


Część V — Trening i alignment

Ta część rozróżnia cel, który tworzy zdolności, techniki pozwalające treningowi zmieścić się w dostępnym sprzęcie oraz metody kształtujące zachowanie modelu po treningu.

23. Pretraining, fine-tuning i alignment

Pretraining to samonadzorowane przewidywanie następnego tokena na dużym korpusie. Jego zapotrzebowanie na obliczenia obejmuje wiele rzędów wielkości; Llama 3 405B zużyła na przykład 3.8×10253.8 \times 10^{25} FLOPs. Nadzorowany fine-tuning (SFT) dostosowuje wstępnie wytrenowany model do etykietowanych danych specyficznych dla zadania. RLHF / RLAIF wykorzystuje dane o preferencjach do kształtowania zachowania: konwencjonalny potok RLHF zbiera porównania, trenuje model nagrody, a następnie optymalizuje politykę. RLAIF zastępuje część ocen ludzkich informacją zwrotną wygenerowaną przez AI. Rysunek pokazuje trzy etapy oraz osobną ścieżkę destylacji, którą opisuje sekcja 31.

Potok treningowy od pretrainingu z przewidywaniem następnego tokena przez nadzorowany fine-tuning po alignment preferencji, z destylacją jako osobną ścieżką, w której wyrównany model-nauczyciel generuje dane dla mniejszego modelu-ucznia.Potok treningowy od pretrainingu z przewidywaniem następnego tokena przez nadzorowany fine-tuning po alignment preferencji, z destylacją jako osobną ścieżką, w której wyrównany model-nauczyciel generuje dane dla mniejszego modelu-ucznia.

Zapotrzebowanie na obliczenia zależy od rozmiaru modelu, długości sekwencji, ilości danych, optymalizatora i metody. PPO wymaga też więcej stanu modelu niż SFT, ponieważ typowa konfiguracja obejmuje modele polityki, referencyjny, nagrody i krytyka. Pełne ramy decyzyjne dotyczące fine-tuningu opisałem w Przewodniku po fine-tuningu LLM.

24. LoRA i QLoRA: fine-tuning efektywny parametrowo

LoRA zamraża wstępnie wytrenowane wagi i wstrzykuje trenowalne macierze niskiego rzędu AA (r×kr \times k) i BB (d×rd \times r), tak że zaktualizowana waga to W0+BAW_0 + BA. Artykuł o LoRA zredukował GPT-3 175B do około 18 milionów trenowalnych parametrów w swojej konfiguracji. Rząd to parametr strojenia, a nie reguła złożoności zadania; dobieraj go przeglądem jakości i pamięci. Adaptery LoRA można po treningu scalić z wagami bazowymi, aby uniknąć osobnej ścieżki adaptera w inferencji.

QLoRA ładuje model bazowy w 4-bitowej kwantyzacji NF4, a adaptery LoRA trenuje w BF16. NormalFloat4 umieszcza więcej poziomów kwantyzacji blisko zera, gdzie gęstość wag jest największa. W artykule dostrojono model 65B na jednym GPU 48 GB i zaraportowano wyniki zbliżone do swoich 16-bitowych punktów odniesienia. Kompromisy czasu działania i pamięci są specyficzne dla testowanego stosu.

25. Trening mieszanej precyzji

Każdy format zmiennoprzecinkowy dzieli swoje bity na trzy pola: znak (zawsze 1 bit), wykładnik (wyznacza zakres dynamiczny) i mantysa (wyznacza precyzję). Więcej bitów wykładnika oznacza szerszy zakres reprezentowalnych wielkości; więcej bitów mantysy oznacza dokładniejsze rozróżnianie bliskich wartości. Formaty całkowitoliczbowe nie mają wykładnika w ogóle i reprezentują tylko równomiernie rozmieszczone liczby całkowite w stałym zakresie.

FormatBityUkład (S / E / M)ZakresPrecyzjaTypowe zastosowanie
FP32321 / 8 / 23±3.4×1038\pm 3.4 \times 10^{38}~7 cyfr dziesiętnychWagi główne (master), stany optymalizatora (momentum i wariancja Adama)
BF16161 / 8 / 7±3.4×1038\pm 3.4 \times 10^{38}~2 cyfry dziesiętnePreferowany format treningu; ten sam zakres co FP32 i zwykle bez skalowania straty
FP16161 / 5 / 10±65,504\pm 65{,}504~3 cyfry dziesiętneTrening ze skalowaniem straty (starsze GPU); inferencja na sprzęcie sprzed Hopper
FP8 E4M381 / 4 / 3±448\pm 448~1 cyfra dziesiętnaPrzebieg forward na Hopper (H100) — większa precyzja dla wag i aktywacji
FP8 E5M281 / 5 / 2±57,344\pm 57{,}344~0,6 cyfry dziesiętnejPrzebieg wsteczny na Hopper — szerszy zakres dla gradientów
INT88stałoprzecinkowy−128-128 do 127127Dokładne liczby całkowiteKwantyzacja wag po treningu do inferencji (W8A8); kwantyzacja KV cache
INT44stałoprzecinkowy−8-8 do 77Dokładne liczby całkowiteAgresywna kwantyzacja samych wag (AWQ, GPTQ) do inferencji na sprzęcie z ograniczoną pamięcią

BF16 ma ten sam zakres co FP32, ponieważ zakres wyznacza pole wykładnika, a BF16 zachowuje wszystkie 8 bitów wykładnika z FP32. Zamiast tego rezygnuje z bitów mantysy (7 wobec 23), wymieniając precyzję na 2-krotne zmniejszenie pamięci, a jednocześnie unikając wielu problemów z zakresem, które dotykają trening w FP16. FP16 ma tylko 5 bitów wykładnika, co ogranicza jego skończony zakres do około 65K. Wiele gradientów jest natomiast zbyt małych dla FP16 i zanika do zera. Skalowanie straty (loss scaling) mnoży stratę przed propagacją wsteczną, aby te gradienty pozostały reprezentowalne, a następnie przed krokiem optymalizatora je odskalowuje; skalowanie dynamiczne obniża współczynnik, gdy wystąpi przepełnienie. Szerszy zakres wykładnika BF16 zwykle pozwala uniknąć tego wymogu.

Formaty całkowitoliczbowe są rzadko używane w głównej arytmetyce treningu, ponieważ propagacja wsteczna wymaga szerokiego zakresu dynamicznego. Są szeroko stosowane w inferencji, gdzie zamrożone wagi można odwzorować na skalibrowane skale. Kwantyzacja wag do INT4 zmniejsza model 7B z około 14 GB do 3,5 GB, jeszcze przed narzutem środowiska uruchomieniowego; jakość trzeba zmierzyć dla wybranego modelu i metody.

Trening w FP8 na H100 przez Transformer Engine używa E4M3 tam, gdzie liczy się precyzja, i E5M2 tam, gdzie liczy się szerszy zakres. Artykuł FP8-LM raportuje, że jego framework mieszanej precyzji wytrenował GPT-175B o 75% szybciej niż bazowy Megatron-LM w BF16 i o 37% szybciej niż NVIDIA Transformer Engine w testowanej konfiguracji H100. DeepSeek-V3 użył mieszanej precyzji FP8 i zaraportował około $5,6 mln w ekwiwalencie kosztu wynajmu mocy obliczeniowej za końcowy przebieg treningowy, bez B+R i infrastruktury.

26. Gradient checkpointing

Każda warstwa przebiegu forward produkuje wyjście pośrednie zwane aktywacją:

Input→[Layer 1]→activation1→[Layer 2]→activation2→[Layer 3]→output\text{Input} \rightarrow [\text{Layer 1}] \rightarrow \text{activation}_1 \rightarrow [\text{Layer 2}] \rightarrow \text{activation}_2 \rightarrow [\text{Layer 3}] \rightarrow \text{output}

Normalnie wszystkie aktywacje muszą pozostać w pamięci, ponieważ propagacja wsteczna potrzebuje ich do obliczenia gradientów. W głębokim transformerze przechowywane aktywacje mogą zająć więcej pamięci niż same wagi modelu.

Gradient checkpointing wymienia obliczenia na pamięć: odrzuca większość tych aktywacji i oblicza je ponownie w locie podczas propagacji wstecznej. Standardowa strategia (Chen et al., 2016) dzieli sieć o nn warstwach na n\sqrt{n} równomiernie rozmieszczonych segmentów i zapisuje tylko aktywację graniczną każdego segmentu. Te zapisane granice to „checkpointy”. Wszystkie aktywacje pośrednie wewnątrz segmentu są natychmiast odrzucane.

Gdy przebieg wsteczny dociera do warstwy wewnątrz segmentu, jej aktywacje są obliczane ponownie od najbliższego checkpointu. W strategii z równomiernym segmentowaniem zapisana pamięć aktywacji spada z O(n)O(n) do O(n)O(\sqrt{n}). Każdy segment jest przeliczany raz, co kosztuje około jednego dodatkowego przebiegu forward na krok treningu (Chen et al., 2016). Rzeczywiste oszczędności pamięci i narzut ponownego obliczania zależą od modelu, granic checkpointów, długości sekwencji, frameworka i implementacji, więc mierz oba na docelowym przebiegu treningowym. FlashAttention stosuje tę samą zasadę wewnątrz attention, nie materializując pełnej macierzy attention. W HuggingFace włącz to przez gradient_checkpointing=True.

27. Etapy DeepSpeed ZeRO

W standardowym data parallelism każde GPU przechowuje pełną kopię wag modelu, gradientów i stanów optymalizatora. Dla Adama każdy parametr zajmuje 2 bajty na wagę FP16 + 4 bajty na wagę główną FP32 + 4 bajty na momentum + 4 bajty na wariancję + 2 bajty na gradient, czyli 16 bajtów na parametr. Model z 7,5 mld parametrów potrzebuje ~120 GB na GPU, a każde GPU przechowuje to samo. Na 64 GPU to 64 identyczne kopie po 120 GB.

DeepSpeed ZeRO (Zero Redundancy Optimizer) usuwa to powielenie, dzieląc te składniki między GPU zamiast je replikować:

  • Etap 1 — podział stanów optymalizatora. Każde GPU przechowuje tylko 1/N stanów optymalizatora (wagi główne FP32 oraz pierwszy i drugi moment Adama, 12 bajtów/parametr). Gdy GPU musi zaktualizować wagę, aktualizuje tylko swój fragment i rozsyła wynik. Przy poniższych założeniach pamięć spada z ~120 GB do ~41,3 GB na GPU.
  • Etap 2 — dodatkowo podział gradientów. Gradienty (2 bajty/parametr) nie są już sumowane operacją all-reduce na każde GPU. Każde GPU otrzymuje tylko potrzebny mu fragment gradientu przez reduce-scatter. Przy tych samych założeniach pamięć spada do ~28,1 GB na GPU.
  • Etap 3 — dodatkowo podział wag modelu. Każde GPU przechowuje tylko 1/N wag FP16. Przed przebiegiem forward lub wstecznym każdej warstwy GPU wywołuje all-gather, by tymczasowo odtworzyć pełne wagi warstwy z pozostałych GPU, wykonuje obliczenia i odrzuca zebrane wagi. Przy tych samych założeniach pamięć spada do ~15,0 GB na GPU.

Rysunek pokazuje, jaki stan każde GPU przechowuje w całości, a jaki dzieli na każdym etapie.

Siatka czterech wierszy (bez ZeRO oraz etapy 1–3) i trzech kolumn: stany optymalizatora po 12 bajtów na parametr, gradienty po 2 i wagi po 2. Każdy etap dzieli o jedną kolumnę więcej. Dla 7,5B parametrów na 8 GPU pamięć stanu modelu na GPU spada ze 120 GB do 41,3, 28,1 i 15,0 GB.Siatka czterech wierszy (bez ZeRO oraz etapy 1–3) i trzech kolumn: stany optymalizatora po 12 bajtów na parametr, gradienty po 2 i wagi po 2. Każdy etap dzieli o jedną kolumnę więcej. Dla 7,5B parametrów na 8 GPU pamięć stanu modelu na GPU spada ze 120 GB do 41,3, 28,1 i 15,0 GB.

Są to przybliżone wartości stanu modelu dla modelu 7,5B parametrów na 8 GPU (rozmiar świata N=8N=8), z wagami i gradientami FP16 oraz wagami głównymi, momentum i wariancją Adama w FP32. Nie obejmują aktywacji, tymczasowych buforów all-gather, fragmentacji alokatora ani narzutu frameworka i środowiska uruchomieniowego. Granicą obliczeń jest 7.5B×7.5B \times bajty na parametr, przy czym każdy stan jest dzielony przez NN tylko na etapach, które go dzielą.

Aby powtórzyć obliczenie dla innego rozmiaru modelu lub liczby GPU:

def zero_model_state_gb(params_b, n_gpus, stage):
    """Model-state GB per GPU for Adam with FP16 weights and gradients.

    Optimizer states (FP32 master weights, momentum, variance) take 12 bytes
    per parameter, gradients 2, and weights 2. Stage 1 shards the optimizer
    states, stage 2 also the gradients, and stage 3 also the weights.
    """
    optimizer, gradients, weights = 12, 2, 2
    if stage >= 1:
        optimizer /= n_gpus
    if stage >= 2:
        gradients /= n_gpus
    if stage >= 3:
        weights /= n_gpus
    return params_b * (optimizer + gradients + weights)

for stage in range(4):
    print(f"stage {stage}: {zero_model_state_gb(7.5, 8, stage):g} GB per GPU")

assert [zero_model_state_gb(7.5, 8, s) for s in range(4)] == [120.0, 41.25, 28.125, 15.0]
# 70B parameters: Stage 3 on 8 GPUs still needs 140 GB of model state per GPU;
# 16 GPUs bring it to 70 GB, before activations.
assert zero_model_state_gb(70, 8, 3) == 140.0
assert zero_model_state_gb(70, 16, 3) == 70.0

Kompromisem jest komunikacja. Etap 1 dodaje minimalny narzut, a etap 2 zastępuje all-reduce operacją reduce-scatter o podobnym koszcie. Etap 3 wymaga wywołań all-gather przed każdą warstwą zarówno w przebiegu forward, jak i wstecznym, co daje około 1,5 raza większą ilość przesyłanych danych niż standardowy data parallelism.

ZeRO-Infinity rozszerza etap 3, odciążając podzielone stany do pamięci RAM CPU, a nawet do dysków SSD NVMe, co może umożliwić trening modeli z bilionami parametrów na ograniczonych klastrach GPU. Odciążanie do pamięci masowej dodaje koszt PCIe i transferu z dysku; jego zmierzony wpływ zależy od dysku, topologii PCIe, podziału, prefetchingu, nakładania transferów i obciążenia. Używaj go, by spełnić wymagania pojemności, a nie zakładaj stałego spowolnienia, i profiluj docelową konfigurację.

28. FSDP: podział natywny dla PyTorch

Fully Sharded Data Parallel (FSDP) to wbudowana w PyTorch odpowiedź na DeepSpeed ZeRO-3. Dzieli parametry, gradienty i stany optymalizatora między GPU według tej samej podstawowej idei. Mechanika dla każdej warstwy to prosta pętla:

  1. All-gather pełnych parametrów ze wszystkich GPU (tymczasowe odtworzenie kompletnej warstwy).
  2. Obliczenie przebiegu forward lub wstecznego dla tej warstwy.
  3. Zwolnienie zebranych parametrów natychmiast. Każde GPU zachowuje tylko swój fragment.
  4. Reduce-scatter gradientów, aby każde GPU otrzymało tylko przypisany mu fragment gradientu.

Ponieważ FSDP jest natywny dla PyTorch, integruje się bezpośrednio z narzędziami do debugowania, profilerami i torch.compile w PyTorch. Wydajność względem DeepSpeed ZeRO-3 zależy od polityki owijania, topologii komunikacji, ustawień odciążania i rozmiaru modelu, więc porównuj je na tym samym klastrze.

KryteriumFSDP (PyTorch)DeepSpeed ZeRO
Styl kontroliPełny podział przez API PyTorchWybierane etapy ZeRO
OdciążanieOdciążanie do CPUCPU + NVMe przez ZeRO-Infinity
Integracja z frameworkiemNatywny PyTorch, ścieżki torch.compileOsobna biblioteka i system konfiguracji
Test wyboruProfiluj docelowe obciążenie PyTorchProfiluj wymagane funkcje i odciążanie

FSDP2 (2024–2025) to przepisanie, które poprawia integrację z torch.compile dla lepszej fuzji kerneli, dodaje obsługę treningu FP8 przez TorchAO i upraszcza API. Zarówno FSDP, jak i DeepSpeed są dostępne przez HuggingFace Accelerate, co pozwala przełączać się między nimi jedną zmianą konfiguracji.

29. Prawa skalowania i koszt inferencji

Skalowanie Chinchilla (DeepMind, 2022) wykazało przy swoich założeniach optymalną pod względem mocy obliczeniowej alokację na poziomie około 20 tokenów treningowych na parametr. Ten cel nie obejmuje kosztu późniejszego serwowania. Jeśli mniejszy model wytrenowany na większej ilości danych osiąga wymaganą jakość, może kosztować mniej w całym cyklu życia przy dużym wolumenie inferencji.

Jedna ze strategii kosztu w cyklu życia to trening mniejszego modelu na znacznie większej ilości danych:

ModelParametryTokeny treningoweTokeny/parametrTokeny/parametr ÷ 20 (wyliczone)
Chinchilla70B1.4T20:11×
Llama 165B1.4T22:11×
Llama 270B2.0T29:11.4×
Llama 3 8B8B15T1,875:194×
Qwen3-0.6B0.6B36T60,000:13,000×

To wyświetlony stosunek tokenów do parametrów podzielony przez przybliżony punkt 20 tokenów na parametr z artykułu o Chinchilli. Jest to stosunek opisowy, a nie zmierzony mnożnik jakości lub kosztu.

Dla modelu serwowanego przy dużym wolumenie wydanie większej mocy obliczeniowej na trening mniejszego modelu może obniżyć koszt w cyklu życia. Llama 3 8B ilustruje tę strategię, ale to, czy się opłaca, zależy od wymaganej jakości i prognozowanego wolumenu inferencji. „Chinchilla-optymalny” odnosi się do efektywności mocy obliczeniowej treningu, czyli innego celu niż koszt w cyklu życia.

30. RLHF, DPO, GRPO i krajobraz metod alignmentu

Alignment kieruje wstępnie wytrenowany model ku pożądanym instrukcjom, preferencjom i politykom bezpieczeństwa. Sam z siebie nie gwarantuje prawdomówności ani bezpiecznego zachowania. Poniższe metody wymieniają ze sobą złożoność implementacji, wymagania dotyczące danych, eksplorację i stabilność treningu.

Klasyczny potok RLHF: SFT → zebranie ludzkich par preferencji → trening modelu nagrody na tych parach → fine-tuning polityki za pomocą PPO (Proximal Policy Optimization). PPO trzyma w pamięci jednocześnie 4 kopie modeli (polityka, referencyjny, krytyk/model wartości, model nagrody) i jest wrażliwe na hiperparametry. Jest też podatne na reward hacking, gdy model wykorzystuje dziwactwa modelu nagrody, takie jak rozwlekłe, pewnie brzmiące odpowiedzi, zamiast rzeczywiście poprawiać jakość.

DPO (Direct Preference Optimization) pomija wyuczony model nagrody i pętlę RL online, optymalizując bezpośrednio stratę na parach preferencji. To upraszcza potok treningowy. Standardowe DPO jest offline: trenuje na stałym zbiorze danych i nie eksploruje nowych odpowiedzi w pętli aktualizacji. To, czy to ograniczenie ma znaczenie, zależy od zadania i pokrycia danych.

GRPO (Group Relative Policy Optimization, DeepSeek) usuwa wyuczonego krytyka z PPO, generując wiele uzupełnień na prompt i używając nagród względem grupy jako punktu odniesienia. Zmniejsza to obciążenie stanem modelu w porównaniu z typową konfiguracją PPO. W przeciwieństwie do DPO, GRPO jest on-policy: model generuje świeże odpowiedzi w trakcie treningu. DeepSeek-R1 łączy GRPO z RLVR (uczenie ze wzmocnieniem z weryfikowalnych nagród), używając kontroli takich jak odpowiedzi matematyczne, kompilacja kodu i testy jednostkowe. Te nagrody łatwiej poddać audytowi niż wyuczony wynik preferencji, ale niepełne testy i cele zastępcze nadal można wykorzystać.

MetodaTypowy stan modeluSygnał nagrodyOnline/offlineKluczowe ograniczenie
PPO4 (polityka, referencyjny, krytyk, nagroda)Wyuczony model nagrodyOnlineReward hacking, złożone strojenie
DPO2 (polityka, referencyjny)Niejawny (pary preferencji)OfflineBrak eksploracji, stałe dane
GRPO2 z nagrodami regułowymi; 3 z wyuczoną nagrodą (polityka, referencyjny, nagroda)Jawny (reguła/weryfikator lub wyuczony)OnlineZależy od jakości nagrody i informatywnej zmienności wewnątrz grupy

31. Destylacja: kompresja wiedzy między modelami

Destylacja wiedzy przenosi zdolności z dużego nauczyciela na mniejszego ucznia. Destylacja oparta na logitach trenuje ucznia tak, by dopasował rozkład wyjściowy nauczyciela. Destylacja oparta na danych polega na tym, że nauczyciel generuje przykłady, na których uczeń jest dostrajany. Metody oparte na danych są popularne w LLM, ponieważ działają między architekturami i z nauczycielami dostępnymi tylko przez API, ale ich wartość jest ograniczona jakością nauczyciela, pokryciem danych, filtrowaniem i kosztem generowania.

DeepSeek-R1 wyselekcjonował mieszankę około 800 000 przykładów — około 600 000 próbek związanych z rozumowaniem i 200 000 bez rozumowania — i użył jej do destylacji modeli Qwen2.5 i Llama 3 od 1,5B do 70B parametrów. W ewaluacji z artykułu:

  • DeepSeek-R1-Distill-Qwen-32B uzyskuje 72,6% na AIME 2024 i 94,3% na MATH-500, powyżej zaraportowanych w artykule wyników OpenAI o1-mini.
  • DeepSeek-R1-Distill-Qwen-7B uzyskuje 55,5% na AIME 2024, powyżej wyniku QwQ-32B-Preview zaraportowanego w artykule, przy mniejszym modelu.

W eksperymentach DeepSeek-R1 z małymi modelami destylacja przewyższyła bezpośrednie GRPO na testowanych modelach bazowych. Wynik ten wspiera destylację w tej konfiguracji; nie ustanawia uniwersalnego rankingu między destylacją a RL.

32. Generowanie danych syntetycznych

Dane treningowe generowane przez LLM są używane w kilku powtarzających się wzorcach:

  • Self-Instruct startuje od małego zbioru zalążkowego instrukcji napisanych przez ludzi: LLM generuje nowe instrukcje, wejścia i wyjścia, które są filtrowane i dodawane z powrotem do puli. Projekt Alpaca użył 52 000 przykładów wygenerowanych ze 175 zalążków. Stanford zaraportował koszt generowania danych poniżej 500ifine−tuninguponiz˙ej500 i fine-tuningu poniżej 100, co daje początkowy koszt odtworzenia poniżej $600; porównanie z GPT-3.5 było ograniczoną oceną projektu, a nie szeroką równoważnością.
  • Evol-Instruct (WizardLM) bierze istniejące instrukcje i iteracyjnie rozwija je wzdłuż osi złożoności (dodawanie ograniczeń, pogłębianie rozumowania, konkretyzowanie problemów), aby tworzyć coraz trudniejsze przykłady treningowe.
  • Phi-4 Microsoftu (14B) użył danych syntetycznych w dużej części pretrainingu, w tym generowania, krytyki, samodzielnej rewizji i odwracania instrukcji. Jego raport techniczny porównuje uzyskane wyniki w STEM i kodowaniu z większymi modelami na wybranych benchmarkach.

Istotnym ryzykiem jest tu zapadanie się modelu (model collapse): gdy modele są rekurencyjnie trenowane na danych syntetycznych z poprzednich generacji, ogony oryginalnego rozkładu stopniowo znikają. Model przecenia typowe wzorce i traci rzadkie, ale ważne warianty (Shumailov et al., 2024). Odrębne badanie klasyfikatora Ahrefs pobrało w kwietniu 2025 jedną nowo wykrytą angielską stronę na domenę z 900 000 stron i zaklasyfikowało 74,2% jako zawierające jakiś tekst wygenerowany przez AI. To badanie dostawcy nie jest spisem całego internetu. Łagodzenie zaczyna się od mieszania danych syntetycznych z rzeczywistymi, filtrowania i śledzenia pochodzenia, tak aby rekurencyjnie wygenerowany materiał dało się zmierzyć.


Część VI — Skalowanie i wdrażanie

Gdy obciążenie przestaje mieścić się na jednym urządzeniu lub spełniać na nim swoje SLO, pozostają trzy wybory: jak podzielić pracę, które środowisko udostępnia potrzebne mechanizmy kontroli i czy każde żądanie wymaga tego samego modelu.

33. Cztery formy parallelism

Cztery formy różnią się tym, jaką część modelu przechowuje każde GPU, i tym, co przechodzi przez łącze między GPU. Rysunek pokazuje każdą z nich na dwóch GPU.

Cztery panele, każdy z GPU 0 i GPU 1. Data parallelism: oba przechowują pełny model i obsługują osobne żądania. Tensor parallelism: każde przechowuje połowę każdej macierzy wag, a all-reduce wykonują w każdej warstwie. Pipeline parallelism: GPU 0 przechowuje warstwy 1–40, a GPU 1 warstwy 41–80, przy czym aktywacje przechodzą między nimi. Expert parallelism: każde przechowuje połowę ekspertów, a tokeny przemieszczają się all-to-all.Cztery panele, każdy z GPU 0 i GPU 1. Data parallelism: oba przechowują pełny model i obsługują osobne żądania. Tensor parallelism: każde przechowuje połowę każdej macierzy wag, a all-reduce wykonują w każdej warstwie. Pipeline parallelism: GPU 0 przechowuje warstwy 1–40, a GPU 1 warstwy 41–80, przy czym aktywacje przechodzą między nimi. Expert parallelism: każde przechowuje połowę ekspertów, a tokeny przemieszczają się all-to-all.

Tensor Parallelism (TP) dzieli poszczególne macierze wag między GPU i zwykle komunikuje się po każdej warstwie. Szybkie łącza wewnątrzwęzłowe, takie jak NVLink, czynią go najbardziej praktycznym w obrębie węzła. Więcej fragmentów zmniejsza pamięć i obliczenia na urządzenie, ale zwiększa komunikację, więc stopień podziału dobierz benchmarkiem opóźnienia.

Pipeline Parallelism (PP) dzieli warstwy sekwencyjnie między GPU, przekazując aktywacje między etapami. Jego wzorzec komunikacji może działać między węzłami, ale bąble w potoku i nierówne czasy etapów obniżają wykorzystanie. Duże wdrożenia często łączą TP w obrębie węzła z PP między węzłami.

Data Parallelism (DP) replikuje serwowany model, tak że każda replika obsługuje niezależne żądania bez komunikacji między replikami na żądanie. Jest wydajny, gdy model się mieści, a ruch można zrównoważyć. W treningu DP często łączy się z ZeRO lub FSDP, aby podzielić stan.

Expert Parallelism (EP) rozdziela ekspertów MoE między GPU, używając komunikacji all-to-all do routingu tokenów. Jego wydajność zależy od równowagi tokenów, rozmieszczenia ekspertów i topologii połączeń; ruch all-to-all może stać się dominującym wąskim gardłem.

Punkt wyjścia przy doborze parallelism:

  • Model mieści się na jednym GPU: zacznij od niezależnych replik i zmierz skalowanie DP.
  • Model mieści się w jednym węźle: przetestuj TP w obrębie węzła, a potem powiel grupę, jeśli ruch tego wymaga.
  • Model obejmuje wiele węzłów: przetestuj kombinację TP i PP względem połączeń i celu opóźnienia.
  • Mixture of experts: dodaj EP tylko wtedy, gdy rozmieszczenie ekspertów tego wymaga.

Poniższa mapa decyzji rysuje tę samą heurystykę jako pytania o dopasowanie modelu.

Przepływ decyzyjny wybierający data, tensor, pipeline lub expert parallelism na podstawie dopasowania modelu, granic węzłów i architektury mixture-of-experts.Przepływ decyzyjny wybierający data, tensor, pipeline lub expert parallelism na podstawie dopasowania modelu, granic węzłów i architektury mixture-of-experts.

34. Porównanie frameworków serwujących

Środowisko uruchomieniowe decyduje, które z optymalizacji z części III dostajesz bez pisania kerneli. Użyj tabeli, aby wybrać pierwsze do benchmarku, a potem porównaj je z jedną alternatywą na tych samych promptach, długościach odpowiedzi, sprzęcie i SLO.

ŚrodowiskoUżyj, gdySprawdź najpierw
vLLMOgólne serwowanie na GPU z API zgodnym z OpenAIDocelowy model i GPU w aktualnej macierzy zgodności
SGLangRuch współdzieli długie prefiksy (prompty systemowe, czat wieloturowy, agenci) lub wymaga ustrukturyzowanych danych wyjściowychWspółczynnik trafień cache prefiksów na własnym ruchu
TensorRT-LLMFlota jest wyłącznie NVIDIA, a najniższe opóźnienie ważniejsze od przenośnościObsługa Twojego modelu i precyzji (FP8, FP4)
llama.cppCPU, Apple silicon lub pojedyncze GPU konsumenckie, z modelami skwantyzowanymi w GGUFTokeny na sekundę z jego narzędzia do benchmarków na docelowej maszynie
OllamaLokalny development i demonstracjePrzejdź na środowisko serwujące przed dużą współbieżnością lub pracą nad SLO

Ten sam wybór jako uporządkowana lista:

  1. Jedna maszyna lokalna lub jedno GPU konsumenckie: zacznij od llama.cpp, a do developmentu od Ollama.
  2. Wyłącznie NVIDIA i najważniejsze jest najniższe opóźnienie: TensorRT-LLM.
  3. Długie wspólne prefiksy lub ustrukturyzowane dane wyjściowe: SGLang.
  4. W pozostałych przypadkach: vLLM.

Przetestuj pierwszy wybór na własnych promptach, długościach wyjścia, sprzęcie i SLO.

vLLM zapewnia stronicowaną alokację KV, continuous batching, API zgodne z OpenAI i kilka trybów parallelism. Jego obsługa modeli i sprzętu często się zmienia.

SGLang łączy RadixAttention do ponownego użycia prefiksów, własny scheduler i generowanie strukturalne. Jego publikowane zyski przepustowości zależą od obciążenia i konfiguracji.

TensorRT-LLM celuje w niskie opóźnienie pojedynczego żądania dzięki fuzji grafów CUDA i optymalizacji kerneli, z natywną obsługą FP8/FP4. Obecne wydania ładują checkpoint Hugging Face bezpośrednio przez backend PyTorch jego API LLM i trtllm-serve; starsze budowanie silnika z wyprzedzeniem to opcja przestarzała. Jego publikowane wyniki są specyficzne dla sprzętu i modelu, a działa tylko na GPU NVIDIA.

TGI jest w trybie utrzymaniowym. Jego README zaleca vLLM, SGLang, llama.cpp lub MLX dla nowych wdrożeń.

Ollama stawia na prosty lokalny przepływ pracy z modelami.

llama.cpp to przenośne środowisko C/C++ ze ścieżkami ARM, x86, Metal, CUDA, ROCm i Vulkan. GGUF obsługuje kilka poziomów kwantyzacji. Wydajność mocno zależy od modelu, kwantyzacji, kontekstu i backendu.

35. Wybór GPU do inferencji

Tabela porównuje publikowane charakterystyki sprzętu. Obsługa precyzji deklarowana przez producenta nie sprawia, że szczytowe wartości obliczeniowe są bezpośrednio porównywalne między formatami, więc wybieraj najpierw według dopasowania pamięci i benchmarkuj docelowe obciążenie. Aktualne ceny chmurowe sprawdzaj osobno, ponieważ zależą od dostawcy, regionu, zobowiązania i dostępności.

GPUPamięćPrzepustowośćNatywna niska precyzjaNVLink na GPU
B200 SXM180 GB HBM3eDo 8 TB/sFP4, FP81,8 TB/s
H200 SXM141 GB HBM3e4,8 TB/sFP8900 GB/s
H100 SXM80 GB HBM33,35 TB/sFP8900 GB/s
A100 80 GB SXM80 GB HBM2e2,039 TB/sINT8 (bez FP8)600 GB/s
L40S48 GB GDDR6864 GB/sFP8Brak
A10G (AWS G5)24 GB GDDR6600 GB/sINT8 (bez FP8)Brak
RTX 409024 GB GDDR6X~1 TB/sFP8Brak

Przepustowość A10G pochodzi ze specyfikacji NVIDIA A10, a wartość dla RTX 4090 (1008 GB/s) z białej księgi architektury Ada.

Pojemność 141 GB w H200 może uprościć niektóre wdrożenia dużych modeli. Karty GDDR w dolnych wierszach mają jedną trzecią przepustowości H100 lub mniej i nie mają NVLink, więc lepiej nadają się do modeli skwantyzowanych, które mieszczą się na jednym GPU, niż do modeli wymagających tensor parallelism.

AWQ i GPTQ serwują modele 4-bitowe, dekwantyzując obsługiwane operacje macierzowe do formatu obliczeniowego, takiego jak FP16 lub BF16. Zgodność i szybkość nadal zależą od architektury modelu, formatu kwantyzacji, backendu serwującego, kernela i GPU, więc sprawdź macierz wsparcia backendu i zbenchmarkuj dokładnie ten artefakt. Wszystkie wymienione GPU obsługują operacje macierzowe INT8.

Decode LLM jest często ograniczony przepustowością pamięci, więc pojemność i przepustowość HBM mogą mieć w obciążeniach serwujących większe znaczenie niż szczytowe TFLOPS. Porównuj GPU przy stałym modelu, precyzji, rozkładzie batcha, długości kontekstu i celu opóźnienia.

36. Kaskadowanie modeli i routing

Routing modeli wybiera, który LLM obsłuży każde zapytanie, na podstawie przewidywanej złożoności lub zdolności. RouteLLM (LMSYS/UC Berkeley, ICLR 2025) raportuje 85% redukcji kosztów w swojej konfiguracji MT-Bench przy zachowaniu 95% jakości bazowej GPT-4. To, czy routing się opłaca, zależy od aktualnych cen, mieszanki ruchu, błędów routera i minimalnej akceptowalnej jakości.

Routery obejmują od lekkich klasyfikatorów po sędziów opartych na LLM. Kaskadowanie to wariant sekwencyjny: zapytanie zaczyna od tańszego modelu i przechodzi wyżej, gdy funkcja oceniająca odrzuci odpowiedź. FrugalGPT raportuje do 98% niższego kosztu lub do 4% wyższej dokładności w ocenianej puli modeli. Kaskada produkcyjna wymaga skalibrowanych kryteriów eskalacji i monitorowania zapytań, które tani model błędnie akceptuje. Rysunek pokazuje, gdzie każde z podejść dokonuje wyboru.

Dwa przepływy. Routing: router pyta, czy zapytanie jest trudne, i kieruje je do mocnego albo taniego modelu, więc działa jeden model. Kaskadowanie: tani model zawsze działa pierwszy; ewaluator sprawdza odpowiedź, zwraca ją, jeśli wynik osiąga próg, a w przeciwnym razie eskaluje do mocnego modelu.Dwa przepływy. Routing: router pyta, czy zapytanie jest trudne, i kieruje je do mocnego albo taniego modelu, więc działa jeden model. Kaskadowanie: tani model zawsze działa pierwszy; ewaluator sprawdza odpowiedź, zwraca ją, jeśli wynik osiąga próg, a w przeciwnym razie eskaluje do mocnego modelu.


Część VII — Aplikacje

Aplikacje zawodzą w miejscach, których stos serwujący nie widzi. Wyszukiwanie może zawieść, zanim zacznie się generowanie, agenci mogą wybrać niepoprawną akcję, a zmiana promptu może poprawić jedno zadanie i zepsuć inne.

37. Modele embeddings a modele generatywne

Modele embeddings kodują tekst w wektory o stałej liczbie wymiarów, które oddają znaczenie semantyczne. W odróżnieniu od modeli generatywnych, które produkują sekwencje tokenów, zwracają jeden gęsty wektor dla wejścia, zwykle o liczbie wymiarów od kilkuset do kilku tysięcy. Ich rdzeniem są dwukierunkowe transformery encoder-only oraz modele wywodzące się z dekoderów, dostosowane do uczenia reprezentacji. Warstwa poolingu często sprowadza reprezentacje poszczególnych tokenów do jednego wektora przez uśrednianie, specjalny token klasyfikacyjny lub metodę ostatniego tokena zależną od modelu. Kontrastowy fine-tuning przybliża następnie teksty podobne semantycznie i oddala niepodobne.

Obecne modele embeddings różnią się właściwościami, które wyznaczają koszt przechowywania i wybór indeksu: liczbą wymiarów wyjściowych, akceptowanymi typami wejścia, sposobem wdrożenia i precyzją wyjścia.

ModelMaks. wymiarówWejścieWagiNatywna precyzja wyjścia
Qwen3-Embedding-8B4,096 (32–4,096 przez MRL)TekstOtwarte (Apache 2.0)Float
Gemini Embedding 23,072 (128–3,072)Tekst, obraz, wideo, audio, PDFAPINie podano
pplx-embed-v1-4B2,560 (MRL)TekstOtwarte (MIT)INT8 i binarna
OpenAI text-embedding-3-large3,072 (skracane przez dimensions)TekstAPIFloat

To przykłady, a nie ranking. Oceń język, modalność, zadanie, liczbę wymiarów i koszt serwowania na jednym zbiorze wyszukiwania.

Matryoshka Representation Learning (MRL, Kusupati et al., NeurIPS 2022) czyni wymiary embeddings elastycznymi. Nazwana od rosyjskich lalek matrioszek, MRL strukturyzuje embedding tak, aby jego pierwsze mm wymiarów było tak samo informatywne jak niezależnie wytrenowany model mm-wymiarowy. Podczas treningu MRL agreguje straty po wybranym zbiorze O(log⁡d)O(\log d) wymiarów prefiksowych, zwykle kolejnych połowieniach; przykład 2048-wymiarowy z artykułu używa {8,16,…,1024,2048}\{8, 16, \ldots, 1024, 2048\}. Zagregowana strata skłania początkowe wymiary do niesienia zgrubnej informacji semantycznej, a późniejsze dodają drobniejsze szczegóły.

Po treningu embedding MRL można obciąć do obsługiwanego wymiaru prefiksowego. OpenAI raportuje, że text-embedding-3-large przy 256 wymiarach przewyższa text-embedding-ada-002 przy 1536 wymiarach w cytowanym porównaniu MTEB. Daje to 6-krotne zmniejszenie surowego miejsca na wektory; opóźnienie wyszukiwania i koszt bazy danych zależą też od indeksu, metadanych, filtrowania i sprzętu.

Model embeddings to jeden z ważnych komponentów potoku RAG, obok parsowania, dzielenia na fragmenty, wyszukiwania, rerankingu i generowania. Jeśli odpowiednie dowody nie zostaną pobrane, mocniejszy generator nie jest w stanie ich wiarygodnie odtworzyć.

38. Architektura RAG w produkcji

Retrieval-Augmented Generation dostarcza LLM dokumenty pobrane w czasie zapytania. Może zapewnić aktualne lub prywatne dowody, których nie ma w wagach modelu, ale samo wyszukiwanie nie gwarantuje, że odpowiedź użyje tych dowodów poprawnie. Produkcyjny system RAG to wieloetapowy potok, którego etapy wymagają osobnej ewaluacji. Rysunek pokazuje ścieżkę ingestii offline i ścieżkę wykonywaną dla każdego zapytania.

Architektura RAG. Offline: parsowanie i dzielenie dokumentów na fragmenty, embedding fragmentów i zapis wektorów w indeksie. Dla każdego zapytania: embedding pytania użytkownika tym samym modelem, opcjonalnie po przeformułowaniu go za pomocą HyDE lub rozszerzenia multi-query, hybrydowe wyszukiwanie gęste i BM25 w indeksie, reranking najlepszych kandydatów i odpowiedź LLM na podstawie najlepszych fragmentów.Architektura RAG. Offline: parsowanie i dzielenie dokumentów na fragmenty, embedding fragmentów i zapis wektorów w indeksie. Dla każdego zapytania: embedding pytania użytkownika tym samym modelem, opcjonalnie po przeformułowaniu go za pomocą HyDE lub rozszerzenia multi-query, hybrydowe wyszukiwanie gęste i BM25 w indeksie, reranking najlepszych kandydatów i odpowiedź LLM na podstawie najlepszych fragmentów.

Potok ingestii działa offline. Surowe dokumenty (PDF, HTML, Markdown, bazy danych) są najpierw parsowane do czystego tekstu. Parsowanie PDF może gubić tabele, nagłówki i formatowanie. Tekst jest następnie dzielony na fragmenty (chunks), które są niezależnie embedowane i indeksowane.

Dzielenie na fragmenty wpływa zarówno na recall wyszukiwania, jak i na kontekst dostępny dla generatora. Użyteczne rozmiary zależą od struktury dokumentu, ziarnistości zapytań, limitów modelu embeddings i limitów rerankera. Typowe podejścia to stały rozmiar z nakładką, rekurencyjny podział wzdłuż granic dokumentu i chunking semantyczny według podobieństwa embeddings. Porównuj je na etykietach trafności na poziomie stron lub sekcji, zamiast przyjmować jeden zakres tokenów uniwersalnie.

Każdy fragment jest następnie embedowany modelem takim jak te z sekcji 37 i zapisywany w indeksie wektorowym. pgvector trzyma wektory w już działającej bazie Postgres. Dedykowany magazyn, taki jak Qdrant, Weaviate lub Pinecone, dodaje wbudowane wyszukiwanie hybrydowe i skaluje indeks niezależnie od bazy danych aplikacji.

Potok wyszukiwania działa w czasie zapytania. Zacznij od mierzalnej wersji bazowej, a potem dodawaj etapy, gdy analiza błędów pokaże, że rozwiązują realną lukę:

  • Wyszukiwanie hybrydowe łączy gęste wyszukiwanie wektorowe z rzadkim, takim jak BM25, często scalane przez Reciprocal Rank Fusion (RRF). Wyszukiwanie gęste radzi sobie z parafrazami semantycznymi; rzadkie wyłapuje dokładne identyfikatory, kody błędów i akronimy. Benchmarki dostawców raportują zyski względem baz opartych tylko na wektorach, ale ich wielkość zależy od korpusu i etykiet trafności.
  • Reranking przepuszcza pobranych kandydatów przez model, który ocenia zapytanie i dokument razem. Może to poprawić trafność w drobnych szczegółach kosztem kolejnego wywołania modelu. Liczbę kandydatów, liczbę zachowanych i opóźnienie należy stroić razem. Pełny wieloetapowy potok opisałem w Budowie nowoczesnego stosu rankingu wyszukiwania.
  • Transformacja zapytania przeformułowuje zapytanie użytkownika przed wyszukiwaniem, aby poprawić recall. HyDE (Hypothetical Document Embeddings) każe LLM wygenerować hipotetyczną odpowiedź, która jest następnie embedowana i używana do wyszukiwania. Rozszerzenie multi-query generuje wiele sformułowań tego samego pytania. Step-back prompting najpierw zadaje bardziej ogólne pytanie, aby pobrać szerszy kontekst.

Typowe tryby awarii:

  • Porażka wyszukiwania — poprawny dokument istnieje, ale nie zostaje pobrany. Przetestuj dzielenie na fragmenty, transformację zapytania, wyszukiwanie hybrydowe i filtrowanie po metadanych pod kątem tej luki.
  • Zatrucie kontekstu — nietrafne pobrane fragmenty wprowadzają LLM w błąd. Przetestuj reranking, filtry kontekstu i mniejsze zbiory zachowanych fragmentów.
  • Lost-in-the-middle — w testowanych ustawieniach wielodokumentowego odpowiadania na pytania i wyszukiwania klucz-wartość Liu et al. stwierdzili, że skuteczność odpowiedzi była zazwyczaj najwyższa, gdy istotna informacja pojawiała się blisko początku lub końca wejścia, a niższa, gdy znajdowała się w środku.

GraphRAG (Microsoft, 2024) uzupełnia wyszukiwanie wektorowe o wyodrębniony graf encji i relacji. Celuje w pytania na poziomie korpusu i silnie relacyjne, które płaskie wyszukiwanie fragmentów może pomijać. Kompromisem jest dodatkowa praca nad ekstrakcją, indeksowaniem, przechowywaniem i ewaluacją.

Poradniki praktyków podają zakresy opóźnień dla embeddingu, wyszukiwania, rerankingu i generowania, ale te wartości zależą od regionu, korpusu, sprzętu i modelu. Mierz każdy etap w śladach (traces) i oceń zmianę jakości, zanim zaakceptujesz dodatkowe opóźnienie.

39. Architektury agentów i wywoływanie narzędzi

Agenci LLM używają modeli do wyboru i układania w sekwencje wywołań narzędzi wokół zmieniającego się stanu. Trzy użyteczne wzorce orkiestracji to:

  • ReAct — przeplata wybór akcji z obserwacjami. Może się dostosować po każdym wyniku narzędzia, ale rosnąca historia podnosi koszt tokenów i opóźnienie.
  • ReWOO — planuje wywołania narzędzi z symbolami zastępczymi, wykonuje niezależną pracę równolegle, a potem syntetyzuje wynik. Jego artykuł raportuje oszczędności tokenów względem ReAct, ale stały plan wymaga jawnej ścieżki naprawczej, gdy narzędzie zawiedzie.
  • Planner-executor — oddziela planowanie od wykonania i może dodać politykę ponownego planowania po awarii. Pozwala użyć innego modelu dla każdej roli, ale dodaje stan planu i drugie wywołanie modelu, które może zawieść.
WzorzecTendencja tokenówZdolność adaptacjiUżyteczny punkt wyjścia
ReActWyższaAktualizuje się po obserwacjachNiepewne lub eksploracyjne użycie narzędzi
ReWOONiższaStały plan, chyba że rozszerzonyPrzewidywalna praca z równoległymi krokami
Planner-executorŚredniaMoże zmienić jawny planDłuższe zadania, które zyskują na kontroli

Rysunek przedstawia trzy wzorce, aby było widać, gdzie każdy z nich planuje i czy ma drogę powrotną po wyniku narzędzia.

Trzy przepływy. ReAct zapętla myślenie, działanie i obserwację, a każda obserwacja zasila kolejną myśl. ReWOO planuje wszystkie wywołania narzędzi raz, z symbolami zastępczymi, uruchamia narzędzia równolegle i pisze odpowiedź, bez krawędzi powrotnej. Planner-executor pisze plan krok po kroku, wykonuje następny krok i wraca do planera, aby zaplanować na nowo, gdy krok zawiedzie.Trzy przepływy. ReAct zapętla myślenie, działanie i obserwację, a każda obserwacja zasila kolejną myśl. ReWOO planuje wszystkie wywołania narzędzi raz, z symbolami zastępczymi, uruchamia narzędzia równolegle i pisze odpowiedź, bez krawędzi powrotnej. Planner-executor pisze plan krok po kroku, wykonuje następny krok i wraca do planera, aby zaplanować na nowo, gdy krok zawiedzie.

Function calling to częsty mechanizm wywoływania narzędzi. API udostępniają definicje narzędzi i zwracają ustrukturyzowane argumenty, co zmniejsza potrzebę parsowania swobodnego tekstu. Argumenty zgodne ze schematem nadal mogą wskazywać złe narzędzie lub zawierać niepoprawne wartości. Równoległe function calling może zmniejszyć liczbę rund komunikacji, gdy operacje są niezależne.

Ustrukturyzowane dane wyjściowe i constrained decoding wymuszają schemat, ograniczając tokeny dostępne w każdym kroku generowania. Silniki takie jak xgrammar, używany w vLLM i SGLang, mogą usunąć wiele błędów składni i parsowania przy niskim narzucie w obsługiwanych konfiguracjach. Nie gwarantują, że wyodrębnione wartości lub decyzje są poprawne. Schema-Guided Reasoning (SGR) wykorzystuje kolejność pól i strukturę schematu, aby stan pośredni można było sprawdzić przed decyzją końcową. Jego trzy wzorce to Cascade (kroki sekwencyjne), Routing (typy unijne jako semantyczne przełączniki) i Cycle (listy ograniczone).

Jakość doboru narzędzi, opóźnienie end-to-end i koszt tokenów zwykle pogarszają się wraz ze wzrostem zbioru narzędzi i głębokości akcji. Zmierz te krzywe na rzeczywistych opisach narzędzi i rozkładzie błędów. Frameworki takie jak LangGraph mogą uczynić stan i ścieżki naprawcze jawnymi, ale nie zdejmują z Ciebie ciężaru ewaluacji.

40. Inżynieria promptów w produkcji

Prompting w produkcji to problem ewaluacji: zmień jedną część promptu lub kontekstu, a potem zmierz jakość zadania i tryby awarii. Poniższe techniki to typowe punkty wyjścia, a nie uniwersalna kolejność.

Przykłady few-shot są często skuteczne w kontrolowaniu formatu wyjścia. Zacznij od 3–5 przykładów obejmujących puste wejścia, niejednoznaczne zapytania i odpowiedzi wieloczęściowe, a potem zmierz wynik na zbiorze wydzielonym. Przykłady powinny obejmować rzeczywisty rozkład wejść, a nie tylko szczęśliwą ścieżkę. Więcej przykładów zużywa kontekst i nie gwarantuje dalszych zysków.

Prompting chain-of-thought (CoT) prosi model o ujawnienie rozumowania pośredniego przed odpowiedzią. Kojima et al. (2022) zaraportowali zyski z przyrostka „Let’s think step by step” w testowanych zadaniach rozumowania, ale efekt zależy od modelu, a nowsze API rozumujące mogą nie ujawniać ukrytych śladów. W produkcji preferuj możliwy do sprawdzenia rozkład zadania lub zwięzłe uzasadnienie, gdy jest przydatne dla ewaluatora. Self-consistency (Wang et al., 2023) próbkuje kilka ścieżek rozumowania i agreguje odpowiedzi, wymieniając dodatkowy koszt inferencji na odporność w odpowiednich zadaniach.

Ustrukturyzowane dane wyjściowe z jawnymi schematami JSON (sekcja 39) usuwają wiele błędów parsowania. Silniki constrained decoding, takie jak xgrammar, mogą wymuszać obsługiwaną gramatykę podczas generowania; poprawność faktograficzna i semantyczna nadal wymagają ewaluacji, a nieobsługiwane cechy schematu mogą nadal wymagać obsługi.

Łańcuchowanie promptów dzieli zadanie na wyspecjalizowane etapy, na przykład klasyfikacja intencji → pobranie kontekstu → wygenerowanie odpowiedzi → walidacja wyniku. Może lokalizować błędy, pozwalać na różne modele w poszczególnych etapach i ujawniać stan pośredni nadający się do cache. Dodaje też interfejsy i opóźnienie, więc porównaj je z wersją bazową z jednym wywołaniem.

Temperatura zmienia rozkład próbkowania. Niskie wartości to rozsądny punkt wyjścia dla klasyfikacji lub ekstrakcji; wyższe mogą zwiększać różnorodność w generowaniu pomysłów. Dokładne zachowanie różni się między API modeli i oddziałuje z top_p, top_k i domyślnymi ustawieniami dostawcy, więc przetestuj obsługiwane ustawienia na zadaniu, zamiast kopiować jeden zakres.

Rozdzielenie wiadomości systemowej i użytkownika oddziela trwałą politykę od treści pojedynczego żądania. Szablony czatu i instruction tuning nadają tym rolom różny priorytet, ale nie czynią wiadomości systemowej granicą egzekwowania. Stabilne zachowanie umieść w wiadomości systemowej, niezaufane dane trzymaj w treści użytkownika lub narzędzia, a twarde ograniczenia, takie jak usuwanie PII, egzekwuj także poza modelem.

Inżynieria kontekstu rozszerza pracę nad promptem na składanie pobranych dokumentów, wyników narzędzi, historii rozmowy i przykładów. Liu et al. znaleźli efekt lost-in-the-middle w testowanych modelach długiego kontekstu, więc pozycja powinna być częścią ewaluacji, a nie zakładaną jako nieistotna. Szerszy przepływ pracy opisałem w Inżynierii kontekstu dla agentów AI.


Część VIII — Operacje produkcyjne

Operacje produkcyjne zamieniają wcześniejsze pojęcia w limity przyjmowania żądań, testy obciążeniowe, alerty i decyzje o pojemności pod rzeczywistym ruchem.

41. Rate limiting dla żądań o zmiennym koszcie

Tradycyjny rate limiting oparty na żądaniach na sekundę zakłada z grubsza równy koszt każdego żądania. LLM łamią to założenie. 10-tokenowy prompt klasyfikacyjny i 100K-tokenowa analiza dokumentu trafiają w ten sam endpoint API, ale różnią się kosztem o cztery rzędy wielkości. Limitowanie według RPS albo przepuszcza drogie żądania bez kontroli, albo niepotrzebnie głodzi tanie.

Systemy produkcyjne potrzebują rate limitingu opartego na tokenach w wielu wymiarach. OpenAI dokumentuje limity żądań i tokenów według poziomu użycia. Anthropic rozdziela limity tokenów wejściowych i wyjściowych. Dokładne kwoty i algorytmy mogą się zmieniać, więc traktuj dokumentację dostawcy jako źródło prawdy; sedno architektury to budżetowanie żądań i tokenów niezależnie.

Praktyczny wzorzec implementacji to wielowymiarowa hierarchia limitów (użytkownik → aplikacja → organizacja → globalny) z poziomami priorytetu dla dostępu premium. Na poziomie żądania rezerwuj tokeny przy przyjęciu: oszacuj łączną liczbę tokenów (wejście + max_tokens), odlicz oszacowanie z kubełka, a po zakończeniu żądania zwróć niewykorzystaną część na podstawie rzeczywistego użycia. Zapobiega to wyczerpaniu pojemności przez falę żądań z długim generowaniem, zanim zaczną produkować wyjście. Żądanie z 2000 tokenów wejściowych i max_tokens = 1000 rezerwuje 3000. Jeśli odpowiedź zużyje 1200 tokenów wyjściowych, 800 wraca do kubełka. Jeśli kubełek ma mniej niż 3000, zwróć 429 albo ustaw żądanie w kolejce.

We wdrożeniach self-hosted odpowiednikiem jest zarezerwowana przepustowość (provisioned throughput): rezerwowanie dedykowanej pojemności GPU dla docelowego tempa generowania tokenów. We wdrożeniach vLLM oznacza to konfigurację kontroli przyjęć wokół aktywnych slotów decode i presji na KV cache, a nie samej liczby żądań. Jak wyjaśnia sekcja 5, zarówno przepustowość, jak i przyjmowanie wymagają limitów uwzględniających tokeny.

42. Tryby awarii, na które trzeba projektować

Serwowanie LLM dodaje tryby awarii związane ze zmienną długością sekwencji, pamięcią KV i długotrwałą pracą decode. Zaprojektuj zabezpieczenia i przetestuj je obciążeniowo, zanim ruch produkcyjny zacznie od nich zależeć.

Brak pamięci (OOM) to częsta awaria. Model 70B w FP16 potrzebuje około 140 GB samych wag, a KV cache dla pojedynczej sekwencji Llama 3.1 70B z kontekstem 128K może dodać około 40 GiB przy założeniach z sekcji 6. Różnica między „mieści się w pamięci” a „OOM pod obciążeniem” jest mniejsza, niż się wydaje, ponieważ batch żądań z długim kontekstem może zużyć więcej pamięci KV, niż oczekiwano. Zapobieganie łączy zmierzoną rezerwę pamięci z kwantyzacją i stronicowaną alokacją KV. W vLLM --gpu-memory-utilization ustawia ułamek pamięci GPU, który silnik może wykorzystać na wagi, aktywacje i KV cache; reszta to rezerwa. Przy obciążeniach z wysoką presją na KV LMCache może odciążać dane KV do pamięci CPU lub na dysk; potraktuj jego publikowane wyniki jako punkt wyjścia i zbenchmarkuj lokalną hierarchię pamięci.

Wywłaszczanie (preemption) następuje, gdy presja na KV cache zmusza planistę do wyrzucenia lub ponownego obliczenia pracy. Dokładna strategia zależy od wersji i konfiguracji serwowania. Z perspektywy użytkownika objawem jest wyższe opóźnienie end-to-end bez oczywistego błędu aplikacji. Obserwuj liczbę wywłaszczeń i koreluj ją z zajętością KV, głębokością kolejki i długościami żądań.

Opóźnienie ogonowe może gwałtownie wzrosnąć, gdy duże prefille opóźniają pracę decode. Chunked prefill (sekcja 7) i szeregowanie uwzględniające długość celują w tę interferencję. Artykuły o planiście Learning-to-Rank (Fu et al., 2024) i CascadeInfer raportują poprawę względem swoich punktów odniesienia w ocenianych obciążeniach, ale dokładny wynik zależy od rozkładu długości żądań i konfiguracji planisty.

Awarie kaskadowe mogą się zacząć, gdy wolne żądania powiększają kolejkę, klienci upstream przekraczają limit czasu, a ponowienia dodają kolejne obciążenie. Zabezpieczenia to kontrola przyjęć, limity współbieżności na najemcę, limity długości wyjścia, budżety ponowień i bezpieczniki (circuit breakers) na bramce. Zdezagregowane pule prefill i decode mogą pomóc, gdy testy obciążeniowe pokazują trwałą interferencję faz. Rysunek pokazuje pętlę i zabezpieczenie na każdej krawędzi.

Pętla czterech kroków: długie żądanie zajmuje slot GPU, kolejka rośnie, klienci przekraczają limit czasu, podczas gdy serwer nadal generuje, a klienci ponawiają żądania, więc ta sama praca nadchodzi ponownie. Przerywane krawędzie nazywają zabezpieczenia: limit długości wyjścia, ograniczanie przyjęć, wycofywanie z jitterem oraz budżet ponowień z bezpiecznikiem (circuit breaker).Pętla czterech kroków: długie żądanie zajmuje slot GPU, kolejka rośnie, klienci przekraczają limit czasu, podczas gdy serwer nadal generuje, a klienci ponawiają żądania, więc ta sama praca nadchodzi ponownie. Przerywane krawędzie nazywają zabezpieczenia: limit długości wyjścia, ograniczanie przyjęć, wycofywanie z jitterem oraz budżet ponowień z bezpiecznikiem (circuit breaker).

43. Monitorowanie systemów LLM

Monitorowanie LLM różni się od monitorowania API na trzy sposoby: każde żądanie ma inny koszt, każde żądanie ma dwie fazy z różnymi wąskimi gardłami, a jego ślad pamięciowy zależy zarówno od długości wejścia, jak i wyjścia. Samo opóźnienie żądania i wskaźnik błędów nie pokazują żadnego z tych elementów.

Goodput to liczba żądań na sekundę spełniających wszystkie zdefiniowane progi SLO, takie jak TTFT, TPOT i całkowite opóźnienie. To użyteczna miara łączna, ponieważ surowa przepustowość może wyglądać zdrowo, gdy SLO opóźnień zawodzą: system przetwarzający 100 żądań na sekundę, który na 40% z nich przekracza progi, ma goodput 60 żądań na sekundę. Optymalizacja pod goodput utrzymuje widoczny rozkład wydajności zamiast raportować samą średnią.

vLLM udostępnia endpoint Prometheus pod /metrics z liczbą żądań działających i oczekujących, zajętością KV cache, rozkładami długości generowania i statystykami prefix cache. Nazwy metryk mogą się zmieniać między wydaniami, więc powiąż dashboardy z wdrożoną wersją. Typowy stos używa Prometheusa do metryk, Grafany do wizualizacji i śladów zgodnych z OpenTelemetry w komponentach aplikacji i serwowania.

Użyteczne wzorce alertów obejmują poniższe. Progi wyprowadź z testów obciążeniowych, zamiast kopiować te przykłady bez zmian:

  • Skoki liczby wywłaszczeń — środowisko wymienia lub ponownie oblicza pracę, co dodaje opóźnienie bez błędu aplikacji.
  • Zajętość KV cache zbliżająca się do przetestowanego obszaru wywłaszczeń — dodaj pojemność lub odrzuć część ruchu, zanim wyrzucenia zaczną się kaskadować.
  • Głębokość kolejki trwale powyżej przetestowanego zakresu batcha — kontrola przyjęć powinna zacząć odrzucać lub obniżać priorytet.
  • TTFT rośnie, a TPOT pozostaje stały — ta rozbieżność wskazuje najpierw na kolejkowanie, przyjmowanie, sieć lub presję na prefill, a nie na przepustowość decode. Do rozróżnienia użyj śladów i metryk kolejki.

W vLLM pierwsze trzy alerty odpowiadają vllm:num_preemptions_total, vllm:kv_cache_usage_perc i vllm:num_requests_waiting (metryki vLLM).

44. Optymalizacja kosztów: strategia kumulująca się

Ceny dostawców i stosunki cen wejścia do wyjścia się zmieniają. Przed decyzją zakupową pobierz aktualne stawki; poziom modelu i długość wyjścia mogą zdominować rachunek jeszcze przed optymalizacjami infrastruktury.

OpenAI, Anthropic i Google wyceniają tokeny wyjściowe kilka razy drożej niż wejściowe w swoich flagowych modelach. Powodem jest podział na prefill i decode: tokeny wejściowe są przetwarzane równolegle w prefill, a każdy token wyjściowy potrzebuje własnego kroku decode. Ucięcie niepotrzebnego wyjścia (ciasne max_tokens, ustrukturyzowane dane wyjściowe, brak powtarzania wejścia) zwykle oszczędza więcej niż ucięcie tej samej liczby tokenów wejściowych.

Kilka podejść można łączyć, ale dopiero po zmierzeniu, które mają zastosowanie do obciążenia:

  1. Kwantyzacja z FP16 do INT4 zmniejsza pamięć wag o 75%. To, czy obniży rachunek, zależy od szybkości kernela, rozmiaru batcha i wykorzystania sprzętu (sekcja 9).
  2. Routing modeli kieruje kwalifikujący się ruch do tańszych modeli. Zmierz odsetek błędnych akceptacji routera i jakość end-to-end, zanim zwiększysz udział obsługiwany przez tańszy model (sekcja 36).
  3. Prompt caching zmniejsza pracę nad powtarzającymi się prefiksami. Rabaty dostawców i traktowanie limitów szybkości zmieniają się w czasie, więc łącz zmierzony współczynnik trafień z aktualnymi warunkami (sekcja 16).
  4. API wsadowe mogą dawać rabat na pracę niewymagającą czasu rzeczywistego, taką jak ewaluacje, generowanie danych syntetycznych i klasyfikacja masowa. Sprawdź aktualne ceny i okna realizacji.
  5. Self-hosting może się opłacać przy stałym wykorzystaniu, ale nie ma uniwersalnego progu opłacalności w wolumenie tokenów. Oprócz wynajmu GPU uwzględnij koszty inżynierii, orkiestracji, observability, zapasu pojemności i dyżurów.

Pomnożenie przykładowych współczynników daje duże teoretyczne zmniejszenie, ale dane wejściowe nie są niezależne: kwantyzacja zmienia przepustowość, routing zmienia mieszankę jakości, a caching i batching dotyczą tylko kwalifikującego się ruchu. Zbuduj oszacowanie ze zmierzonych udziałów ruchu i zweryfikuj je z fakturą.

45. Planowanie pojemności i autoskalowanie

Planowanie pojemności dla serwowania LLM musi uwzględniać zmienny koszt żądań, długotrwałą pracę decode i pamięć zależną od sekwencji. W zależności od obciążenia zasobem ograniczającym może być pamięć KV, przepustowość pamięci, moc obliczeniowa lub interkonekt.

Teoretyczny pułap pamięci dla liczby równoległych żądań wynika z budżetu KV cache:

max concurrent sequences=GPU memory−model weights−overheadper-sequence KV cache size\text{max concurrent sequences} = \frac{\text{GPU memory} - \text{model weights} - \text{overhead}}{\text{per-sequence KV cache size}}

Dla rachunku pojemności załóżmy, że środowisko udostępnia budżet KV 40 GiB dla Llama 3.1 70B z KV cache w FP16. Każda sekwencja 4K zajmuje około 1,25 GiB, a każda sekwencja 128K około 40 GiB. Taki budżet mieści więc co najwyżej około 32 sekwencje 4K albo jedną sekwencję 128K, zanim doliczy się narzut alokatora, środowiska, zmienności obciążenia i SLO. Funkcja kv_cache_bytes z sekcji 6 powtarza to obliczenie dla innego modelu lub budżetu. Dlatego wybór GPU i optymalizacja KV cache bezpośrednio wyznaczają plan pojemności.

Wzór pojemności do wymiarowania floty:

required GPUs=peak tokens/s×safety-factor multiplierper-GPU tokens/s at target SLO\text{required GPUs} = \frac{\text{peak tokens/s} \times \text{safety-factor multiplier}}{\text{per-GPU tokens/s at target SLO}}

Przed dzieleniem przelicz oba tempa na tę samą jednostkę czasu. Użyj przepustowości na GPU zmierzonej przy docelowym SLO, a nie przepustowości szczytowej. Mnożnik zapasu bezpieczeństwa, taki jak 1,3, rezerwuje 30% zapasu; dobierz go na podstawie zmierzonej zmienności ruchu, awarii i czasu odzyskiwania. Szczytowa przepustowość tokenów i przepustowość zgodna z SLO mogą się mocno różnić wraz ze wzrostem współbieżności. Benchmarkuj z rzeczywistym rozkładem długości promptów i odpowiedzi przy wymaganych progach TTFT i TPOT, zamiast używać teoretycznego maksimum.

Zajętość GPU jako jedyny sygnał autoskalowania nie wystarcza, ponieważ może pozostawać wysoka zarówno przy zdrowym przetwarzaniu, jak i przy przeciążeniu. Połącz ją z głębokością kolejki, zajętością KV cache i spadkiem goodputu. Progi dostrój w testach obciążeniowych; wartości takie jak 80% zajętości KV to punkty wyjścia, a nie uniwersalne limity. Te metryki wprowadza sekcja 43.

Scale-to-zero może pasować do środowisk deweloperskich i stagingowych z długimi okresami bezczynności. Platformy inferencji serverless i autoskalery oparte na Kubernetesie, takie jak KEDA, mogą usunąć bezczynną pojemność, ale oszczędności i czas zimnego startu zależą od rozmiaru modelu, cache obrazów i wag oraz infrastruktury. Zmierz czas uruchamiania, zanim zastosujesz tę samą politykę do ruchu produkcyjnego wrażliwego na opóźnienia.


Jak łączą się pojęcia dotyczące inferencji

Wiele wpisów z części I–III opisuje jeden łańcuch. Prześledź KV cache jednego żądania przez system: jego rozmiar na sekwencję (sekcja 6) wyznacza, ile sekwencji mieści się w budżecie pamięci, ta liczba ogranicza rozmiar batcha, rozmiar batcha wyznacza intensywność arytmetyczną (sekcja 1), a intensywność arytmetyczna wyznacza TPOT i przepustowość. GQA i kwantyzacja KV cache do FP8 lub INT8 zmniejszają pierwsze ogniwo; PagedAttention zmniejsza straty w drugim. Dla Llama 3.1 70B, KV cache w FP16 i budżetu 40 GiB mieści się 32 sekwencje po 4K tokenów, ale tylko jedna o długości 128K. Gdy budżet się kończy, serwer wywłaszcza żądania albo kończy się OOM (sekcja 42).

Routing, caching, kwantyzacja i wybór sprzętu kumulują się tylko wtedy, gdy każdy z nich oceniono względem tego samego celu jakości i opóźnienia. Wybierz jeden objaw z tabeli na górze, ustal wersję bazową i zadbaj, aby następną zmianę łatwo było cofnąć.


Dalsza lektura

Powiązane pogłębione artykuły z tego bloga, pogrupowane tematycznie:


Bibliografia

Pogrupowana według obszaru tematycznego.

Inferencja i attention

Speculative decoding

Kwantyzacja

Trening i fine-tuning

Alignment

Skalowanie i architektura

Embeddings

Architektury agentów

Prompting

Routing

Benchmarki

Architektury serwowania

Frameworki serwujące

  • vLLM - PagedAttention-based serving engine
  • SGLang - RadixAttention and structured generation
  • TensorRT-LLM - NVIDIA optimized inference
  • llama.cpp - Portable C/C++ inference
  • DeepSpeed - Microsoft distributed training library
  • Ollama - Local LLM runner

Operacje