diff --git a/wyk/10_Atencja.ipynb b/wyk/10_Atencja.ipynb index 0f8a603..ecaf967 100644 --- a/wyk/10_Atencja.ipynb +++ b/wyk/10_Atencja.ipynb @@ -1 +1,19 @@ -{"cells":[{"cell_type":"markdown","metadata":{},"source":["## Atencja\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Sieci LSTM w roku 2017/2018 zostały wyparte przez nową, pod pewnymi\nwzględami prostszą, architekturę Transformer. Sieci Transformer oparte\nsą zasadniczo na prostej idei **atencji** (*attention*), pierwszy\nartykuł wprowadzający sieci Transformer nosił nawet tytuł\n[Attention Is All You Need]([https://arxiv.org/abs/1706.03762](https://arxiv.org/abs/1706.03762)).\n\nIntuicyjnie, atencja jest rodzajem uwagi, którą sieć może selektywnie\nkierować na wybrane miejsca (w modelowaniu języka: wybrane wyrazy).\n\nIdea atencji jest jednak wcześniejsza, powstała jako ulepszenie sieci\nrekurencyjnych. My omówimy ją jednak na jeszcze prostszym przykładzie\nużycia w modelowaniu języka za pomocą hybrydy modelu\nbigramowego i modelu worka słów.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Prosty przykład zastosowania atencji\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Wróćmy do naszego przykładu z Wykładu 8, w którym łączyliśmy $n$-gramowy\nmodel języka z workiem słów. Przyjmijmy bigramowy model języka ($n=2$), wówczas:\n\n$$y = \\operatorname{softmax}(C[E(w_{i-1}),A(w_1,\\dots,w_{i-2})]),$$\n\ngdzie $A$ była prostą agregacją (np. sumą albo średnią) embeddingów\n$E(w_1),\\dots,E(w_{i-2})$. Aby wyjść z prostego nieuporządkowanego\nmodelu worka słów, próbowaliśmy w prosty sposób uwzględnić pozycję\nwyrazów czy ich istotność (za pomocą odwrotnej częstości\ndokumentowej). Oba te sposoby niestety zupełnie nie uwzględniają kontekstu.\n\nInnymi słowy, chcielibyśmy mieć sumę ważoną zanurzeń:\n\n$$A(w_1,\\dots,j) = \\omega_1 E(w_1) + \\dots \\omega_j E(w_j) = \\sum_{k=1}^j \\omega_k E(w_k),$$\n\ntak by $\\omega_k$ w sposób bardziej zasadniczy zależały od lokalnego kontekstu, a\nnie tylko od pozycji $k$ czy słowa $w_k$. W naszym prostym przypadku\njako kontekst możemy rozpatrywać słowo bezpośrednio poprzedzające\nodgadywane słowa (kontekstem jest $w_{i-1}$).\n\nWygodnie również przyjąć, że $\\sum_{k=1}^j \\omega_k = 1$, wówczas mamy do czynienia ze średnią ważoną.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Nieznormalizowane wagi atencji\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Będziemy liczyć nieznormalizowane ****wagi atencji****\n$\\hat{\\alpha}_{k,j}$. Określają one, jak bardzo słowo $w_j$ „zwraca\nuwagę” na poszczególne, inne słowa. Innymi słowy, wagi je opisują, jak\nbardzo słowo $w_k$ pasuje do naszego kontekstu, czyli słowa $w_j$.\n\nNajprostszy sposób mierzenia dopasowania to po prostu iloczyn skalarn:\n\n$$\\hat{\\alpha}_{k,j} = E(w_k)E(w_j),$$\n\nmożna też alternatywnie złamać symetrię iloczynu skalarnego i\nwyliczać dopasowanie za pomocą prostej sieci feed-forward:\n\n$$\\hat{\\alpha}_{k,j} =\n\\vec{v}\\operatorname{tanh}(W_{\\alpha}[E(w_k),E(w_j)] +\n\\vec{b_{\\alpha}}).$$\n\nW drugim przypadku pojawiają się dodatkowe wyuczalne paramatery: macierz $W_{\\alpha}$, wektory\n$\\vec{b_{\\alpha}}$ i $\\vec{v}$.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Normalizacja wag atencji\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Jak już wspomniano, dobrze żeby wagi atencji sumowały się do 1. W tym celu możemy po prostu zastosować\nfunkcję softmax:\n\n$$\\alpha_{k,j} = \\operatorname{softmax}([\\hat{\\alpha}_{1,j},\\dots,\\hat{\\alpha}_{j-1,j}]).$$\n\nZauważmy jednak, że otrzymanego z funkcji softmax wektora\n$[\\alpha_{1,j},\\dots,\\alpha_{j-1,j}]$ tym razem nie interpretujemy jako rozkład prawdopodobieństwa.\nJest to raczej rozkład uwagi, atencji słowa $w_j$ względem innych słów.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Użycie wag atencji w prostym neuronowym modelu języka\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Teraz jako wagi $\\omega$ w naszym modelu języka możemy przyjąć:\n\n$$\\omega_k = \\alpha_{k,i-1}.$$\n\nOznacza to, że z naszego worka będziemy „wyjmowali” słowa w sposób\nselektywny w zależności od wyrazu, który bezpośrednio poprzedza\nsłowo odgadywane.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Diagram\n\n"]},{"cell_type":"markdown","metadata":{},"source":["![img](./10_Atencja/simple-attention.drawio.png \"Atencja użyta w prostym neuronowym modelu języka\")\n\n"]}],"metadata":{"org":null,"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.5.2"}},"nbformat":4,"nbformat_minor":0} \ No newline at end of file + +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n", + "
\n", + "

Modelowanie języka

\n", + "

10. Atencja [wykład]

\n", + "

Filip Graliński (2022)

\n", + "
\n", + "\n", + "![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)\n", + "\n" + ] + }, +{"cell_type":"markdown","metadata":{},"source":["## Atencja\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Sieci LSTM w roku 2017/2018 zostały wyparte przez nową, pod pewnymi\nwzględami prostszą, architekturę Transformer. Sieci Transformer oparte\nsą zasadniczo na prostej idei **atencji** (*attention*), pierwszy\nartykuł wprowadzający sieci Transformer nosił nawet tytuł\n[Attention Is All You Need]([https://arxiv.org/abs/1706.03762](https://arxiv.org/abs/1706.03762)).\n\nIntuicyjnie, atencja jest rodzajem uwagi, którą sieć może selektywnie\nkierować na wybrane miejsca (w modelowaniu języka: wybrane wyrazy).\n\nIdea atencji jest jednak wcześniejsza, powstała jako ulepszenie sieci\nrekurencyjnych. My omówimy ją jednak na jeszcze prostszym przykładzie\nużycia w modelowaniu języka za pomocą hybrydy modelu\nbigramowego i modelu worka słów.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Prosty przykład zastosowania atencji\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Wróćmy do naszego przykładu z Wykładu 8, w którym łączyliśmy $n$-gramowy\nmodel języka z workiem słów. Przyjmijmy bigramowy model języka ($n=2$), wówczas:\n\n$$y = \\operatorname{softmax}(C[E(w_{i-1}),A(w_1,\\dots,w_{i-2})]),$$\n\ngdzie $A$ była prostą agregacją (np. sumą albo średnią) embeddingów\n$E(w_1),\\dots,E(w_{i-2})$. Aby wyjść z nieuporządkowanego\nmodelu worka słów, próbowaliśmy w prosty sposób uwzględnić pozycję\nwyrazów czy ich istotność (za pomocą odwrotnej częstości\ndokumentowej). Oba te sposoby niestety zupełnie nie uwzględniają **kontekstu**.\n\nInnymi słowy, chcielibyśmy mieć sumę ważoną zanurzeń:\n\n$$A(w_1,\\dots,j) = \\omega_1 E(w_1) + \\dots + \\omega_j E(w_j) = \\sum_{k=1}^j \\omega_k E(w_k),$$\n\ntak by $\\omega_k$ w sposób bardziej zasadniczy zależały od lokalnego kontekstu, a\nnie tylko od pozycji $k$ czy słowa $w_k$. W naszym uproszczonym przypadku\njako kontekst możemy rozpatrywać słowo bezpośrednio poprzedzające\nodgadywane słowa (kontekstem jest $w_{i-1}$).\n\nWygodnie również przyjąć, że $\\sum_{k=1}^j \\omega_k = 1$ i $\\omega_k\n\\in (0,1)$, wówczas mamy do czynienia ze średnią ważoną.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Nieznormalizowane wagi atencji\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Będziemy liczyć nieznormalizowane ****wagi atencji****\n$\\hat{\\alpha}_{k,j}$. Określają one, jak bardzo słowo $w_j$ „zwraca\nuwagę” na poszczególne, inne słowa. Innymi słowy, wagi atencji opisują, jak\nbardzo słowo $w_k$ pasuje do naszego kontekstu, czyli słowa $w_j$.\n\n**Uwaga**: (nieznormalizowane czy znormalizowane) wagi atencji nie należą do wyuczalnych\nwag (parametrów) modelu.\n\nNajprostszy sposób mierzenia dopasowania to po prostu iloczyn skalarny:\n\n$$\\hat{\\alpha}_{k,j} = E(w_k)E(w_j),$$\n\nmożna też alternatywnie złamać symetrię iloczynu skalarnego i\nwyliczać dopasowanie za pomocą prostej sieci feed-forward:\n\n$$\\hat{\\alpha}_{k,j} =\n\\vec{v}\\operatorname{tanh}(W_{\\alpha}[E(w_k),E(w_j)] +\n\\vec{b_{\\alpha}}).$$\n\nW drugim przypadku pojawiają się dodatkowe wyuczalne paramatery: macierz $W_{\\alpha}$, wektory\n$\\vec{b_{\\alpha}}$ i $\\vec{v}$.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Normalizacja wag atencji\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Jak już wspomniano, dobrze żeby wagi atencji sumowały się do 1. W tym celu możemy po prostu zastosować\nfunkcję softmax:\n\n$$\\alpha_{k,j} = \\operatorname{softmax}([\\hat{\\alpha}_{1,j},\\dots,\\hat{\\alpha}_{j-1,j}]).$$\n\nZauważmy jednak, że otrzymanego z funkcji softmax wektora\n$[\\alpha_{1,j},\\dots,\\alpha_{j-1,j}]$ tym razem nie interpretujemy jako rozkład prawdopodobieństwa.\nJest to raczej rozkład uwagi, atencji słowa $w_j$ względem innych słów.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Użycie wag atencji w prostym neuronowym modelu języka\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Teraz jako wagi $\\omega$ w naszym modelu języka możemy przyjąć:\n\n$$\\omega_k = \\alpha_{k,i-1}.$$\n\nOznacza to, że z naszego worka będziemy „wyjmowali” słowa w sposób\nselektywny, w zależności od wyrazu, który bezpośrednio poprzedza\nsłowo odgadywane.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Diagram\n\n"]},{"cell_type":"markdown","metadata":{},"source":["![img](./10_Atencja/simple-attention.drawio.png \"Atencja użyta w prostym neuronowym modelu języka\")\n\n"]},{"cell_type":"markdown","metadata":{},"source":["### Atencja jako składnik sieci rekurencyjnej\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Atencję wprowadzono pierwotnie jako uzupełnienie sieci rekurencyjnej.\nPotrzeba ta pojawiła się na początku rozwoju **neuronowego tłumaczenia\nmaszynowego** (*neural machine translation*, *NMT*), czyli tłumaczenia\nmaszynowego (automatycznego) realizowanego za pomocą sieci neuronowych.\n\nNeuronowe tłumaczenie maszynowe jest właściwie rozszerzeniem idei\nmodelowania języka na biteksty (teksty równoległe). Omówmy najpierw\npodstawy generowania tekstu.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Model języka jako generator\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Jak pamiętamy, model języka $M$ wylicza prawdopodobieństwo tekstu $w_1,\\dots,w_N$:\n\n$$P_M(w_1,\\dots,w_N) = ?.$$\n\nZazwyczaj jest to równoważne obliczaniu rozkładu prawdopodobieństwa kolejnego słowa:\n\n$$P_M(w_j|w_1,\\dots,w_{j-1}) = ?.$$\n\nZałóżmy, że mamy pewien początek (**prefiks**) tekstu o długości $p$:\n$w_1,\\dots,w_p$. Powiedzmy, że naszym celem jest **wygenerowanie**\ndokończenia czy kontynuacji tego tekstu (nie określamy z góry\ndługości tej kontynuacji).\n\nNajprostszy sposób wygenerowania pierwszego wyrazu dokończenia polega\nna wzięciu wyrazu maksymalizującego prawdopodobieństwo według modelu języka:\n\n$$w_{p+1} = \\operatorname{argmax}_w P_M(w|w_1,\\dots,w_p).$$\n\n**Pytanie**: Dlaczego $\\operatorname{argmax}$, a nie $\\operatorname{max}$?\n\nSłowo $w_{p+1}$ możemy dołączyć do prefiksu i powtórzyć procedurę:\n\n$$w_{p+2} = \\operatorname{argmax}_w P_M(w|w_1,\\dots,w_p,w_{p+1}),$$\n\ni tak dalej.\n\n**Pytanie**: Kiedy zakończymy procedurę generowania?\n\nOmawiana procedura jest najprostszym sposobem, czasami nie daje\nnajlepszego wyniku, na przykład może pojawić się efekt „jąkania”\n(model generuje w kółko ten sam wyraz), dlatego opracowano bardziej\nwymyślne sposoby generowania w oparciu o modele języka. Omówimy je później.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Zastosowania generatora opartego na modelu języka\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Mogłoby się wydawać, że generator tekstu ma raczej ograniczone\nzastosowanie (generowanie fake newsów?). Okazuje się jednak, że\nzaskakująco wiele zadań przetwarzania języka naturalnego można\nprzedstawić jako zadanie generowania tekstu. Przykładem jest tłumaczenie maszynowe.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Tłumaczenie maszynowe jako zadanie generowania tekstu\n\n"]},{"cell_type":"markdown","metadata":{},"source":["W tłumaczeniu maszynowym (tłumaczeniu automatycznym, ang. *machine\ntranslation*) na wejściu podawany jest tekst (na ogół pojedyncze\nzdanie) źródłowy (*source sentence*) $S = (u_1,\\dots,u_{|S|})$, celem\njest uzyskanie tekstu docelowego (*target sentence*)\n$T=(w_1,\\dots,w_{|T|})$. Zakładamy, że $S$ jest tekstem w pewnym języku\nźródłowym (*source language*), zaś $T$ — w innym języku, języku\ndocelowym (*target language*).\n\nWspółczesne tłumaczenie maszynowe jest oparte na metodach\nstatystycznych — system uczy się na podstawie obszernego zbioru\nodpowiadających sobie zdań w obu językach. Taki zbiór nazywamy\nkorpusem równoległym (*parallel corpus*). Duży zbiór korpusów\nrównoległych dla wielu języków można znaleźć na stronie projektu [OPUS]([https://opus.nlpl.eu/](https://opus.nlpl.eu/)).\nZobaczmy na przykład fragment EUROPARL (protokoły Parlamentu Europejskiego):\n\n $ wget 'https://opus.nlpl.eu/download.php?f=Europarl/v8/moses/en-pl.txt.zip' -O en-pl.txt.zip\n $ unzip en-pl.txt.zip\n $ paste Europarl.en-pl.en Europarl.en-pl.pl | shuf -n 5\n The adoption of these amendments by the Committee on the Environment meant that we could place more emphasis on patients' rights to information, rather than make it an option for the pharmaceutical industries to provide that information.\tPrzyjęcie tych poprawek przez Komisję Ochrony Środowiska Naturalnego oznaczało, że mogliśmy położyć większy nacisk na prawo pacjentów do informacji, zamiast uczynić zeń możliwość, z której branża farmaceutyczna może skorzystać w celu dostarczenia informacji.\n I hope that the High Representative - who is not here today - will raise this episode with China and also with Nepal, whose own nascent democracy is kept afloat partly by EU taxpayers' money in the form of financial aid.\tMam nadzieję, że nieobecna dzisiaj wysoka przedstawiciel poruszy tę kwestię w rozmowach z Chinami, ale również z Nepalem, którego młoda demokracja funkcjonuje częściowo dzięki finansowej pomocy pochodzącej z pieniędzy podatników w UE.\n Immunity and privileges of Renato Brunetta (vote)\tWniosek o obronę immunitetu parlamentarnego Renata Brunetty (głosowanie)\n The 'new Member States' - actually, the name continues to be sort of conditional, making it easier to distinguish between the 'old' Member States and those that acceded to the EU after two enlargement rounds, owing to their particular historical background and perhaps the fact that they are poorer than the old ones.\"Nowe państwa członkowskie” - ta nazwa nadal ma w pewnym sensie charakter warunkowy i ułatwia rozróżnienie pomiędzy \"starszymi” państwami członkowskimi oraz tymi, które przystąpiły do UE po dwóch rundach rozszerzenia, które wyróżnia ich szczególna historia, a zapewne także fakt, że są uboższe, niż starsze państwa członkowskie.\n The number of armed attacks also rose by 200% overall.\tTakże liczba ataków zbrojnych wzrosła łącznie o 200 %.\n\nZauważmy, że możemy taki (bi)tekst modelować po prostu traktując jako\njeden ciągły tekst. Innymi słowy, nie modelujemy tekstu angielskiego ani polskiego,\ntylko angielsko-polską mieszankę, to znaczy uczymy model, który najpierw modeluje prawdopodobieństwo\npo stronie źródłowej (powiedzmy — angielskiej):\n\n The number of armed attacks also ?\n\nW momencie napotkania specjalnego tokenu końca zdania źródłowego (powiedzmy ``) model\npowinien nauczyć się, że musi przełączyć się na modelowanie tekstu w języku docelowym (powiedzmy — polskim):\n\n The number of armed attacks also rose by 200% overall.Także liczba ataków ?\n\nW czasie uczenia wykorzystujemy korpus równoległy traktując go po prostu jako zwykły ciągły tekst\n(dodajemy tylko specjalne tokeny końca zdania źródłowego i końca zdania docelowego).\n\nW fazie inferencji (w tłumaczeniu maszynowym tradycyjnie nazywaną\n**dekodowaniem**) zamieniamy nasz model języka w generator i podajemy\ntłumaczone zdanie jako prefiks, doklejając tylko token ``.\n\n"]},{"cell_type":"markdown","metadata":{},"source":["##### Neuronowe modele języka jako translatory\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Jako że n-gramowego modelu języka ani modelu opartego na worku słów\nnie da się użyć w omawiany sposób w tłumaczeniu maszynowym\n(dlaczego?), jako pierwszych użyto w neuronowym tłumaczeniu maszynowym\nsieci LSTM, przy zastosowaniu omawianego wyżej sposobu.\n\nSystem tłumaczenia oparte na sieciach LSTM działały zaskakująco\ndobrze, zważywszy na to, że cała informacja o zdaniu źródłowym musi\nzostać skompresowana do wektora o stałym rozmiarze. (Dlaczego? W\nmomencie osiągnięcia tokenu `` cały stan sieci to kombinacja\nwłaściwego stanu $\\vec{s_i}$ i komórki pamięci $\\vec{c_i}$.)\n\nNeuronowe tłumaczenie oparte na sieciach LSTM działa względnie dobrze\ndla krótkich zdań, dla dłuższych rezultaty są gorsze — po prostu sieć\nnie jest w stanie skompresować w wektorze o stałej długości znaczenia\ncałego zdania. Na początku rozwoju neuronowego tłumaczenia maszynowego\nopracowano kilka metod radzenia sobie z tym problemem (np. zaskakująco\ndobrze działa odwrócenie zdania źródłowego — siec LSTM łatwiej zacząć\ngenerować zdanie docelowe, jeśli niedawno „widziała” początek zdania\nźródłowego, przynajmniej dla pary języków o podobnym szyku).\n\nNajlepsze efekty dodało dodanie atencji do modelu LSTM\n\n"]},{"cell_type":"markdown","metadata":{},"source":["##### Atencja w sieciach rekurencyjnych\n\n"]},{"cell_type":"markdown","metadata":{},"source":["Funkcję rekurencyjną można rozbudować o trzeci argument, w którym\npodany będzie wynik działania atencji $A'$ względem ostatniego wyrazu, tj.:\n\n$$A(w_1,\\dots,w_t) = R(A(w_1,\\dots,w_{t-1}), A'(w_1,\\dots,w_{t-1}), E(w_t)),$$\n\nW czasie tłumaczenia model może kierować swoją uwagę na wyrazy\npowiązane z aktualnie tłumaczonym fragmentem (zazwyczaj — po prostu odpowiedniki).\n\n"]}],"metadata":{"org":null,"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.5.2"}},"nbformat":4,"nbformat_minor":0} \ No newline at end of file diff --git a/wyk/10_Atencja.org b/wyk/10_Atencja.org index e976b7c..46bb6e8 100644 --- a/wyk/10_Atencja.org +++ b/wyk/10_Atencja.org @@ -37,15 +37,19 @@ nie tylko od pozycji $k$ czy słowa $w_k$. W naszym uproszczonym przypadku jako kontekst możemy rozpatrywać słowo bezpośrednio poprzedzające odgadywane słowa (kontekstem jest $w_{i-1}$). -Wygodnie również przyjąć, że $\sum_{k=1}^j \omega_k = 1$, wówczas mamy do czynienia ze średnią ważoną. +Wygodnie również przyjąć, że $\sum_{k=1}^j \omega_k = 1$ i $\omega_k +\in (0,1)$, wówczas mamy do czynienia ze średnią ważoną. *** Nieznormalizowane wagi atencji Będziemy liczyć nieznormalizowane **wagi atencji** $\hat{\alpha}_{k,j}$. Określają one, jak bardzo słowo $w_j$ „zwraca -uwagę” na poszczególne, inne słowa. Innymi słowy, wagi opisują, jak +uwagę” na poszczególne, inne słowa. Innymi słowy, wagi atencji opisują, jak bardzo słowo $w_k$ pasuje do naszego kontekstu, czyli słowa $w_j$. +*Uwaga*: (nieznormalizowane czy znormalizowane) wagi atencji nie należą do wyuczalnych +wag (parametrów) modelu. + Najprostszy sposób mierzenia dopasowania to po prostu iloczyn skalarny: $$\hat{\alpha}_{k,j} = E(w_k)E(w_j),$$ @@ -86,67 +90,6 @@ słowo odgadywane. #+CAPTION: Atencja użyta w prostym neuronowym modelu języka [[./10_Atencja/simple-attention.drawio.png]] -** Atencja jako „miękka” baza danych - -O atencji można myśleć metaforycznie jako o odpytywaniu „miękkiej”, wektorowej -bazy danych. Możemy sobie wyobrazić, że słowa $w_1,\dots,w_{j-1}$ są -naszą bazą danych, a słowo $w_j$ (z którego kierujemy „snop” uwagi) -jest *zapytaniem* (/query/). To zapytanie dopasowujemy do *kluczy* -(/keys/), w najprostszym ujęciu po prostu słów $w_1,\dots,w_{j-1}$ (a -właściwie ich zanurzeń). Jeśli klucz pasuje do zapytania, odpowiednia -wartość (/value/) jest wydobywana z bazy. Nasza baza jest jednak -„miękka”, nie — zerojedynkowa, zapytanie pasuje klucza w pewnym -stopniu, mniej lub bardziej. - -W najprostszym ujęciu wartości są tym samym co klucze, czyli z naszej -bazy wydobywamy te same zanurzenia słów, których używamy jako kluczy. -Można jednak skomplikować schemat rozróżniając klucze i wartości — -mogą one powstawać przez rzutowanie podstawowe zanurzenia różnymi -macierzami: - -$$\vec{k_i} = W_k E(w_i),$$ - -$$\vec{v_i} = W_v E(w_i).$$ - -Również samo zapytanie może powstać przez rzutowanie: - -$$\vec{q_i} = W_q E(w_i).$$ - -Jeśli zanurzenie $E(w_i)$ o rozmiarze $m$ przedstawimy w postaci -kolumnowej, wówczas macierze będą $W_k$ i $W_q$ będą miały rozmiar -$d_k \times m$, gdzie $d_k$ jest rozmiarem kluczy i zapytań (dlaczego -wektory kluczy i zapytań powinny mieć raczej ten sam rozmiar?), zaś macierz -$W_v$ — $d_v \times m$, gdzie $d_v$ to rozmiar zanurzenia wektora wartości. -Zazwyczaj $d_k = d_v = m$, ale nie jest to obligatoryjne. - -Teraz nieznormalizowane wagi atencji przyjmą postać: - -$$\hat{\alpha}_{i,j} = \vec{q_i}^T\vec{k_j} = (W_q E(w_i))(W_k E(k_j)).$$ - -Zauważmy, że ciąg $\hat{\alpha}_{1,j},\dots,\hat{\alpha}_{j-1,j}$ można potraktować jako wektor -$\hat{\vec{\alpha}_{*,j}}$ i wyliczać w postaci zwartej: - -$$\hat{\vec{\alpha}_{*,j}} = \vec{k_j}^T K$$ - -gdzie $K$ to macierz kluczy złożona z wektorów -$\vec{k_1},\dots,\vec{k_{j-1}}$, tj. macierz o rozmiarze $d_k \times (j-1)$. - -Wektor znormalizowanych wag atencji będzie miał wówczas postać: - -$$\vec{\alpha}_{*,j} = \operatorname{softmax}(\vec{k_j}^T K).$$ - -Dokonajmy teraz agregacji wartości — obliczeniamy średnią wektorów -wartości (\vec{v_i}) ważoną atencją: - -$$A(w_1,\dots,j-1) = \alpha_{1,j} \vec{v_1} + \dots + \alpha_{j-1,j} \vec{v_{j-1}} = \sum_{i=1}^{j-1} \alpha_{i,j} v_i.$$ - -Jeśli $j-1$ wektorów wartości ułożyłem w macierz $V$ (o rozmiarze -$(j-1) \times d_v$), powyższy wzór będziemy mogli zapisać jako iloczyn wektora wag atencji i macierzy $V$: - -$$A(w_1,\dots,j-1) = \vec{\alpha}_{*,j}^T V = \operatorname{softmax}(\vec{k_j}^T K)^T V.$$ - -Sposób patrzenia na atencję przez pryzmat trójki -zapytania-klucze-wartości okaże się niezwykle ważny w wypadku modelu Transformer (zob. kolejny wykład). ** Atencja jako składnik sieci rekurencyjnej @@ -171,7 +114,7 @@ $$P_M(w_j|w_1,\dots,w_{j-1}) = ?.$$ Załóżmy, że mamy pewien początek (*prefiks*) tekstu o długości $p$: $w_1,\dots,w_p$. Powiedzmy, że naszym celem jest *wygenerowanie* -dokończenia czy kontynuacji tego tekstu (nie określamy z góry tej +dokończenia czy kontynuacji tego tekstu (nie określamy z góry długości tej kontynuacji). Najprostszy sposób wygenerowania pierwszego wyrazu dokończenia polega @@ -179,7 +122,7 @@ na wzięciu wyrazu maksymalizującego prawdopodobieństwo według modelu języka $$w_{p+1} = \operatorname{argmax}_w P_M(w|w_1,\dots,w_p).$$ -*Pytanie*: Dlaczego \operatorname{argmax}, a nie \operatorname{max}? +*Pytanie*: Dlaczego $\operatorname{argmax}$, a nie $\operatorname{max}$? Słowo $w_{p+1}$ możemy dołączyć do prefiksu i powtórzyć procedurę: @@ -205,9 +148,9 @@ przedstawić jako zadanie generowania tekstu. Przykładem jest tłumaczenie masz W tłumaczeniu maszynowym (tłumaczeniu automatycznym, ang. /machine translation/) na wejściu podawany jest tekst (na ogół pojedyncze -zdanie) źródłowy (/source sentence/) $S = (u_1,\dots,u_|S|)$, celem +zdanie) źródłowy (/source sentence/) $S = (u_1,\dots,u_{|S|})$, celem jest uzyskanie tekstu docelowego (/target sentence/) -$T=(w_1,\dots,w_|T|). Zakładamy, że $S$ jest tekstem w pewnym języku +$T=(w_1,\dots,w_{|T|})$. Zakładamy, że $S$ jest tekstem w pewnym języku źródłowym (/source language/), zaś $T$ — w innym języku, języku docelowym (/target language/). @@ -229,8 +172,8 @@ The 'new Member States' - actually, the name continues to be sort of conditional The number of armed attacks also rose by 200% overall. Także liczba ataków zbrojnych wzrosła łącznie o 200 %. #+END_SRC -Zauważmy, że możemy taki tekst modelować po prostu traktując jako -jeden. Innymi słowy, nie modelujemy tekstu angielskiego ani polskiego, +Zauważmy, że możemy taki (bi)tekst modelować po prostu traktując jako +jeden ciągły tekst. Innymi słowy, nie modelujemy tekstu angielskiego ani polskiego, tylko angielsko-polską mieszankę, to znaczy uczymy model, który najpierw modeluje prawdopodobieństwo po stronie źródłowej (powiedzmy — angielskiej): @@ -239,7 +182,7 @@ The number of armed attacks also ? #+END_SRC W momencie napotkania specjalnego tokenu końca zdania źródłowego (powiedzmy ~~) model -powinien nauczyć się, że musi przerzucić się na modelowanie tekstu w języku docelowym (powiedzmy — polskim): +powinien nauczyć się, że musi przełączyć się na modelowanie tekstu w języku docelowym (powiedzmy — polskim): #+BEGIN_SRC The number of armed attacks also rose by 200% overall.Także liczba ataków ? @@ -254,10 +197,10 @@ tłumaczone zdanie jako prefiks, doklejając tylko token ~~. **** Neuronowe modele języka jako translatory -Jako że N-gramowego modelu języka ani modelu opartego na worku słów +Jako że n-gramowego modelu języka ani modelu opartego na worku słów nie da się użyć w omawiany sposób w tłumaczeniu maszynowym (dlaczego?), jako pierwszych użyto w neuronowym tłumaczeniu maszynowym -sieci LSTM, przy użyciu omawianego wyżej sposobu. +sieci LSTM, przy zastosowaniu omawianego wyżej sposobu. System tłumaczenia oparte na sieciach LSTM działały zaskakująco dobrze, zważywszy na to, że cała informacja o zdaniu źródłowym musi diff --git a/wyk/11_Transformer.org b/wyk/11_Transformer.org new file mode 100644 index 0000000..3a41ea9 --- /dev/null +++ b/wyk/11_Transformer.org @@ -0,0 +1,281 @@ + +* Transformer + +** Atencja jako „miękka” baza danych + +O atencji można myśleć metaforycznie jako o odpytywaniu „miękkiej”, wektorowej +bazy danych. Możemy sobie wyobrazić, że słowa $w_1,\dots,w_{j-1}$ są +naszą bazą danych, a słowo $w_j$ (z którego kierujemy „snop” uwagi) +jest *zapytaniem* (/query/). To zapytanie dopasowujemy do *kluczy* +(/keys/), w najprostszym ujęciu po prostu słów $w_1,\dots,w_{j-1}$ (a +właściwie ich zanurzeń). Jeśli klucz pasuje do zapytania, odpowiednia +wartość (/value/) jest wydobywana z bazy. Nasza baza jest jednak +„miękka”, nie — zerojedynkowa, zapytanie pasuje do klucza w pewnym +stopniu, mniej lub bardziej. + +W najprostszym ujęciu wartości są tym samym co klucze, czyli z naszej +bazy wydobywamy te same zanurzenia słów, których używamy jako kluczy. +Można jednak skomplikować schemat rozróżniając klucze i wartości — +mogą one powstawać przez rzutowanie podstawowych zanurzeń różnymi +macierzami: + +$$\vec{k_i} = W_k E(w_i),$$ + +$$\vec{v_i} = W_v E(w_i).$$ + +Również samo zapytanie może powstać przez rzutowanie: + +$$\vec{q_i} = W_q E(w_i).$$ + +Jeśli zanurzenie $E(w_i)$ o rozmiarze $m$ przedstawimy w postaci +kolumnowej, wówczas macierze będą $W_k$ i $W_q$ będą miały rozmiar +$d_k \times m$, gdzie $d_k$ jest rozmiarem kluczy i zapytań (dlaczego +wektory kluczy i zapytań powinny mieć raczej ten sam rozmiar?), zaś macierz +$W_v$ — $d_v \times m$, gdzie $d_v$ to rozmiar zanurzenia wektora wartości. +Zazwyczaj $d_k = d_v = m$, ale nie jest to obligatoryjne. + +Teraz nieznormalizowane wagi atencji przyjmą postać: + +$$\hat{\alpha}_{i,j} = \vec{q_i}^T\vec{k_j} = (W_q E(w_i))(W_k E(k_j)).$$ + +Zauważmy, że ciąg $\hat{\alpha}_{1,j},\dots,\hat{\alpha}_{j-1,j}$ można potraktować jako wektor +$\hat{\vec{\alpha}_{*,j}}$ i wyliczać w postaci zwartej: + +$$\hat{\vec{\alpha}_{*,j}} = \vec{q_j}^T K$$ + +gdzie $K$ to macierz kluczy złożona z wektorów +$\vec{k_1},\dots,\vec{k_{j-1}}$, tj. macierz o rozmiarze $d_k \times (j-1)$. + +Wektor znormalizowanych wag atencji będzie miał wówczas postać: + +$$\vec{\alpha}_{*,j} = \operatorname{softmax}(\vec{q_j}^T K).$$ + +Dokonajmy teraz agregacji wartości — obliczamy średnią wektorów +wartości ($\vec{v_i}$) ważoną atencją: + +$$A(w_1,\dots,j-1) = \alpha_{1,j} \vec{v_1} + \dots + \alpha_{j-1,j} \vec{v_{j-1}} = \sum_{i=1}^{j-1} \alpha_{i,j} v_i.$$ + +Jeśli $j-1$ wektorów wartości ułożyłem w macierz $V$ (o rozmiarze +$(j-1) \times d_v$), powyższy wzór będziemy mogli zapisać jako iloczyn wektora wag atencji i macierzy $V$: + +$$A(w_1,\dots,j-1) = \vec{\alpha}_{*,j}^T V = \operatorname{softmax}(\vec{q_j}^T K)^T V.$$ + +Sposób patrzenia na atencję przez pryzmat trójki +zapytania-klucze-wartości okaże się niezwykle ważny w wypadku modelu Transformer. + +** Model Transformer — historia + +Architekturę Transformer opracowano, pierwotnie, na potrzeby +tłumaczenia automatycznego (rok 2017, artykuł [Attention Is All You +Need](https://arxiv.org/abs/1706.03762)). Szybko okazało się, że +podobnie jak w wypadku modelu ELMo dla sieci LSTM, można *pretrenować* +duże modele Transformer (po prostu na dużych korpusach tekstowych, w +sposób nienadzorowany), a potem dostrajać pod konkretne zadanie +przetwarzania języka naturalnego. Jednym z pierwszych przykładów +takiego podejścia był model BERT (rok 2018, artykuł [BERT: +Pre-training of Deep Bidirectional Transformers for Language +Understanding](https://arxiv.org/abs/1810.04805)). To podejście było +później rozwinięte w postaci różnych modeli Transformer, również dla innych +języków niż angielski (RoBERTa, XLM, Polish RoBERTa itd.). + +Na tym wykładzie my skupimy się na innej odnodze modeli Transformer — +modelach generatywnych, takich jak na przykład GPT-2 czy GPT-3. To +podejście jest bliższe duchowi czystego modelowania języka — model +języka jest używany wprost jako generator. + +** GPT-2 — przykład działania + +Dokonajmy najpierw tokenizacji: + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + from transformers import AutoTokenizer + tokenizer = AutoTokenizer.from_pretrained("gpt2") + text = "The World War III will begin in" + encoded_input = tokenizer(text, return_tensors='pt') + encoded_input +#+END_SRC + +#+RESULTS: +:results: +{'input_ids': tensor([[ 464, 2159, 1810, 6711, 481, 2221, 287]]), 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1]])} +:end: + +Możemy podejrzeć uzyskane tokeny: + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + [tokenizer.decode(i) for i in encoded_input.input_ids[0]] +#+END_SRC + +#+RESULTS: +:results: +['The', ' World', ' War', ' III', ' will', ' begin', ' in'] +:end: + +Zwróćmy uwagę, że w GPT-2 tokeny obejmują spacje! + +Teraz uruchommy zasadniczy model: + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + from transformers import AutoModelForCausalLM + model = AutoModelForCausalLM.from_pretrained("gpt2") + outputs = model(**encoded_input) +#+END_SRC + +#+RESULTS: +:results: +:end: + +Z modelu GPT-2 otrzymamy rozkład prawdopodobieństwa kolejnego wyrazu, najpierw w postaci +nieznormalizowanych *logitów*: + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + logits = outputs[0][0][-1] + logits +#+END_SRC + +#+RESULTS: +:results: +tensor([-130.2947, -129.5677, -136.4030, ..., -138.3791, -138.8967, + -131.6319], grad_fn=) +:end: + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + from torch import softmax, topk + + k = 20 + + t = topk(softmax(logits, -1), k) + + tb = [[tokenizer.decode(t.indices[ix]), t.values[ix].item()] for ix in range(k)] + tb +#+END_SRC + +#+RESULTS: +:results: +[[' earnest', 0.07378227263689041], [' the', 0.06698606163263321], [' 1945', 0.043497972190380096], [' September', 0.024068640545010567], [' March', 0.0228887926787138], [' October', 0.02232857048511505], [' Europe', 0.02032744698226452], [' 2020', 0.018564637750387192], [' Japan', 0.018423961475491524], [' December', 0.016560807824134827], [' January', 0.015074416995048523], [' July', 0.014139187522232533], [' April', 0.013183596543967724], [' November', 0.012901309877634048], [' 20', 0.012770282104611397], [' Afghanistan', 0.012765118852257729], [' 1944', 0.01266297698020935], [' June', 0.012072316370904446], [' 1914', 0.011765970848500729], [' May', 0.011659453622996807]] +:end: + +*** Generowanie tekstu za pomocą GPT-2 + +#+BEGIN_SRC python :session mysession :exports both :results raw drawer + from transformers import pipeline + generator = pipeline('text-generation', model='gpt2') + generator('Hello, I\'m a language model,', max_length=30, num_return_sequences=1) +#+END_SRC + +#+RESULTS: +:results: +:end: + +** Model Transformer — podstawowa idea + +Model Transformer sprowadza się właściwie do atencji; nie posiada +żadnego komponentu rekurencyjnego, ani nawet nie stosujemy czegoś w +rodzaju połączenia modelu worka słów i modelu n-gramowego. + +W pierwszym przybliżeniu przy obliczaniu rozkładu prawdopodobieństwa +dla kolejnego wyrazu, to jest: + +$$P(w_j|w_1\dots w_{j-1})$$ + +na $j$-tym miejscu (w miejscu przewidywanego wyrazu) doklejamy +specjalny token, powiedzmy ~~. Token ten będzie „atendował” do +innych wszystkich wcześniejszych tokenów w zdaniu: + +$$\vec{\alpha}_{*,j}^T V = \operatorname{softmax}(\vec{q_j}^T K)^T V.$$ + +Samo to byłoby oczywiście zbyt proste: + +1. Otrzymalibyśmy model (ważonego) worka słów, w dodatku każde słowo + miałoby zawsze taką samą wagę! — Token $w_j$, który atenduje jest + zawsze ten sam (~~). Musimy wzbogacić reprezentację wektorową + słów i specjalnego tokenu (~~). + +2. Model Transformer w swojej podstawowej postaci w ogóle nie jest + wyposażony w pojęcie sekwencji — w przeciwieństwie do sieci + rekurencyjnych, które w sposób inherentny operują krok po kroku, w + sekwencji (w czasie). Musimy pozycję tokenów wprowadzić do sieci + Transformer nie przez modyfikację jej architektury, lecz przez dołączenie + informacji pozycyjnej do początkowych zanurzeń. + +3. Model Transformer nie powinien mieć żadnych tokenów OOV/UNK. Musimy + wrócić do kwestii tokenizacji tekstu i wprowadzić podział rzadszych + tokenów na mniejsze, *podwyrazowe* jednostki. + +** Atencja wsobna + +Jeśli chodzi problem (1), rozwiążemy go przez wprowadzenie +**skontekstualizowanych reprezentacji** tokenów. + +Na przykład słowo /mysz/ ma jedno wejściowe (/statyczne/) zanurzenie +(embedding) — bez względu na to, czy chodzi o zwierzę czy urządzenie +peryferyjne, tymczasem dość łatwo ustalić na podstawie kontekstu, o +które znaczenie chodzi. + +Rozwiązanie polega na tym, że tokenom będziemy przypisywać kolejne +zanurzenia skontekstualizowane — zależne od innych wyrazów w zdaniu. W +tym celu zastosujemy atencję wsobną (samo-atencję, /self-attention/). +Każdy token będzie atendował potencjalnie do każdego innego tokenu, +również do samego siebie (!). + +*** Wzory + +Rozpatrywać zatem będziemy nie tylko pojedynczy wektor znormalizowanych atencji + +$$\vec{\alpha}_{*,j}^T V = \operatorname{softmax}(\vec{q_j}^T K)^T V$$, + +lecz całą serię wektorów: + +$$\vec{\alpha}_{*,1},\dots,\vec{\alpha}_{*,i},\dots,\vec{\alpha}_{*,j}$$ + +gdzie: + +$$\vec{\alpha}_{*,i} = \operatorname{softmax}(\vec{q_i}^T K)$$ + +i $K$ jest macierzą kluczy o rozmiarze $d_k \times j$ (tym razem obejmuje również sam $i$-ty token). + +Nowa, skontekstualizowana reprezentacja $i$-tego tokenu będzie po prostu średnią wszystkich +wektorów ważoną atencją: + +$$E_1(w_i) = \operatorname{softmax}(\vec{q_i}^T K)^T V,$$ + +gdzie: + +- $E_1(w_i)$ — skontekstualizowane zanurzenie $i$-tego tokenu; używając indeksu $_1$ + zaznaczamy, że to jest pierwszy skonstekstualizowany embedding, rekurencyjnie będziemy budowali + kolejne $E_2(w_i)$, $E_3(w_i)$ itd. (zaś wejściowy statyczny embedding możemy oznaczyć przez $E_0(w_i)$); +- $V$ to macierz wartości o rozmiarze $j \times d_v$. + +**** Zwarta postać macierzowa atencji wsobnej + +Z praktycznych powodów (szybkość obliczeń na kartach graficznych) dużą +zaletą atencji wsobnej jest to, że wyliczenie skonstekstualizowanych zanurzeń dla wszystkich tokenów +w tekście da się zapisać w postaci zwartego wzoru macierzowego: + +$$E_1 = \operatorname{Attention}(Q, K, V) = \operatorname{softmax}(QK)^T V,$$ + +gdzie $Q$ to macierz wszystkich zapytań o rozmiarze $j \times d_k$ (wektory ułożone poziomo). + +**** Skalowanie atencji + +Twórcy modelu Transformer odkryli, że lepsze wyniki daje skalowanie atencji +przez stałą zależną od rozmiaru wektora klucza/zapytania $d_k$: + +$\operatorname{Attention}(Q, K, V) = \operatorname{softmax}(\frac{QK}{d_k})^T V,$$ + +** Wielogłowicowa atencja + +Od samego początku w Transformerze zamiast jednej atencji zaproponowano wiele **głowic atencji** +$(\operatorname{head}_1,\dots,\operatorname{head}_h$, każda głowica atencji działa w następujący sposób: + +$$\operatorname{head_i} = \operatorname{Attention}(QW_i^Q, KW_i^K,VW_i^V),$$ + +to znaczy każda głowica atencji działa tak samo, tylko przed jej zastosowaniem mnożymy +wektory zapytań, kluczy i wartości przez różne wyuczalne macierze, odpowiednio, +W_i^Q, W_i^K,W_i^V. Otrzymamy w ten sposób $h$ wektorów, konkatenujemy po prostu i mnożymy +przez dodatkową wyuczalną macierz $W^O$: + +$$\operatorname{MultiHead}(Q, K, V) = [\operatorname{head}_1,...,\operatorname{head}_n]W^O.$$ + +Przyjmujemy, że $d_k = d_v = m/h$, wtedy rozmiary macierzy $W_i^Q$ i $W_i^K$ będą wynosiły +$m \times d_k$, macierzy $W_i^V$ — $m \times d_v$, $W^O$ — $hd_v \times m$. diff --git a/wyk/helpers/intro b/wyk/helpers/intro index b45a955..6da9943 100644 --- a/wyk/helpers/intro +++ b/wyk/helpers/intro @@ -1,3 +1,4 @@ + { "cells": [ { @@ -7,7 +8,7 @@ "![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n", "
\n", "

Modelowanie języka

\n", - "

2. Języki [wykład]

\n", + "

10. Atencja [wykład]

\n", "

Filip Graliński (2022)

\n", "
\n", "\n",