# R-Transformer - dokumentacja końcowa
## Skład zespołu
* Kamil Przybyła (300254)
* Urszula Tworzydło (295809)
## Opis zadania
Celem zadania była implementacja i porównanie działania trzech różnych modeli realizujących zadanie modelowania języka na zbiorze danych *Penn Treebank*. Modelami tymi były: R-Transformer oraz dwie rekurencyjne sieci składające się z komórek typu GRU oraz LSTM.
## Realizacja projektu
Projekt został zrealizowany przy użyciu języka Python 3.8 oraz biblioteki PyTorch. W celu łatwego porównywania modeli oraz śledzenia procesu trenowania wykorzystano usługę *Weights & Biases*. Wyniki wszystkich eksperymentów zostały tam zapisane. Modele wytrenowano korzystając z Google Colab.
Wykorzystano domyślny podział zbioru danych: 888.7 tys. słów w zbiorze treningowym, 78 656 w testowym oraz 70 368 w walidacyjnym. Każda z zaimplementownych sieci przyjmowała na wejściu tensor o wymiarze $(L, B)$ składający się z indeksów wyrazów w słowniku, gdzie $L$ to przyjęta długość sekwencji, a $B$ to rozmiar batcha. Funkcją aktywacyjną w ostatniej warstwie zawsze był logarytm z funkcji softmax, a za funkcję błędu przyjęto *negative log likelihood*. Przy porównywaniu modeli wykorzystano zaś metrykę *perplexity*, której wartość wynosi $\exp({\mbox{nnl loss}})$. Jako metodę optymalizacji wykorzystano spadek stochastyczny (SGD).
Stan warstwy ukrytej resetowano przy każdym kroku treningu (co epokę) oraz przed każdą ewaluacją modelu na zbiorze walidacyjnym.
Aby uniknąć problemu eksplodujących gradientów, pojawiającego się przy trenowaniu modeli wykorzystujących sieci rekurencyjne, zastosowano technikę przycinania gradientów, których norma przekraczała wybraną wartość.
Wykorzystano również technikę redukcji wartości *learning rate* w sytuacji, gdy metryka błędu na zbiorze walidacyjnym nie poprawiła się przez określoną liczbę epok.
Umożliwiono ustawienie wartości wszystkich parametrów modeli oraz hiperparametrów za pośrednictwem argumentów wywołania aplikacji ewaluującej wybrany model. Przygotowano również skrypty uruchamiające eksperymenty oraz instrukcję przygotowania środowiska wirtualnego.
## Architektury sieci
### GRU/LSTM
Modele oparte o sieci rekurencyjne składały się kolejno z: warstwy zanużenia, jednostronnej sieci rekurencyjnej o wybranym typie komórek (GRU lub LSTM) oraz liniowej warstwy dekodującej z powrotem do wymiaru słownika. Między każdą z wyżej wymienionych warstw umieszczony został *dropout*.
### R-Transformer

*źródło: R-Transformer: Recurrent Neural Network Enhanced Transformer (Wang et al.)*
W modelu wykorzystującym architekturę R-Transformer zastosowano taki sam zestaw warstw co w uprzednio opisanym modelu, tylko w miejsce sieci rekurencyjnej pojawił się właśnie R-Transformer.
Pojedyncza warstwa dla sieci o tej architekturze składa się z trzech podwarstw przedstawionych na rysunku powyżej, między którymi zawarto połączenie rezydualne oraz warstwę normalizacji. W podwarstwie *Local RNN* wykorzystano sieć rekurencyjną z komórkami typu LSTM. Druga podwarstwa wymagała zastosowania maskowania, aby komórki atencji z przyszłych wartości w sekwencji nie wpływały na obecnie obliczaną wartość. W warstwie liniowej zastosowano warstwy liniowe najpierw rozszerzające czterokrotnie wymiar reprezentacji, a po zastosowaniu funkcji *ReLU* kompresujące do pierwotnego wymiaru. Taka kombinacja wymiarów macierzy została zaczerpnięta bezpośrednio z oryginalnej implementacji autorów i nie została w żaden sposób opisana w publikacji.
Zmodyfikowano również kolejność wykonywania działań, względem opisu w publikacji. W połączeniach rezydualnych bowiem najpierw aplikowana jest normalizacja, a dopiero później dodawana jest wartość z poprzedniej warstwy. Zmiana ta również pojawia się w implementacji autorów i w naszej implementacji skutkowała tym, że model osiągał lepsze wyniki.
## Przeprowadzone eksperymenty
W celu zbadania działania implementowanych architektur, przeprowadzono kilka eksperymentów, sprawdzających wpływ różnych parametrów na jakość osiąganych predykcji. Każdy z eksperymentów przeprowadzony został z ziarnem o tej samej wartości równej $42$.
### Eksperymenty przeprowadzone dla R-Transformera
Każdy z opisanych w niniejszej sekcji eksperymentów przeprowadzony został z parametrem *clip* określającym maksymalną normę gradientu ustawionym na wartość wynoszącą 0.35. Wartość parametru uczenia się była redukowana o połowe, gdy metryka błędu nie poprawiała się przez 5 epok.
Poza badanym parametrem, pozostałe nie ulegały zmianie i ustawione były na wartości domyślne, dla których liczba warstw wynosi 2, liczba głów atencji 8, wymiar zanurzenia 256, szerokość okna 9, początkowa wartość parametru uczenia się 3, dropout 0.35, a długość sekwencji oraz batch size 32.
#### Rozmiar okna w Local RNN

|Rozmiar okna | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|3 | 153.27| 5.032|
|6 | 154.423| 5.04|
|**9** | **152.502**| **5.027**|
|12 | 153.008| 5.03|
**Wnioski:**
Najbardziej optymalne okazało się ustawienie rozmiaru okna LocalRNN na 9. Dla większego rozmiaru wynik perplexity na zbiorze testowym okazał się być już nieco gorszym, jednak parametr ten nie wydaje się mieć dużego wpływu na jakość predykcji, gdyż różnice w wyniach są bardzo niewielkie.
#### Wpływ długości sekwencji

|Długość sekwencji | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|10 | 172.094| 5.148|
|30 | 155.249| 5.045|
|**50** | **152.442**| **5.027**|
|70 | 156.063| 5.05|
**Wnioski:**
Eksperyment wykazał, że najlepsze rezultaty uzyskał model dla długości sekwencji 50. Dłuższe sekwencje pozwalały na uzyskanie coraz lepszych wyników, jednak dla zbyt dużych wartości efekt ten przestał być widoczny.
#### Liczba warstw

|Liczba warstw | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|1 | 175.027| 5.165|
|2 | 152.502| 5.027|
|3 | 145.947| 4.983|
|**4** | <span style="color:red">**138.387**</span> |<span style="color:red">**4.93**</span>
**Wnioski:**
Eksperyment wykazał, że im więcej warstw, tym R-Transformer osiąga lepsze wyniki.
#### Liczba głów atencji

|Liczba głów atencji | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|4 | 156.749| 5.055|
|8 | 152.502| 5.027|
|16 | 152.056| 5.024|
|**32** | **150.325**| **5.013**|
**Wnioski:**
Eksperyment wykazał, że im więcej głów atencji, tym R-Transformer osiąga lepsze wyniki, aczkolwiek zmiany pomiędzy poszczególnymi wynikami nie są aż tak od siebie odległe jak na przykład te, w których zmieniana była liczba warstw sieci (patrz: eksperyment powyżej).
#### Wpływ wymiaru zanurzenia

|Wymiar zanurzenia | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|64 | 225.991| 5.42|
|128 | 184.758| 5.219|
|256 | 152.502| 5.027|
|**512** | **141.286**| **4.951**|
**Wnioski:**
Z przeprowadzonego eksperymentu wynika, że zwiększenie wymiaru zanurzenia powoduje polepszenie się jakości modelu - najniższą wartość perplexity na zbiorze testowym osiągnął model o wymiarze zanurzenia 512. Parametr ten wydaje się mieć również duży wpływ na jakość modelu, gdyż różnice w wynikach są większe niż były w przypadku pozostałych eksperymentów.
### Eksperymenty przeprowadzone dla LSTM i GRU
Eksperymenty przeprowadzone na sieciach zawierających mechanizm LSTM lub GRU można podzielić na dwie kategorie. Najpierw zostały przeprowadzone eksperymenty mające na celu dostrojenie parametrów: dropout, liczby komórek w warstwie ukrytej (hidden units) oraz parametru uczenia (learning rate). Następnie przeprowadzono eksperymenty, których celem było wyznaczenie optymalnej liczby warstw LSTM/GRU, długości sekwencji oraz wymiaru zanurzenia. Dla drugiej serii eksperymentów parametry dropoutu, liczby komórek w warstwie ukrytej oraz parametr uczenia został dobrany na podstwie pierwszej serii eksperymentów.
Podobnie jak w przypadku eksperymentów przeprowadzonych na architekturze R-Transformer, wszystkie parametery poza badanym ustawione były na domyślne wartości: liczba warstw 2, 200 komórek w warstwie ukrytej, wymiar zanurzenia równy 256, parametr uczenia się równy 20, dropout 0.25 oraz batch size i długość sekwencji 32. Maksymalna norma gradientów ustawiona była na wartość wynoszącą 0.25, a wartość parametru uczenia się redukowana była czterokrotnie po każdej epoce, w której metryka błędu nie uległa poprawie (parametr *scheduler\_patience* równy 1).
#### Wpływ współczynnika uczenia się
Eksperymenty zostały przeprowadzone dla wartości współrzynnika uczenia: 5, 10, 15 oraz 20.
**Dla rekurencyjnej sieci neuronowej z LSTM:**

Wyniki poszczególnych modeli na zbiorze testowym:
|Współczynnik uczenia się | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|5 |107.703 | 4.679|
|**10** | **103.573**| **4.64**|
|15 | 103.808 | 4.643|
|20 | 105.23| 4.656|
**Dla rekurencyjnej sieci neuronowej z GRU:**

|Współczynnik uczenia się | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|**5** | **116.954**| **4.762**|
|10 | 124.094| 4.821|
|15 | 135.726 | 4.911|
|20 | 152.533| 5.027|
**Wnioski:**
Zaobserwowano, że optymalna wartość współczynnika uczenia się jest inna dla sieci z LSTM i dla sieci z GRU. W przypadku LSTM optymalną wartością jest 10, co ciekawe dla tej to wartości współczynnik uczenia się spada najpóźniej i do najniższej wartości.
Natomiast dla GRU okazało się, że lepsza jest niższa początkowa wartość współczynnika uczenia się wynosząca 5. Można tu także zaobserwować, że wartość tego współczynnika spada najpóźniej i ostatecznie osiąga najniższą wartość.
#### Wpływ parametru dropout
**Dla rekurencyjnej sieci neuronowej z LSTM:**

|Wartość dropout | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|0.0 |127.926 |4.851 |
|**0.25** |**106.951** |**4.672** |
|0.5 |135.535 | 4.909|
|0.75 |225.83 | 5.420|
**Dla rekurencyjnej sieci neuronowej z GRU:**

|Wartość dropout | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|0.0 |160.727 |5.08 |
|**0.25** |**155.604** |**5.047** |
|0.5 |216.357 |5.377|
|0.75 |641.631 |6.464|
**Wnioski:**
Najlepszym okazał się współczynnik dropoutu 0.5 zarówno dla sieci LSTM, jak i GRU. Dla dropoutu 0 można zaobserwować na wykresie Validation Loss podnoszenie się straty po gwałtownym spadku, czyli efekt przeuczania się sieci (wynika stąd, że dropout faktycznie jest potrzebny, aby się temu efektowi przeciwstawić).
Dla dropoutu 0.75 sieć prawie wcale nie zmienia straty na zbiorze walidacyjnym - pozostawionych wag jest zbyt mało, aby model mógł się nauczyć dokonywania poprawnej predykcji.
#### Wpływ liczby komórek w warstwie ukrytej
**Dla rekurencyjnej sieci neuronowej z LSTM:**

|Liczba komórek | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|50 |155.063 |5.044 |
|100 |119.753 |4.785 |
|150 |108.358 |4.685|
|200 |105.23 |4.656|
|250 |101.856 |4.624|
|**300** |**100.904** |**4.614**|
**Dla rekurencyjnej sieci neuronowej z GRU:**

|Liczba komórek | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|50 |198.998 |5.293 |
|100 |172.168 |5.148 |
|150 |160.132 |5.076|
|200 |152.533 |5.027|
|250 |143.471 |4.966|
|**300** |**141.019** |**4.949**|
**Wnioski:**
Liczba komórek w warstwie ukrytej ma znaczący wpływ na jakość dokonywanej predykcji. W przypadku sieci z LSTM różnica pomiędzy wynikami perplexity na zbiorze testowym osiągniętym dla 50 i 300 komórek w warstwie ukrytej osiągnęła 54.159, natomiast dla sieci z GRU: 57.979.
Ciekawą obserwacją jest to, że jakość predykcji wzrastała bardziej przy początkowym zwiększaniu parametru ustawionego na 50, a im większa była liczba komórek w warstwie ukrytej, tym mniejsze znaczenie miało zwiększenie parametru - pomiędzy ustawieniem parametru 250 a 300 różnica perplexity na zbiorze testowym wyniosła 0.952 dla LSTM i 2.452 dla GRU, natomiast pomiędzy 50 a 100 dla LSTMa różnica wynosiła aż 35.31, a dla GRU 26.83.
#### Podsumowanie pierwszych trzech eksperymentów
Pierwsza seria trzech eksperymentów wykazała, że najlepszym ustawieniem paramerów dla modelu LSTM jest:
* współczynnik uczenia się: 10
* parametr dropoutu: 0.25
* liczba komórek w warstwie ukrytej: 300
Natomiast dla modelu GRU:
* współczynnik uczenia się: 5
* parametr dropoutu: 0.25
* liczba komórek w warstwie ukrytej: 300
Ciekawą obserwacją jest to, że optymalny współczynnik uczenia się dla sieci z mechanizmem GRU jest niższy niż dla sieci z mechanizmem LSTM.
W kolejnych eksperymentach parametr dropoutu oraz współczynnik uczenia został dobrany tak, jak przedstawiają powyższe najlepsze ustawienia. Natomiast liczba komórek w warstwach ukrytych została ustawiona na 250, a nie, jak wskazują najlepsze wyniki na 300. Powodem jest obserwacja, że zmiana o 50 powyższego parametru nie powoduje dużych zmian w końcowej mierze jakości perplexity, a istniała obawa, że zbyt duża liczba komórek w ukrytej warstwie przyczyni się do wydłużenia czasu trenowania się modelu.
#### Wpływ liczby warstw
**Dla rekurencyjnej sieci neuronowej z LSTM:**

|Liczba warstw | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|1 |116.381 |4.757 |
|**2** |**102.65** |**4.631** |
|3 |106.788 |4.671|
|4 |106.769 |4.671|
**Dla rekurencyjnej sieci neuronowej z GRU:**

|Liczba warstw | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|1 |124.564 |4.825 |
|2 |117.009 |4.762 |
|**3** |**115.974** |**4.753**|
|4 |119.26 |4.781|
**Wnioski:**
Dla sieci z LSTM najlepsze wyniki osiąga używanie dwóch warstw LSTM, natomist dla GRU - trzech warstw.
#### Wpływ wymiaru zanurzenia
**Dla rekurencyjnej sieci neuronowej z LSTM:**

|Wymiar zanurzenia | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|50 |111.035 |4.71 |
|100 |106.669 |4.67 |
|150 |109.33 |4.694|
|200 |104.019 |4.645|
|250 |106.081 |4.664|
|**300** |<span style="color:red">**100.364**</span> |<span style="color:red">**4.609**</span>|
|350 |101.065 |4.616|
|400 |100.37 |4.609|
**Dla rekurencyjnej sieci neuronowej z GRU:**

|Wymiar zanurzenia | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|50 |141.774 |4.954 |
|100 |125.722 |4.834 |
|150 |120.917 |4.795|
|200 |118.94 |4.779|
|250 |118.104 |4.772|
|300 |114.024 |4.736|
|350 |113.871 |4.735|
|**400** |<span style="color:red">**112.032**</span> |<span style="color:red">**4.719**</span>|
**Wnioski:**
Zmiana wymiaru zanurzenia ma znaczący wpływ na poprawność dokonywanych przez model predykcji.
Dla sieci z LSTM najlepszy wynik osiągnął model, dla którego tenże parametr wynosił 300, aczkolwiek zmiany dla wymiaru zanurzenia 350 i 400 nie są aż tak znacząco gorsze. Wynika stąd, że powiększanie dalej wymiaru zanurzenia nie poprawiłoby już predykcji.
Natomiast dla GRU najlepszy wynik został osiągnięty dla wymiaru zanurzenia 400.
#### Wpływ długości sekwencji
**Dla rekurencyjnej sieci neuronowej z LSTM:**

|Długość sekwencji | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|10 | 103.911| 4.644|
|20 | 102.9| 4.634|
|30 | 104.449| 4.649|
|40 | 101.814| 4.623|
|**50** | **101.606**| **4.621**|
|60 | 105.813| 4.662|
**Dla rekurencyjnej sieci neuronowej z GRU:**

|Długość sekwencji | Test Perplexity | Test Loss |
| -------- | -------- | -------- |
|10 | 124.534| 4.825|
|20 | 118.77| 4.777|
|30 | 116.113| 4.755|
|**40** | **114.555**| **4.741**|
|50 | 115.038| 4.745|
|60 | 120.752| 4.794|
**Wnioski:**
Eksperyment wykazał, że optymalna długość sekwencji wynosi 40-50 (40 dla modelu GRU, a 50 dla modelu LSTM).
## Wyniki
Poniższa tabela zestawia najlepszą kombinację parametrów dla każdego z badanych typów modeli.
| Nazwa modelu | Parametry | Wynik (perplexity) |
| -------- | -------- | -------- |
| GRU | wymiar zanurzenia: 400, komórki w warstwie ukrytej: 250, liczba warstw: 2, współczynnik uczenia się: 5, liczba epok: 30, batch size: 32, długość sekwencji: 32, dropout: 0.25 |112.032|
| LSTM | wymiar zanurzenia: 300, komórki w warstwie ukrytej: 250, liczba warstw: 2, współczynnik uczenia się: 10, liczba epok: 30, batch size: 32, długość sekwencji: 32, dropout: 0.25 |**100.364**|
| R-Transformer | wymiar zanurzenia: 256, liczba warstw: 4, szerokość okna: 9, liczba głów atencji: 8, współczynnik uczenia się: 3, długość sekwencji: 32, batch size: 32, dropout: 0.35 | 138.387 |
Wynika z niej, że do realizacji zadania modelowania języka, najlepszym sporśród badanych typów modeli okazał się być model oparty o komórki LSTM. R-Transformer dawał najbardziej rozczarowujące rezultaty, biorąc pod uwagę jego złożoność.
## Wnioski i przemyślenia
* Niestety nie udało nam się odtworzyć wyników, jakie autorzy publikacji osiągnęli z wykorzystaniem modelu R-Transformer. Jednym z powodów było to, że niestety implementacja autorów nie jest w pełni zgodna z ich publikacją, co było dla nas dosyć problematyczne w trakcie wykonywania naszego zadania.
* Rozmiar okna oraz liczba głów atencji, w badanym zakresie wartości, nie miały znaczącego wpływu na jakość modelu języka, reprezentowanego przez sieć opartą o R-Transformera, co może sugerować niepoprawność implementacji.
* Jakość predykcji rośnie wraz ze wzrostem wymiaru zanurzenia i parametr ten miał duże znaczenie - szczególnie w zakresie mniejszych jego wartości.
* Rosnąca liczba komórek w warstwie ukrytej ma pozytywny wpływ na jakość modelu.
* Modele z dużą liczbą warstw są trudniejsze do uczenia, gdyż osiągały czasem gorsze rezultaty niż mniejsze modele.
* Model oparty o architekturę R-Transformera trenował się najdłużej, a osiągał jedne z najgorszych rezultatów.
* Modele działały lepiej, gdy były trenowane na dłuższych sekwencjach, co jest zgodne z oczekiwaniami, gdyż wtedy mają szanse poznać szerszy kontekst zdania. Dla zbyt długich sekwencji modele oparte o komórki GRU/LSTM osiągały jednak gorsze wyniki.