Klasyczne sieci neuronowe przetwarzają każde wejście niezależnie — nie mają pojęcia o kolejności ani kontekście. Tymczasem ogromna część danych, z którymi mierzymy się na co dzień, ma charakter sekwencyjny: zdania składają się ze słów w określonej kolejności, muzyka to ciąg nut, ceny akcji to serie wartości w czasie. Rekurencyjne sieci neuronowe (RNN) zostały zaprojektowane właśnie po to, by przetwarzać sekwencje i zapamiętywać kontekst z poprzednich kroków.
Czym jest rekurencyjna sieć neuronowa?
Rekurencyjna sieć neuronowa (ang. Recurrent Neural Network, RNN) to architektura sieci neuronowej, w której wyjście z poprzedniego kroku czasowego jest podawane jako dodatkowe wejście w bieżącym kroku. Dzięki temu sieć posiada wewnętrzną „pamięć" — stan ukryty (hidden state), który akumuluje informacje z dotychczas przetworzonych elementów sekwencji.
Matematyka RNN
W każdym kroku czasowym t sieć RNN wykonuje dwa obliczenia:
Stan ukryty: hₜ = tanh(Wₕₕ · hₜ₋₁ + Wₓₕ · xₜ + bₕ)
Wyjście: yₜ = Wₕᵧ · hₜ + bᵧ
Gdzie:
- xₜ — wejście w kroku t (np. embedding słowa)
- hₜ — stan ukryty w kroku t (wektor pamięci)
- hₜ₋₁ — stan ukryty z poprzedniego kroku
- Wₕₕ, Wₓₕ, Wₕᵧ — macierze wag (współdzielone między krokami)
- bₕ, bᵧ — biasy
- tanh — funkcja aktywacji
Kluczowa cecha: wagi są współdzielone (shared weights) między wszystkimi krokami czasowymi. Sieć stosuje tę samą transformację na każdym kroku, ale z innym stanem ukrytym — co pozwala przetwarzać sekwencje dowolnej długości.
Rozwinięcie w czasie (Unrolling)
RNN można zwizualizować przez „rozwinięcie" pętli rekurencyjnej w łańcuch identycznych modułów — po jednym na każdy krok czasowy. Każdy moduł przyjmuje wejście xₜ i stan hₜ₋₁, produkując nowy stan hₜ. Ten rozwinięty widok pokazuje, że RNN to de facto bardzo głęboka sieć — z tyloma „warstwami" ile kroków czasowych.
Typy architektury RNN
W zależności od relacji między wejściem a wyjściem wyróżniamy kilka wariantów:
One-to-Many
Jedno wejście → sekwencja wyjść. Przykład: generowanie opisu obrazu (image captioning) — jedno zdjęcie na wejściu, sekwencja słów na wyjściu.
Many-to-One
Sekwencja wejść → jedno wyjście. Przykład: analiza sentymentu — sekwencja słów na wejściu, etykieta (pozytywny/negatywny) na wyjściu.
Many-to-Many
Sekwencja wejść → sekwencja wyjść. Dwa warianty:
- Równoległy — wyjście na każdym kroku (np. tagowanie części mowy: każde słowo → etykieta)
- Encoder-Decoder — najpierw cała sekwencja wejściowa jest kodowana w wektor kontekstu, potem dekoder generuje sekwencję wyjściową (np. tłumaczenie maszynowe)
Problem zanikającego gradientu
RNN trenuje się przez Backpropagation Through Time (BPTT) — odmianę propagacji wstecznej rozwiniętą w czasie. Gradient błędu jest propagowany wstecz przez wszystkie kroki czasowe.
Problem pojawia się przy długich sekwencjach. Gradient musi przejść przez wiele mnożeń macierzy Wₕₕ. Jeśli wartości własne tej macierzy są mniejsze od 1, gradient zanika wykładniczo — sieć nie potrafi uczyć się zależności między odległymi elementami sekwencji. Jeśli wartości własne są większe od 1, gradient eksploduje.
Konsekwencje praktyczne
Klasyczna RNN z funkcją tanh potrafi efektywnie modelować zależności na dystansie 5-10 kroków. Dla dłuższych sekwencji — np. powiązanie podmiotu z orzeczeniem oddalonym o 50 słów — gradient zanika do zera i sieć nie uczy się tej zależności. To był główny powód poszukiwania lepszych architektur.
LSTM — Long Short-Term Memory
LSTM (ang. Long Short-Term Memory) to architektura zaproponowana przez Seppa Hochreitera i Jürgena Schmidhubera w 1997 roku, zaprojektowana specjalnie do rozwiązania problemu zanikającego gradientu. Kluczowa innowacja to stan komórki (cell state) — dedykowana ścieżka informacji biegnąca przez całą sekwencję, chroniona przez trzy bramki (gates).
Architektura LSTM
Każda jednostka LSTM zawiera:
1. Bramka zapominania (Forget Gate) fₜ = σ(Wf · [hₜ₋₁, xₜ] + bf)
Decyduje, jaką część poprzedniego stanu komórki zachować. Wartość 0 = „zapomnij całkowicie", 1 = „zachowaj w pełni". Funkcja sigmoid σ zapewnia wyjście w zakresie [0, 1].
2. Bramka wejściowa (Input Gate) iₜ = σ(Wᵢ · [hₜ₋₁, xₜ] + bᵢ) C̃ₜ = tanh(W_C · [hₜ₋₁, xₜ] + b_C)
Dwa etapy: sigmoid decyduje, które wartości aktualizować, a tanh tworzy wektor kandydatów do dodania.
3. Aktualizacja stanu komórki Cₜ = fₜ ⊙ Cₜ₋₁ + iₜ ⊙ C̃ₜ
Stan komórki jest aktualizowany: stare wartości mnożone przez bramkę zapominania plus nowe wartości mnożone przez bramkę wejściową. Operator ⊙ to mnożenie element po elemencie (Hadamard product).
4. Bramka wyjściowa (Output Gate) oₜ = σ(Wₒ · [hₜ₋₁, xₜ] + bₒ) hₜ = oₜ ⊙ tanh(Cₜ)
Decyduje, jaką część stanu komórki ujawnić jako wyjście.
Dlaczego LSTM rozwiązuje problem zanikającego gradientu?
Stan komórki Cₜ jest aktualizowany addytywnie (dodawanie, nie mnożenie). Gradient przepływa przez stan komórki niemal bez zakłóceń — bramka zapominania kontroluje, ile informacji zachować, ale nie wymusza wielokrotnego mnożenia przez tę samą macierz wag. To pozwala LSTM uczyć się zależności na dystansie setek kroków.
GRU — Gated Recurrent Unit
GRU (ang. Gated Recurrent Unit) to uproszczona wersja LSTM zaproponowana przez Kyunghyun Cho w 2014 roku. GRU łączy bramkę zapominania i bramkę wejściową w jedną bramkę aktualizacji (update gate) i rezygnuje z oddzielnego stanu komórki.
Architektura GRU
Bramka aktualizacji: zₜ = σ(Wz · [hₜ₋₁, xₜ] + bz)
Bramka resetu: rₜ = σ(Wr · [hₜ₋₁, xₜ] + br)
Kandydat stanu: h̃ₜ = tanh(W · [rₜ ⊙ hₜ₋₁, xₜ] + b)
Nowy stan: hₜ = (1 - zₜ) ⊙ hₜ₋₁ + zₜ ⊙ h̃ₜ
LSTM vs GRU
| Cecha | LSTM | GRU |
|---|---|---|
| Bramki | 3 (forget, input, output) | 2 (update, reset) |
| Parametry | Więcej (~4x rozmiar stanu ukrytego) | Mniej (~3x) |
| Stan komórki | Oddzielny (C i h) | Tylko h |
| Wydajność | Wolniejszy trening | Szybszy trening |
| Jakość | Lepsza przy bardzo długich sekwencjach | Porównywalna przy krótszych |
W praktyce różnica w jakości jest niewielka — GRU jest preferowane tam, gdzie liczy się szybkość treningu i mniejsze zużycie pamięci.
Dwukierunkowe RNN (Bidirectional RNN)
Standardowa RNN przetwarza sekwencję od lewej do prawej — w kroku t zna tylko elementy x₁, ..., xₜ. W wielu zadaniach kontekst z obu stron jest istotny. Na przykład w zdaniu „Zamek był stary" — czy chodzi o zamek w drzwiach, czy zamek obronny? Odpowiedź może zależeć od kontynuacji zdania.
Dwukierunkowa RNN (BiRNN) rozwiązuje to, uruchamiając dwie niezależne warstwy RNN — jedną przetwarzającą sekwencję do przodu, drugą do tyłu. Ich stany ukryte są łączone (konkatenacja lub suma) w każdym kroku czasowym:
hₜ = [h→ₜ ; h←ₜ]
BiLSTM (dwukierunkowy LSTM) to jedna z najskuteczniejszych architektur rekurencyjnych, stosowana szeroko w przetwarzaniu języka naturalnego — od NER (rozpoznawania encji) po analizę sentymentu.
Zastosowania RNN i LSTM
Przetwarzanie języka naturalnego
Przed erą transformerów, LSTM dominował w zadaniach NLP:
- Modelowanie języka — przewidywanie następnego słowa w sekwencji
- Tłumaczenie maszynowe — architektura encoder-decoder (Seq2Seq)
- Streszczanie tekstu — generowanie krótszej wersji dokumentu
- Tagowanie sekwencji — rozpoznawanie encji (NER), tagowanie POS
Rozpoznawanie mowy
Systemy ASR (Automatic Speech Recognition) od lat opierały się na BiLSTM. Wejście to sekwencja cech akustycznych (mel-spektrogramy), wyjście to sekwencja fonemów lub znaków. Google zastosował LSTM w systemie rozpoznawania mowy w 2015 roku, redukując błędy o 49%.
Szeregi czasowe
LSTM doskonale sprawdza się w prognozowaniu szeregów czasowych:
- Prognoza pogody — sekwencje pomiarów meteorologicznych
- Predykcja cen — analiza trendów finansowych
- Wykrywanie anomalii — monitorowanie systemów IT, IoT
Generowanie sekwencji
RNN może generować tekst, muzykę, kod — znak po znaku lub token po tokenie. Trening polega na przewidywaniu następnego elementu sekwencji. Przy generowaniu sieć produkuje element, dodaje go do wejścia i generuje kolejny — autoregresyjnie.
Mechanizm atencji i rewolucja transformerów
W 2014 roku Bahdanau et al. wprowadzili mechanizm atencji (attention) jako rozszerzenie architektury encoder-decoder opartej na LSTM. Zamiast kompresować całą sekwencję wejściową do jednego wektora kontekstu, atencja pozwala dekoderowi „patrzeć" na wszystkie stany ukryte enkodera i dynamicznie ważyć ich istotność.
To był krok w stronę transformerów. W 2017 roku Vaswani et al. w artykule Attention Is All You Need zaproponowali architekturę opartą wyłącznie na atencji, rezygnując z rekurencji. Transformery przetwarzają całą sekwencję równolegle (nie sekwencyjnie jak RNN), co dramatycznie przyspiesza trening i umożliwia skalowanie do miliardów parametrów.
Czy RNN jest jeszcze potrzebne?
Transformery zdominowały NLP i wiele innych dziedzin, ale RNN/LSTM nadal mają swoje nisze:
- Urządzenia edge — LSTM jest lżejszy od transformera przy małych sekwencjach
- Przetwarzanie strumieniowe — RNN naturalnie przetwarza dane element po elemencie, bez buforowania
- Szeregi czasowe — w wielu benchmarkach LSTM pozostaje konkurencyjny
- Modele hybrydowe — np. Conformer łączy konwolucje, LSTM i atencję w rozpoznawaniu mowy
Ponadto nowe architektury inspirowane RNN — jak State Space Models (Mamba, S4) — łączą sekwencyjne przetwarzanie z wydajnością transformerów, co sugeruje, że idea rekurencji nie powiedziała ostatniego słowa.
Implementacja prostego LSTM w Pythonie
Współczesne frameworki (PyTorch, TensorFlow) udostępniają gotowe moduły LSTM. Przykład w PyTorch:
import torch
import torch.nn as nn
class LSTMClassifier(nn.Module):
def __init__(self, vocab_size, embed_dim, hidden_dim, num_classes):
super().__init__()
self.embedding = nn.Embedding(vocab_size, embed_dim)
self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True, bidirectional=True)
self.fc = nn.Linear(hidden_dim * 2, num_classes)
def forward(self, x):
embeds = self.embedding(x)
lstm_out, (h_n, c_n) = self.lstm(embeds)
# Konkatenacja ostatnich stanów ukrytych obu kierunków
hidden = torch.cat((h_n[0], h_n[1]), dim=1)
return self.fc(hidden)
Ten prosty model łączy warstwę embeddingów, dwukierunkowy LSTM i warstwę liniową — wystarczającą architekturę do klasyfikacji tekstu.
Podsumowanie
Rekurencyjne sieci neuronowe wprowadziły do uczenia maszynowego zdolność przetwarzania sekwencji — fundamentalną dla języka, mowy i szeregów czasowych. LSTM i GRU rozwiązały problem zanikającego gradientu przez mechanizmy bramkowania, umożliwiając modelowanie długoterminowych zależności. Choć transformery przejęły pałeczkę w wielu zadaniach, architektury rekurencyjne pozostają ważnym narzędziem i inspiracją dla nowych rozwiązań.