Tenhle rozdíl je jeden z největších aha momentů celé architektury a v popisech se skoro vždycky vynechá. Při tréninku model zpracuje celou sekvenci naráz a udělá tisíc předpovědí jedním průchodem. Při generování dělá jednu předpověď za průchod. Z toho plyne, proč je trénink překvapivě efektivní, proč je generování pomalé a odkud se bere jeden zákeřný problém navíc.
Trénink: tisíc predikcí za jeden průchod
Vezmi větu o 1 000 tokenech. Naivně by ses mohl domnívat, že model musí projít tisíckrát, pro každou pozici zvlášť. Nemusí.
Model totiž vydá logits pro každou pozici najednou:
vstup: [ Praha je hlavní město České ]
↓ ↓ ↓ ↓ ↓
výstup: [ je hlavní město České republiky ] ← predikce z každé pozice
A protože kauzální maska zaručuje, že pozice 3 nevidí na pozice 4 a 5, je každá z těch předpovědí poctivá, model při ní opravdu neznal budoucnost. Loss se spočítá pro všech 1 000 pozic a zprůměruje.
jeden forward + backward = 1 000 trénovacích příkladů
Tohle je hlavní důvod, proč vůbec jde natrénovat model na bilionech tokenů. Bez kauzální masky by to bylo tisíckrát dražší.
Tenhle nepoměr je důvod, proč se model natrénuje na bilionech tokenů za týdny, ale odpověď o pěti stech tokenech píše několik sekund.
Teacher forcing
Při tréninku model dostává na vstup vždy správnou historii, ne to, co by sám vygeneroval:
teacher forcing: … [Praha] [je] [hlavní] → predikuj "město"
vstup je vždy skutečný text z korpusu
generování: … [Praha] [je] [nejlepší] → predikuj další
vstup obsahuje to, co model sám vyprodukoval
Trénuje se to tak proto, že jinak by se model na začátku učil z vlastních nesmyslů a nikdy by se nerozjel. Má to ale důsledek, kterému se říká exposure bias: model nikdy během tréninku neviděl vlastní chyby, takže když při generování jednou odbočí, ocitne se v situaci, na kterou nebyl připravený a chyba se nabaluje (viz predikce).
To je jeden z důvodů, proč pomáhá posilované učení na vlastních výstupech modelu: tam už model kouká na to, co sám vyprodukoval.
Generování: jedna predikce za průchod
Při inferenci nemáš budoucnost, takže se musí postupovat sériově:
průchod 1: [Praha] → "je"
průchod 2: [Praha, je] → "hlavní"
průchod 3: [Praha, je, hlavní] → "město"
…
S KV cache se sice nepřepočítává celý kontext, ale počet průchodů modelem se rovná počtu vygenerovaných tokenů. Odtud pramení, že délka odpovědi určuje latenci.
Prefill je vlastně trénink bez učení
Když se na to podíváš takhle, dojde ti hezká souvislost: prefill funguje přesně jako trénovací forward, celý prompt naráz, paralelně přes všechny pozice. Jen se nepočítá loss a nedělá backward.
pozic naráz učí se fáze
trénink forward všechny ano compute-bound
prefill všechny ne compute-bound
decode 1 ne memory-bound
Proto je prefill rychlý (dobře vytíží GPU) a decode pomalý (čeká na paměť).
Kolik to stojí
Užitečný odhad, který se hodí mít v hlavě:
forward ≈ 2 × parametry FLOPs na token
backward ≈ 2 × forward
jeden krok ≈ 6 × parametry FLOPs na token
Pro model 7 B a bilion tokenů to dává řádově 10²² operací a odtud se počítá, kolik GPU a jak dlouho. Stejný vzorec ti řekne, že trénink jednoho tokenu stojí zhruba třikrát tolik co inference téhož tokenu.
Co z toho plyne prakticky
- Dlouhý prompt tě netrápí tolik jako dlouhá odpověď. Prompt se zpracuje paralelně, odpověď sériově.
- Fine-tuning na dlouhých příkladech je efektivní: jeden příklad o 2 000 tokenech dá modelu 2 000 trénovacích signálů, ne jeden.
- Model nikdy neviděl své chyby (pokud neproběhlo RL), takže se z odbočky sám nevzpamatuje. Když ti generování ujede, nepomůže prosba, ale restart s lepším promptem.
- Odhad tréninkových nákladů zvládneš z jednoho vzorce, aniž bys cokoli spouštěl.
Cvičení
- Model má 7 mld parametrů. Kolik FLOPs zhruba stojí jeden trénovací krok na dávce 1 milionu tokenů?
- Proč nejde generovat paralelně tak, jako se trénuje? Co konkrétně brání tomu spočítat tokeny 1–100 najednou?
- Máš prompt 4 000 tokenů a odpověď 200 tokenů. Kolik průchodů modelem se odehraje?
Náčrt řešení: rozbal, až si cvičení zkusíš sám
- Zhruba
4,2 × 10¹⁶FLOPs, tedy 42 PFLOPs. Používá se pravidlo6 × N × D, kdeNje počet parametrů aDpočet tokenů v dávce:6 × 7 × 10⁹ × 10⁶. Šestka v něm je2za forward a4za backward, protože zpětný průchod stojí zhruba dvakrát tolik co dopředný. - Brání tomu autoregrese. Token 2 je vstupem pro predikci tokenu 3, takže dokud ho model nevygeneruje, nemá co poslat na vstup. Při tréninku tenhle problém není, protože správná posloupnost je předem známá z dat a stačí zakrýt budoucnost maskou. To je celý teacher forcing.
- 201 průchodů. Jeden prefill, ve kterém se všechny 4 000 tokenů promptu zpracují naráz paralelně, a pak 200 kroků decode, každý za jeden token. Proto délka odpovědi ovlivňuje latenci mnohem víc než délka promptu.
Shrnutí
- Kauzální maska umožňuje trénovat na všech pozicích jedním průchodem, tisíc predikcí za forward.
- Teacher forcing dává modelu při tréninku vždy správnou historii; odtud exposure bias.
- Generování je sériové: jeden průchod = jeden token, proto délku odpovědi cítíš v latenci.
- Prefill je totéž co trénovací forward, jen bez učení; proto je rychlý a decode ne.
Proč stačí při tréninku jeden průchod modelem na sekvenci o tisíci tokenech, i když se model učí předpovídat každý z nich?
Model vydává logits pro každou pozici zároveň a kauzální maska zaručuje, že žádná pozice nevidí do budoucnosti. Každá z těch tisíce předpovědí je proto poctivá a loss se dá spočítat pro všechny naráz, jeden forward tak nahradí tisíc trénovacích příkladů.
Co je teacher forcing a jaký má nežádoucí důsledek?
Při tréninku model dostává na vstup vždy skutečné pokračování textu, ne to, co by sám vygeneroval. Bez toho by se na začátku učil z vlastních nesmyslů. Důsledkem je exposure bias: model nikdy neviděl vlastní chyby, takže když při generování odbočí, neumí se vrátit a chyba se nabaluje.
Proč nejde generování paralelizovat stejně jako trénink?
Protože při tréninku je celá sekvence dopředu známá, zatímco při generování každý další token závisí na tom předchozím, který ještě neexistuje. Vzniká sériová závislost, proto se generuje token po tokenu a délka odpovědi přímo určuje latenci.
