# Rekurentní sítě a LSTM

Věta „vyrostl jsem ve Francii, a proto plynně mluvím ... " má na konci slovo, které se dá odvodit jen z informace vzdálené deset slov zpátky. Klasická rekurentní síť ho nedoplní, i když má teoreticky paměť neomezené délky.

Důvod není v architektuře, ale v číslech. **Gradient se při zpětném průchodu časem násobí v každém kroku, a když je ten násobitel menší než jedna, po deseti krocích z něj nezbude nic.** Síť se prostě nemá jak naučit, že tam ta souvislost je.

LSTM tenhle problém řeší jedním strukturálním nápadem z roku 1997. Tahle stránka ho vysvětluje po jednotlivých hradlech. Předpokládá to [MLP a backpropagation](MLP-a-backpropagation), zejména gradientní sestup a mizející gradient, a [topologie sítí](Topologie-a-uceni-siti). Kde to vede v praxi, ukazují [jazykové modely](Jazykove-modely).

## Rekurentní síť

**Rekurentní neuronová síť (RNN)** je síť se zpětnou vazbou - výstup neuronu je vedle okolních neuronů přiveden i sám na sebe nebo na předchozí vrstvu. Hodí se k modelování **sekvencí**: text, řeč, časové řady.

Zásadní rozdíl proti [dopředné síti](MLP-a-backpropagation): **tentýž vstup může dát jiný výstup**, protože záleží na tom, co bylo předtím. Dopředná síť je funkce, rekurentní je automat se stavem.

Trénuje se to **rozvinutím v čase** (backpropagation through time): síť se pro sekvenci délky `T` rozbalí na `T` kopií za sebou, čímž vznikne obyčejná hluboká dopředná síť, a na ni se pustí normální backpropagation. Váhy jsou ve všech kopiích sdílené, takže se gradienty sečtou - stejný princip jako u [sdílených filtrů v CNN](Konvolucni-site#konvoluční-vrstva).

A přesně tady vzniká problém.

## Problém dlouhodobých závislostí

Klasické RNN mají problém s dlouhodobými závislostmi: **gradient během zpětného šíření skrz mnoho časových kroků buď mizí, nebo exploduje** (Hochreiter 1991, Bengio et al. 1994). Síť si pak nedokáže „zapamatovat" informace přes delší časový interval.

Mechanismus je jednoduchý a stojí za to si ho spočítat. Při rozvinutí na `T` kroků se gradient násobí `T`-krát stejným faktorem. Pro faktor `0,9`:

| Kroků zpět | Zbytek gradientu |
|---|---|
| 10 | 0,35 |
| 50 | 0,005 |
| 100 | 0,000027 |

Pro faktor `1,1` naopak po sto krocích vyjde `13 780` a gradient exploduje - trénink diverguje a váhy skončí jako `NaN`.

**Exploze se řeší snadno: gradient se ořízne (gradient clipping) na maximální normu a hotovo.** Mizení se takhle řešit nedá, protože chybějící informaci nemáš z čeho doplnit. Proto se musela změnit architektura.

Souvislost se [sigmoidou](Neuron-a-perceptron#aktivační-funkce): její derivace je nejvýš `0,25`, takže u rekurentní sítě s sigmoidální aktivací gradient mizí obzvlášť rychle.

## LSTM

Architektura navržená **Hochreiterem a Schmidhuberem v roce 1997**. Zavádí dvě věci:

**Cell state `Ct`** - „dopravníkový pás" vedený časem **s minimem změn**.

**Tři hradla (gates)** tvořená sigmoidálními neurony, která regulují, co se do stavu zapíše, co se vymaže a co vystoupí.

Ten dopravníkový pás je celý nápad a stojí za to říct, proč funguje. Podívej se dopředu na rovnici `Ct = ft ⊙ Ct−1 + it ⊙ C̃t`. **Stav se do dalšího kroku dostává násobením a sčítáním, ne průchodem aktivační funkcí.** Když je `ft` blízko jedné, gradient projde skrz beze změny - není čím ho zmenšit. To je celý mechanismus, kterým LSTM mizející gradient obchází.

Hradlo je vždycky sigmoida, protože její výstup je mezi 0 a 1 a chová se tak jako **ventil**: nula zavřeno, jedna otevřeno, mezitím přiškrceno.

### Zapomínací hradlo (forget gate)

Rozhoduje, které informace z předchozího stavu `Ct−1` zahodit:

```
ft = σ( Wf · [ht−1, xt] + bf )
```

Hodnota blízko 0 znamená **zapomeň**, blízko 1 znamená **ponech**.

Ten zápis `[ht−1, xt]` znamená zřetězení předchozího skrytého stavu a aktuálního vstupu. **Hradlo se tedy rozhoduje na základě toho, co síť ví, i toho, co právě přišlo.**

### Vstupní hradlo (input gate)

Rozhoduje, co nového do stavu zapsat. Jsou to dvě věci naráz:

```
it  = σ( Wi · [ht−1, xt] + bi )
C̃t = tanh( WC · [ht−1, xt] + bC )
```

`C̃t` je **kandidát** na novou hodnotu stavu, `it` určuje, **kolik z něj připustit**. Rozdělení na „co" a „kolik" je záměrné - kandidát je z tanh a může být záporný i kladný, ventil je ze sigmoidy a je vždycky mezi 0 a 1.

### Aktualizace buněčného stavu

Jádro celého LSTM:

```
Ct = ft ⊙ Ct−1 + it ⊙ C̃t
```

kde `⊙` je prvkové (Hadamardovo) násobení.

Přečti si tu rovnici slovy: **nový stav = (kolik si nechám ze starého) + (kolik připustím z nového)**. Nic víc. A protože se stav mezi kroky jen násobí a sčítá, gradient jím proteče bez ztráty.

### Výstupní hradlo (output gate)

Určuje, co síť vyprodukuje jako skrytý stav `ht`:

```
ot = σ( Wo · [ht−1, xt] + bo )
ht = ot ⊙ tanh(Ct)
```

**Stav `Ct` a výstup `ht` jsou dvě různé věci** a tohle je věc, kterou lidi u LSTM přehlédnou nejčastěji. Buňka si může něco pamatovat a nedávat to ven. Informace uložená deset kroků zpátky může sedět v `Ct` a projevit se až ve chvíli, kdy ji výstupní hradlo pustí.

## Varianty LSTM

**Peephole connections (Gers a Schmidhuber, 2000)** - hradla získávají přístup i ke stavu `Ct−1`. Rozhodují se tedy nejen podle vstupu a výstupu, ale i podle toho, co je v paměti.

**Coupled forget/input gate** - zapomínáme a zapisujeme společně: `it = 1 − ft`. Logika je, že novou informaci zapíšeš právě tam, kde jsi starou zapomněl. Míň parametrů, srovnatelný výsledek.

**GRU (Gated Recurrent Unit, Cho et al. 2014)** - zjednodušená varianta se **dvěma hradly** (update, reset), která **spojuje cell state a skrytý stav dohromady**. Často srovnatelné výsledky, méně parametrů.

**Doporučení: začni GRU.** Má míň parametrů, trénuje se rychleji a na většině úloh dosáhne stejného výsledku jako LSTM. Na LSTM přejdi, jen když ti GRU nestačí.

## Kde se to používá

Zpracování přirozeného jazyka (strojový překlad, generování textu), rozpoznávání řeči, rozpoznávání rukou psaného textu, popisky obrázků (image captioning), predikce časových řad.

## Kde LSTM přestává platit

**Nedá se paralelizovat.** Krok `t` potřebuje výsledek kroku `t−1`, takže se sekvence musí projít po jednom. [CNN](Konvolucni-site) spočítá celou vrstvu naráz, LSTM ne. **Tohle je hlavní důvod, proč LSTM prohrálo s Transformerem** - ne kvalita, ale to, že Transformer zpracuje celou sekvenci paralelně a využije grafickou kartu.

**Na velmi dlouhé závislosti pořád nestačí.** Odsune problém z desítek kroků na stovky, neodstraní ho. Na tisíce kroků potřebuješ pozornost (attention).

**Pro generování dlouhých koherentních textů byly LSTM předstiženy architekturami typu Transformer.** To je dnešní stav a je dobré ho říct rovnou.

**Kde LSTM pořád dává smysl:** [na rozpoznávání](Jazykove-modely#kde-lstm-dnes-pořád-dává-smysl) - třeba detekci sentimentu - je stále použitelné. LLM zvládne stejnou úlohu, ale **středně velký LSTM potřebuje řádově méně výpočetních zdrojů**. U časových řad se senzorickými daty, kde jde o krátkou historii a běží to na malém zařízení, je to pořád rozumná volba.

## Co se na tom nejčastěji rozbije

| Příznak | Kde je problém |
|---|---|
| Ztráta se změní na `NaN` | explodující gradient - zapni gradient clipping |
| Síť se učí jen krátké souvislosti | mizející gradient v obyčejné RNN - přejdi na LSTM nebo GRU |
| Trénink je extrémně pomalý | sekvenční povaha RNN - zkrať sekvence, zmenši model, zvaž Transformer |
| Model ignoruje začátek sekvence | příliš dlouhá sekvence i na LSTM - potřebuje attention |
| Výsledky kolísají mezi běhy | krátká sekvence a malý dataset, přidej dropout a víc dat |
| Model funguje na trénování, na delších sekvencích ne | trénoval jsi na krátkých - délky musí odpovídat nasazení |

## Co si odnést

**RNN má stav, dopředná síť ne.** Tentýž vstup může dát jiný výstup.

**Trénuje se rozvinutím v čase**, čímž vznikne velmi hluboká síť - a s ní problém gradientu.

**Explodující gradient se ořízne, mizející ne.** Proto musela vzniknout jiná architektura.

**Cell state je dopravníkový pás.** Prochází časem jen násobením a sčítáním, takže jím gradient proteče.

**Tři hradla: zapomeň, zapiš, vydej.** Všechna jsou sigmoidy, tedy ventily mezi 0 a 1.

**`Ct` a `ht` jsou dvě různé věci.** Buňka si může pamatovat a nevydávat.

**GRU je jednodušší a většinou stačí.**

**Transformer vyhrál kvůli paralelizaci**, ne kvůli kvalitě jednotlivého kroku.

## Kam dál

- **[Jazykové modely](Jazykove-modely)** - co LSTM na znakové úrovni doopravdy umí a co ne
- **[MLP a backpropagation](MLP-a-backpropagation)** - algoritmus, který se tu rozvíjí v čase
- **[Konvoluční sítě](Konvolucni-site)** - druhá specializovaná architektura, pro srovnání
- **[Topologie a učení sítí](Topologie-a-uceni-siti)** - kam se rekurentní sítě řadí
