diff --git a/wyk/09_Rekurencyjny_model_jezyka.org b/wyk/09_Rekurencyjny_model_jezyka.org new file mode 100644 index 0000000..9b21092 --- /dev/null +++ b/wyk/09_Rekurencyjny_model_jezyka.org @@ -0,0 +1,157 @@ +* Model języka oparty na rekurencyjnej sieci neuronowej + +** Podejście rekurencyjne + +Na poprzednim wykładzie rozpatrywaliśmy różne funkcje +$A(w_1,\dots,w_{i-1})$, dzięki którym możliwe było „skompresowanie” ciągu słów +(a właściwie ich zanurzeń) dowolnej długości w wektor o stałej długości. + +Funkcję $A$ moglibyśmy zdefiniować w inny sposób, w sposób **rekurencyjny**. + +Otóż moglibyśmy zdekomponować funkcję $A$ do + +- pewnego stanu początkowego $\vec{s^0} \in \mathcal{R}^p$, +- pewnej funkcji rekurencyjnej $R : \mathcal{R}^p \times \mathcal{R}^m \rightarrow \mathcal{R}^p$. + +Wówczas funkcję $A$ można będzie zdefiniować rekurencyjnie jako: + +$$A(w_1,\dots,w_t) = R(A(w_1,\dots,w_{t-1}), E(w_t)),$$ + +przy czym dla ciągu pustego: + +$$A(\epsilon) = \vec{s^0}$$ + +Przypomnijmy, że $m$ to rozmiar zanurzenia (embeddingu). Z kolei $p$ to rozmiar wektora stanu +(często $p=m$, ale nie jest to konieczne). + +Przy takim podejściu rekurencyjnym wprowadzamy niejako „strzałkę +czasu”, możemy mówić o przetwarzaniu krok po kroku. + +W wypadku modelowania języka możemy końcowy wektor stanu zrzutować do wektora o rozmiarze słownika +i zastosować softmax: + +$$\vec{y} = \operatorname{softmax}(CA(w_1,\dots,w_{i-1})),$$ + +gdzie $C$ jest wyuczalną macierzą o rozmiarze $|V| \times p$. + +** Worek słów zdefiniowany rekurencyjnie + +Nietrudno zdefiniować model „worka słów” w taki rekurencyjny sposób: + +- $p=m$, +- $\vec{s^0} = [0,\dots,0]$, +- $R(\vec{s}, \vec{x}) = \vec{s} + \vec{x}.$ + +Dodawanie (również wektorowe) jest operacją przemienną i łączną, więc +to rekurencyjne spojrzenie niewiele tu wnosi. Można jednak zastosować +funkcję $R$, która nie jest przemienna — w ten sposób wyjdziemy poza +nieuporządkowany worek słów. + +** Związek z programowaniem funkcyjnym + +Zauważmy, że stosowane tutaj podejście jest tożsame z zastosowaniem funkcji typu ~fold~ +w językach funkcyjnych: + +#+CAPTION: Opis funkcji foldl w języku Haskell +[[./09_Rekurencyjny_model_jezyka/fold.png]] + +W Pythonie odpowiednik ~fold~ jest funkcja ~reduce~ z pakietu ~functools~: + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + from functools import reduce + + def product(ns): + return reduce(lambda a, b: a * b, ns, 1) + + product([2, 3, 1, 3]) +#+END_SRC + +#+RESULTS: +:results: +18 +:end: + +** Sieci rekurencyjne + +W jaki sposób „złamać” przemienność i wprowadzić porządek? Jedną z +najprostszych operacji nieprzemiennych jest konkatenacja — możemy +dokonać konkatenacji wektora stanu i bieżącego stanu, a następnie +zastosować jakąś prostą operację (na wyjściu musimy mieć wektor o +rozmiarze $p$, nie $p + m$!), dobrze przy okazji „złamać” też +liniowość operacji. Możemy po prostu zastosować rzutowanie (mnożenie +przez macierz) i jakąś prostą funkcję aktywacji (na przykład sigmoidę): + +$$R(\vec{s}, \vec{e}) = \sigma(W[\vec{s},\vec{e}] + \vec{b}).$$ + +Dodatkowo jeszcze wprowadziliśmy wektor obciążeń $\vec{b}, a zatem wyuczalne wagi to: + +- macierz $W \in \mathcal{R}^p \times \mathcal{R}^{p+m}$, +- wektor obciążń $b \in \mathcal{R}^p$. + +Olbrzymią zaletą sieci rekurencyjnych jest fakt, że liczba wag nie zależy od rozmiaru wejścia! + +*** Zwykła sieć rekurencyjna + +Wyżej zdefiniową sieć nazywamy „zwykłą” siecią rekurencyjną (/Vanilla RNN/). + +*Uwaga*: przez RNN czasami rozumie się taką „zwykłą” sieć +rekurencyjną, a czasami szerszą klasę sieci rekurencyjnych +obejmujących również sieci GRU czy LSTM (zob. poniżej). + +#+CAPTION: Schemat prostego modelu języka opartego na zwykłej sieci rekurencyjnych +[[./09_Rekurencyjny_model_jezyka/rnn.drawio.png]] + +*Uwaga*: powyższy schemat nie obejmuje już „całego” działania sieci, + tylko pojedynczy krok czasowy. + +*** Praktyczna niestosowalność prostych sieci RNN + +Niestety w praktyce proste sieci RNN sprawiają duże trudności jeśli +chodzi o propagację wsteczną — pojawia się zjawisko zanikającego +(rzadziej: eksplodującego) gradientu. Dlatego zaproponowano różne +modyfikacje sieci RNN. Zacznijmy od omówienia stosunkowo prostej sieci GRU. + +** Sieć GRU + +GRU (/Gated Recurrent Unit/) to sieć z dwiema **bramkami** (/gates/): + +- bramką resetu (/reset gate/) $\Gamma_\gamma \in \mathcal{R}^p$ — która określa, w jakim + stopniu sieć ma pamiętać albo zapominać stan z poprzedniego kroku, +- bramką aktualizacji (/update gate/) $\Gamma_u \in \mathcal{R}^p$ — która określa wpływ + bieżącego wyrazu na zmianę stanu. + +Tak więc w skrajnym przypadku: + +- jeśli $\Gamma_\gamma = [0,\dots,0]$, sieć całkowicie zapomina + informację płynącą z poprzednich wyrazów, +- jeśli $\Gamma_\update = [0,\dots,0]$, sieć nie bierze pod uwagę + bieżącego wyrazu. + +Zauważmy, że bramki mogą selektywnie, na każdej pozycji wektora stanu, +sterować przepływem informacji. Na przykład $Gamma_\gamma = +[0,1,\dots,1]$ oznacza, że pierwsza pozycja wektora stanu jest +zapominana, a pozostałe — wnoszą wkład w całości. + +*** Wzory + +Najpierw zdefiniujmy pośredni stan $\vec{\xi} \in \mathcal{R}^p$: + +$$\vec{\xi_t} = \operatorname{tanh}(W_{\xi}[\Gamma_\gamma \bullet c_{t-1}, E(w_t)] + b_{\xi}),$$ + +gdzie $\bullet$ oznacza iloczyn Hadamarda (nie iloczyn skalarny!) dwóch wektorów: + +$$[x_1,\dots,x_n] \bullet [y_1,\dots,y_n] = [x_1 y_1,\dots,x_n y_n].$$ + +Obliczanie $$\vec{\xi_t}$$ bardzo przypomina zwykłą sieć rekurencyjną, +jedyna różnica polega na tym, że za pomocą bramki $\Gamma_\gamma$ +modulujemy wpływ poprzedniego stanu. + +Ostateczna wartość stanu jest średnią ważoną poprzedniego stanu i bieżącego stanu pośredniego: + +$$\vec{c_t} = \Gamma_u \bullet \vec{\xi_t} + (1 - \Gamma_u) \bullet \vec{c_{t-1}}.$$ + +Skąd się biorą bramki $\Gamma_\gamma$ i $\Gamma_u$? Również z poprzedniego stanu i z biężacego wyrazu. + +$$\Gamma_\gamma = \sigma(W_\gamma[\vec{c_{t-1}},E(w_t)] + b_\gamma),$$ + +$$\Gamma_u = \sigma(W_u[\vec{c_{t-1}},E(w_t)] + b_u),$$ diff --git a/wyk/09_Rekurencyjny_model_jezyka/fold.png b/wyk/09_Rekurencyjny_model_jezyka/fold.png new file mode 100644 index 0000000..d0f9dd9 Binary files /dev/null and b/wyk/09_Rekurencyjny_model_jezyka/fold.png differ diff --git a/wyk/09_Rekurencyjny_model_jezyka/rnn.drawio b/wyk/09_Rekurencyjny_model_jezyka/rnn.drawio new file mode 100644 index 0000000..22b852e --- /dev/null +++ b/wyk/09_Rekurencyjny_model_jezyka/rnn.drawio @@ -0,0 +1 @@ +5Vrbcto6FP0aHjljyzaYx0LIbZLpSXOmbZ46KlaMirB8ZIExX18Jy/gmCEnABPIC0rIu1l77pg0tazBdXDEYju+ph0gLGN6iZV20AOjZpviUQJICZqdnp4jPsKewHHjES6RAQ6Ez7KGoNJBTSjgOy+CIBgEa8RIGGaNxedgzJeVdQ+ijGvA4gqSO/sAeH6eoC7o5fo2wP852FgdMn0xhNlgtEY2hR+MUWh3OGrasAaOUp63pYoCIFF4ml1QClxuerl+MoYDvMuHh63389Woyubq7Cb79f+lz071rq5eNeJIdGHni/KpLGR9TnwaQDHO0z+gs8JBc1RC9fMwdpaEATQH+QZwnikw441RAYz4l6ilaYP5TTv/HUb0ntZhsXyyKnUR16qfNxEpnbIS2HLGjtAYyH/Et49x0nDx/YQMlyytEp4izRAxgiECO52X9gErN/PW4nAnRUGS8ghj11nNIZmqnGlM5D1Ko8Rhz9BjClSxiYYxlmW+U3xwxjhZbT6yeAkPZpLLltqP6cW4YtquwccEoLONAQjLtU1FfIXWWFCbJ7lO2nuzk01a996u9u6Pam9aH0nv3BPTePL7iGxoxdYjYto9Fw5cNQumkPQszXOyzflQTqZAEL8st4oxO0IASygQS0ECazjMmpAJBgv1AdEdCvkjgfSlXLOLnF/Vgij1vZXc6osq2uAeuHKMrDKzIFnDrZHUa5cqscRVDFvEYCpDgAFPZOldC7E7ZeEwNHabRKB+gxkdEn/kULs6YBVB1YcbRabA2ujAPzzNPxehy0ho4LRdATwqBwdijIf2N0Qq1lRl5RH5OoAT7Aw/5tCVPLNIDO/6FZdsZ4EB8f0/BglMsbKbZP4N+sypSnXquqgN6oOJR2+vLWUF5QM85jPIMfyyT/9iN9dO6TfDylsb9p0XbOWre11DWV8nIXkwDR9T9c/nQe7rEt+PedwcMp16/bdXTQNoJ+xYY9n/R2f31wHu4uLketZtK+ra95EdK+myrlkjYGpdpHchlasX0eW87+7ucqKn/Uiy2KKSNoMS1BSocpnamZhWLLC8sBLqVhVJDrC30hTGYFIaFckC0+wuDnvG69yqPF430DXLlXAv37fqqq2FoImwapVvdPhZeqHuxPUKfa5i1u9Uwa1nNXVy0IaH7ad1NMapujpY7RFVn3+7rXYTWL6JHD7OWU1Z6U5Namt0mtb5zKlr/du116tq7rQbdvPZqc/6T+alikzsydnJHr836d2VYK1P3mO7I0bijVeh3BhH2pzBLBKqsE4LDaFNgLnAHozD9RfAZL6QOHKKQoqsEa7yVfShvVS+XzyYs4bIa8pmKjPllrRg3nAPFDa0p1auK+wiuNRloJLU5uNaL4U3eYbViOuod1iz68LVHf8mLl3x47tL36sW1stLUbjar3rHC8k5l3LVjn6ORuOhF6W0PyNveCV/43mWc66x2i2ke6rqnJbJ+W484lDXzpTwXDdkSeQFOS+sTIfKZ+B4tYUTjFXa2PDkVnpr8AWtz0vY2izM/s8V1eh/M4jS/4gc0Tlbil5Z3tkRUXV/vcCYluvlf7NLCZv5HRWv4Fw== \ No newline at end of file diff --git a/wyk/09_Rekurencyjny_model_jezyka/rnn.drawio.png b/wyk/09_Rekurencyjny_model_jezyka/rnn.drawio.png new file mode 100644 index 0000000..91a7261 Binary files /dev/null and b/wyk/09_Rekurencyjny_model_jezyka/rnn.drawio.png differ