Předchozí kapitoly popisovaly, jak trénink funguje, když funguje. Tahle je o tom zbytku. Trénink neuronové sítě je jeden z mála druhů kódu, který selže tiše: nespadne, nevyhodí výjimku, jen se naučí něco jiného, než jsi chtěl. Kompilátor tě neochrání, testy taky ne. Jediné, co máš, je křivka loss a schopnost číst z ní.
Základní pravidlo: loss je jediný přístroj v kokpitu
Skoro každá porucha se pozná z tvaru křivky. Naučit se ty tvary je největší praktická dovednost, kterou v tréninku získáš.
loss
|
|\ A) zdravý průběh
| \___ rychlý pád, pak pomalé zlepšování
| \_______
| \___________
+---------------------------------> krok
|\ /\ B) loss spike
| \____/ \____ náhlý skok nahoru, návrat trvá dlouho
| \_____
+--------------------------------->
|\ C) plateau
| \____________________ po pár krocích se nic neděje
|
+--------------------------------->
|\ ,--'' D) divergence
| \ ,-' loss stoupá a nezastaví se
| `--'
+--------------------------------->
|\___ E) overfitting
| \____ train train klesá, validace se otočila nahoru
| ,---- validace
+--------------------------------->
Diagnostika podle příznaku
| Co vidíš | Nejčastější příčina | Co udělat nejdřív |
|---|---|---|
Loss je hned NaN | přetečení v fp16, dělení nulou, log(0) | přepnout na bf16, zkontrolovat epsilon v softmaxu a normalizaci |
Loss NaN po tisících kroků | ojedinělá extrémní dávka, exploze gradientu | gradient clipping, snížit learning rate, najít tu dávku |
| Loss stoupá od začátku | learning rate o řád moc velký, špatné znaménko loss | zmenšit lr desetkrát, ověřit, že se loss opravdu minimalizuje |
Loss stojí na ln(V) | model se neučí vůbec, gradient nedotéká | zkontrolovat, že parametry dostávají nenulový gradient |
Loss stojí těsně pod ln(V) | model se naučil jen četnosti tokenů | typicky chyba v maskování nebo v posunu labelů |
| Náhlé skoky nahoru | loss spike, běžné u velkých modelů | vrátit se k poslednímu checkpointu a přeskočit dávku |
| Train klesá, validace roste | overfitting, málo dat | víc dat, weight decay, dropout, dřívější zastavení |
| Loss výborná, výstup nesmysl | chyba v generování, ne v tréninku | ověřit tokenizer a pořadí kroků při vzorkování |
Kontrolní číslo, které musíš znát: ln(V)
Na začátku tréninku model nic neumí a rozděluje pravděpodobnost rovnoměrně mezi všech V
tokenů slovníku. Loss tedy musí vyjít blízko přirozeného logaritmu velikosti slovníku:
| Slovník V | Očekávaná počáteční loss = ln(V) |
|---|---|
| 65 (znakový model) | 4,17 |
| 32 000 | 10,37 |
| 128 000 | 11,76 |
Tohle je první věc, kterou po spuštění zkontroluješ. Když je počáteční loss výrazně jiná, model není náhodně inicializovaný, ale rozbitý:
- Loss výrazně vyšší než
ln(V): inicializace má moc velký rozptyl, model si je jistý špatnými odpověďmi. - Loss výrazně nižší než
ln(V): model už na startu ví něco, co vědět nemá. Skoro vždy to znamená leak labelů, typicky chybějící nebo posunutou kauzální masku.
Ta druhá varianta je nejzákeřnější chyba v celém tréninku, protože vypadá jako úspěch. Loss klesá krásně, model dosahuje čísel, která nedávají smysl, a při generování produkuje odpad, protože se naučil opisovat odpověď ze vstupu.
Sanity check, který ušetří dny: přetrénuj jednu dávku
Než pustíš cokoliv velkého, vezmi jednu jedinou dávku a nech na ní model trénovat pár set kroků bez střídání dat.
x, y = batch() # jedna dávka, pořád ta samá
for step in range(300):
logits, cache = forward(x)
loss, dl = loss_and_grad(logits, y)
optimizer_step(backward(dl, cache))
Zdravý model tuhle dávku musí umět nadrtit skoro na nulovou loss. Má dost parametrů na to, aby si ji zapamatoval nazpaměť. Pokud loss zůstane viset:
- gradient někam nedotéká (odpojený tenzor, chybějící parametr v optimizeru),
- learning rate je mimo,
- v loss funkci je chyba,
- labely neodpovídají vstupům.
Trvá to minutu a odhalí to většinu chyb, které by ses jinak dozvěděl po třech dnech na osmi GPU.
Loss spikes u velkých modelů
Čím větší model, tím častěji narazíš na náhlý skok loss. Není to nutně chyba, je to vlastnost tréninku ve velkém měřítku.
Obrana v pořadí, v jakém se nasazuje:
- Gradient clipping na normu (obvykle 1,0). Nejlevnější a nejúčinnější pojistka.
- Bezpečná numerika: bf16 místo fp16, akumulace v fp32.
- Časté checkpointy, aby návrat stál hodiny a ne dny.
- Přeskočení problematických dávek a jejich pozdější prozkoumání.
Chyby, které nevidíš na loss
Nejnebezpečnější kategorie. Křivka je krásná, model je špatný.
- Kontaminace testovacích dat. Benchmark se dostal do tréninkových dat. Model má výborná čísla a v praxi selhává. Řeší se dekontaminací, viz trénovací data.
- Duplicity v datech. Model dané pasáže odříkává nazpaměť místo zobecňování.
- Nesoulad tokenizeru. Trénink probíhal s jiným tokenizerem než inference. Loss je fajn, výstup je slovní salát.
- Špatný chat template. Model se učil na jiném formátu zpráv, než jaký mu podáváš. Projeví se jako záhadné ignorování systémové zprávy.
- Nevyvážená data. Devadesát procent jednoho zdroje. Model umí jeden styl a nic jiného.
Praktický postup, když to nejede
- Zkontroluj počáteční loss proti
ln(V). - Přetrénuj jednu dávku na nulu.
- Vypiš si normu gradientu po krocích. Nula znamená odpojený graf, obrovské číslo znamená nestabilitu.
- Sniž learning rate desetkrát. Pokud se problém ztratí, byl to lr.
- Vypni polovinu vylepšení (dropout, augmentace, plánovač lr) a rozjeď nejhloupější variantu, která má fungovat. Teprve pak přidávej zpět.
- Podívej se očima na deset náhodných dávek dat. Tenhle krok se přeskakuje nejčastěji a nachází nejvíc chyb.
Kam dál
Teorii toho, co se tu ladí, najdeš v loss a gradient a optimizer a learning rate. Numerické potíže s bf16 a fp8 rozebírá numerika a přesnost, problémy specifické pro běh na víc kartách distribuovaný trénink. A jestli chceš vidět zdravý průběh na vlastní oči, pusť si postav si vlastní model.
Cvičení
- Trénuješ se slovníkem 50 000 tokenů. Jaká má být počáteční loss a co znamená, když vyjde 3,5?
- Loss klesá krásně, ale generovaný text je slovní salát. Vyjmenuj tři příčiny, které se na křivce loss neprojeví.
Náčrt řešení: rozbal, až si cvičení zkusíš sám
- Má být
ln(50 000) = 10,82. Hodnota 3,5 znamená leak labelů. Model, který nic neumí a hádá rovnoměrně, musí mít lossln(V). Výrazně nižší počáteční hodnota znamená, že vidí informaci, kterou má teprve předpovědět: chybí kauzální maska, nebo jsou labely špatně posunuté. Je to nejzákeřnější chyba v celém tréninku, protože se tváří jako úspěch. - Nesoulad tokenizeru mezi tréninkem a generováním, chyba ve vzorkovací smyčce a špatný chat template. Ve všech třech případech se model naučil správně, jen mu při generování podáváš něco jiného, než na čem trénoval, případně špatně čteš jeho výstup. Proto se do trénovací smyčky přidává generování ukázky každých pár set kroků: chyby tohohle druhu uvidíš okamžitě, zatímco na loss nikdy.
Shrnutí
- Trénink selhává tiše. Křivka loss je hlavní diagnostický přístroj.
- Počáteční loss musí sedět na
ln(V). Nižší hodnota znamená leak labelů, typicky rozbitou masku. - Přetrénování jedné dávky na nulovou loss je nejlevnější test správnosti celé smyčky.
- Loss spikes jsou u velkých modelů normální. Brání se jim clipping, bf16 a časté checkpointy.
- Kontaminace, duplicity a nesoulad tokenizeru na loss vidět nejsou a napáchají největší škodu.
Trénuješ model se slovníkem 32 000 tokenů a hned první loss je 6,2 místo očekávaných 10,4. Co to znamená?
Že model už na startu ví něco, co vědět nemá, protože rovnoměrné hádání mezi 32 000 tokeny musí dát loss kolem 10,4. Skoro vždy jde o leak labelů: chybí kauzální maska nebo jsou labely špatně posunuté, takže model vidí token, který má teprve předpovědět. Vypadá to jako úspěch, ale výsledný model bude při generování nepoužitelný.
Proč se před dlouhým tréninkem vyplatí nechat model přetrénovat jednu jedinou dávku?
Protože model s dostatkem parametrů si jednu dávku musí zapamatovat a dostat loss skoro na nulu. Pokud to nedokáže, je chyba ve smyčce samotné: gradient někam nedotéká, learning rate je mimo, loss funkce je špatně nebo labely neodpovídají vstupům. Test trvá minutu a ušetří dny výpočtu.
Loss během tréninku náhle vyskočí nahoru a pak se pomalu vrací. Co je to a jak se tomu předchází?
Loss spike, u velkých modelů běžný jev způsobený neobvyklou dávkou nebo výjimečně velkým gradientem, který jedním krokem odhodí váhy daleko. Předchází se mu ořezáváním normy gradientu zhruba na 1,0, počítáním v bf16 s akumulací ve fp32 a častými checkpointy, aby se dal trénink vrátit zpět, pokud se z výkyvu nevzpamatuje.
