Loss a gradient

Co se přesně minimalizuje a jak model ví, kam posunout váhy.

Co se naučíš: Budeš vědět, co přesně se minimalizuje, a spočítáš si, proč trénink žere tolik paměti.

8 min čtení + cvičeníNavazuje na:🧮 Backprop ručně

Až doteď kurz říkal „za každou chybu se váhy trošku poopraví“. Tady se podíváme, co to přesně znamená. Je to motor celého učení a stojí na dvou věcech: čísle, které měří, jak moc se model spletl (loss), a na návodu, kterým směrem každý parametr posunout (gradient). Kdo tohle pochopí, přestane vnímat trénink jako magii.


Loss: jedno číslo, které měří chybu

Model pro každou pozici vydá pravděpodobnosti přes celý slovník. Známe správný token (je jím prostě ten další v textu), takže se stačí podívat, jakou pravděpodobnost mu model přidělil.

Používá se cross-entropy loss:

loss = −log p(správný token)

model dal správnému tokenu 90 %  →  −log(0,9) = 0,105   (malá chyba)
model dal správnému tokenu 10 %  →  −log(0,1) = 2,303   (velká chyba)
model dal správnému tokenu  1 %  →  −log(0,01) = 4,605  (katastrofa)

Logaritmus tam je proto, aby jistý omyl bolel násobně víc než mírná nejistota. Model se tak neučí jen „hádat správně“, ale i „nebýt sebejistý, když si nejsem jistý“.

Celková loss je průměr přes všechny pozice v dávce. Když se u modelu mluví o „loss 2,1“, znamená to, že správnému tokenu dává v průměru pravděpodobnost kolem e⁻²·¹ ≈ 12 %. Vztah k perplexitě rozebírá kapitola metriky.

💡 Všimni si, že není potřeba žádné anotování. Správná odpověď je vždycky další token v textu. Proto se dá trénovat na libovolném množství surového textu, a proto se tomu říká self-supervised učení.


⏩ Loss se nepočítá jen pro poslední token, ale pro každou pozici v sekvenci naráz, proč to jde a co z toho plyne, rozebírá trénink vs generování.

Gradient: kterým směrem posunout každý parametr

Gradient je odpověď na otázku: „Když tenhle jeden parametr nepatrně zvětším, loss vzroste, nebo klesne a jak rychle?“ Je to derivace loss podle daného parametru.

gradient parametru w = +0,3   → zvětšení w loss zvýší  → posuň w dolů
gradient parametru w = −1,2   → zvětšení w loss sníží  → posuň w nahoru (a víc)
gradient parametru w =  0,0   → na tomhle parametru teď nezáleží

Model má miliardy parametrů, takže gradient je vektor o miliardách čísel, pro každý parametr jeden. A spočítá se naráz jedním průchodem zpět.


🧮 Celý výpočet na jednom neuronu s konkrétními čísly najdeš v backprop ručně.

Forward počítá výsledek, backward počítá vinu. Obojí stojí zhruba stejně, proto se říká, že jeden krok tréninku vyjde na trojnásobek ceny jednoho forwardu.


Backpropagation: gradient bez šílených nákladů

Naivně by se muselo pro každý parametr zkusit, co udělá jeho změna, miliardy průchodů modelem. Backprop to řeší řetízkovým pravidlem: gradient se propaguje od loss zpátky vrstvu po vrstvě a každá vrstva ho jen „přeloží“ pro tu předchozí.

FORWARD  →   vstup → vrstva 1 → vrstva 2 → … → vrstva N → loss
BACKWARD ←   gradienty ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ←

Cena backwardu je zhruba dvojnásobek forwardu, takže jeden trénovací krok stojí asi třikrát tolik co inference téhož vstupu.


Proč trénink žere tolik paměti

Tohle je nejčastější překvapení: model, který se do karty vejde k inferenci, se do ní nevejde k tréninku. Důvod je v tom, co všechno je potřeba držet:

CoVelikost pro model 7 B
Váhy (bf16)14 GB
Gradienty (bf16)14 GB
Stavy optimizeru (fp32, viz optimizer)~56 GB
Aktivace z forwardu (potřebné pro backward)jednotky až desítky GB

Dohromady klidně desetinásobek velikosti samotného modelu. Odtud plyne celý cirkus kolem distribuovaného tréninku a technik jako LoRA, které trénují jen malý přídavek místo celého modelu.

Gradient checkpointing je kompromis: část aktivací se neuloží a při backwardu se dopočítá znovu. Ušetří výrazně paměti za cenu zhruba 30 % času navíc.


Krok učení celý dohromady

1. vezmi dávku textu
2. FORWARD:   spočítej předpovědi a loss
3. BACKWARD:  spočítej gradient pro každý parametr
4. UPDATE:    posuň parametry proti gradientu (o kolik, řeší optimizer)
5. opakuj, statisíckrát až milionkrát

Celý pretraining velkého modelu je tohle, spuštěné na tisících GPU po dobu týdnů.


Co se může pokazit

  • Divergence. Příliš velký krok učení a loss vystřelí do nebe; model se z toho nemusí vzpamatovat.
  • Loss spike. Náhlý skok kvůli nešťastné dávce dat nebo numerické nestabilitě. Provozně se řeší návratem k poslednímu uloženému bodu a přeskočením problémové dávky.
  • Vanishing gradient. U hlubokých sítí gradient cestou dolů zmizí. Přesně tomuhle brání residual spojení a pre-norm (normalizace).
  • Přeučení (overfitting). U pretrainingu na bilionech tokenů prakticky nehrozí (model vidí většinu dat jednou), zato u fine-tuningu na malé sadě je to hlavní riziko.

Cvičení

  1. Model přiřadil správnému tokenu pravděpodobnost 0,25. Jaká je loss? A jaká perplexita odpovídá průměrné loss 1,6?
  2. Trénuješ model 3 B v bf16 s AdamW. Odhadni paměť na váhy, gradienty a stavy optimizeru. Vejde se to na kartu s 80 GB i s aktivacemi?
  3. Proč nemá smysl počítat loss z pozice, která je maskovaná (padding)?
Náčrt řešení: rozbal, až si cvičení zkusíš sám
  1. Loss 1,386 a perplexita 4,95. Loss je −ln(0,25) = 1,3863. Perplexita je e^loss, takže e^1,6 = 4,953. Čte se to jako „model je v průměru na rozpacích mezi zhruba pěti možnostmi“, což je mimochodem docela dobrý model.
  2. Zhruba 36 GB, takže se to vejde, ale ne s velkou rezervou. Váhy v bf16 3 × 2 = 6 GB, gradienty taky 6 GB, stavy AdamW ve fp32 3 × 8 = 24 GB. Aktivace přidají jednotky až desítky GB podle délky sekvence a velikosti dávky, takže na kartě s 80 GB to projde, ale s velkou dávkou nebo dlouhým kontextem začneš potřebovat gradient checkpointing.
  3. Protože na takové pozici není co predikovat. Padding je jen výplň do stejné délky, žádný skutečný následující token tam neexistuje. Kdybys loss z těch pozic počítal, model by se učil předpovídat výplň a zároveň bys si zředil průměr, takže by gradient ze skutečných tokenů byl slabší. Maskované pozice se proto z průměru vyhazují úplně.

Shrnutí

  • Loss = −log pravděpodobnosti správného tokenu; jistý omyl trestá násobně víc.
  • Správná odpověď je vždy další token v textu, proto není potřeba anotovat data.
  • Gradient říká pro každý parametr, kterým směrem a jak moc ho posunout; počítá backprop.
  • Trénink potřebuje řádově víc paměti než inference kvůli gradientům, stavům optimizeru a aktivacím.
Model přiřadil správnému tokenu pravděpodobnost 10 %. Jaká je loss a co znamená?

Loss je −log(0,1) ≈ 2,3. Znamená to, že model byl na správné odpovědi dost nejistý. Kdyby jí dal 90 %, byla by loss 0,1; kdyby 1 %, byla by 4,6, logaritmus zajišťuje, že sebejistý omyl bolí mnohem víc než mírná nejistota.

Proč se trénink LLM označuje jako self-supervised, když se model něco „učí“?

Protože správná odpověď se nemusí anotovat, je jí prostě další token v textu. Trénovací signál si tak model bere přímo z dat, takže se dá použít libovolné množství surového textu bez lidské práce navíc.

Model 7 B se ti vejde do karty na inferenci, ale trénink spadne na nedostatek paměti. Proč?

Kromě vah je potřeba držet gradienty, stavy optimizeru (typicky ve fp32, tedy několikanásobek vah) a aktivace z forwardu potřebné pro backward. Dohromady to bývá řádově desetinásobek velikosti modelu, proto se trénuje distribuovaně nebo jen přes adaptéry typu LoRA.