diff --git a/wyk/15_Pozycyjne_zanurzenia.ipynb b/wyk/15_Pozycyjne_zanurzenia.ipynb
new file mode 100644
index 0000000..50dda59
--- /dev/null
+++ b/wyk/15_Pozycyjne_zanurzenia.ipynb
@@ -0,0 +1,481 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Pozycyjne zanurzenia\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Atencja nie uwzględnia kolejności wyrazów\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "W przeciwieństwie do sieci rekurencyjnych sama atencja nie ma\n",
+ "naturalnego, wbudowanego pojęcia kolejności, porządku czy „strzałki\n",
+ "czasu”. Oznacza to, że sieci Transformer w postaci przedstawionej do\n",
+ "tej pory właściwie operowałyby na tekście jak na worku słów (dowolna\n",
+ "permutacja tekstu dawałaby identyczny wynik.\n",
+ "\n",
+ "Oznacza to, że pozycje wyrazów (tokenów) muszą być w jakiś sposób,\n",
+ "celowo „wstrzyknięte” do sieci Transformer. Standardowa procedura\n",
+ "polega na uzupełnieniu zanurzeń do element pozycyjny. Taki element\n",
+ "sieci neuronowej nazywamy **zanurzeniami (embeddingami) pozycyjnymi**\n",
+ "(*position(al) embeddings, encodings*).\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Rodzaje zanurzeń pozycyjnych\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Opracowano kilka różnych typów embeddingów pozycyjnych, najczęściej stosowane:\n",
+ "\n",
+ "- właściwe zanurzenia pozycyjne zależne wprost od bezwzględnej pozycji tokena\n",
+ " w zdaniu\n",
+ " - wyuczalne embeddingi pozycyjne\n",
+ " - embeddingi sinusoidalne\n",
+ "- zanurzenia względne,\n",
+ "- zanurzenia obrotowe.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Zanurzenia zależne od bezwzględnej pozycji tokena\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Najprostszy sposób uwzględnienia pozycji tokena polega na\n",
+ "zdefiniowaniu pewnej funkcji $E_p(i) \\colon \\mathcal{N} \\rightarrow\n",
+ "\\mathcal{R}^m$, to jest zanurzenia zależnego tylko od pozycji tokenu\n",
+ "$i$.\n",
+ "\n",
+ "Następnie takie zanurzenie $E^p$ jest po prostu dodawane do standardowego\n",
+ "embeddingu „semantycznego” $E^s$, by ostatecznie otrzymać embeddingu\n",
+ "tokenu na konkretnej pozycji:\n",
+ "\n",
+ "$$E(w_i) = E^p(i) + E^s(w_i).$$\n",
+ "\n",
+ "Rzecz jasna rozmiar embeddingu pozycyjnego musi być identyczny jak\n",
+ "rozmiar zwykłego embeddingu ($m$).\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Wyuczalne embeddingi pozycyjne\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Najprostszy sposób definiowania funkcji $E_p$ to po prostu przypisanie\n",
+ "każdej pozycji (siłą rzeczy ze skończonego zbioru\n",
+ "$\\{1,\\dots,p_{\\operatorname{max}}\\}$) osobnego wyuczalnego wektora.\n",
+ "Przypomina to zwykły embedding wyuczalny dla poszczególnych słów:\n",
+ "podobnie jak słowa *a*, *aby*, *abrakadabra*,…,/żyzny/ mają swoje\n",
+ "embeddingi, tak i pozycje będą miały swoje embeddingi (pozycja 1 ma\n",
+ "swój embedding, pozycja 2 — inny, itd., oczywiście nie należy tego\n",
+ "mylić z embeddingami tokenów złożonych z cyfr *1*, *2*, itd.).\n",
+ "\n",
+ "Zaletą tego podejścia jest prostota, wady to:\n",
+ "\n",
+ "- nie generalizuje się na sekwencje dowolnej długości\n",
+ " - jeśli zdarzy się zdanie dłuższe niż $p_{\\operatorname{max}}\\}$,\n",
+ " embeddingu po prostu… nie ma\n",
+ " - … wprawdzie można po prostu zdefiniować cyklicznie embeddingi\n",
+ " $Epp{\\operatorname{max}}+i = Ep(i)\n",
+ " - … ma to jednak swoje wady (na pozycji $p{\\operatorname{max}}+1$ sztucznie\n",
+ " „wracamy” na początek tekstu,\n",
+ "- sieć musi uczyć się osobno dla sąsiadujących pozycji, na przykład\n",
+ " embedding pozycji 38 musi zostać wyuczony zupełnie niezależnie od pozycji 39,\n",
+ "- … co jest szczególnie problematyczne dla pozycji o wyższych numerach pojawiających\n",
+ " się rzadziej,\n",
+ "- tego rodzaju embeddingów nie da się stosować relatywnie, a chcielibyśmy, żeby\n",
+ " atencja z wyrazu na pozycji 14 kierowana na wyraz 12 była w pewnym stopniu podobna\n",
+ " do atencji z wyrazu 27 kierowanej na wyraz 25.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Embeddingi sinusoidalne\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Byłoby pożądane, gdyby za pomocą embeddingów pozycyjnych możliwe było wyrażenie pozycji wyrazów\n",
+ "w różnych **skalach** — zarówno bezpośrednio poprzedzanie/następowanie, jak również\n",
+ "relację typu „słowo X występuje około 8 słów wcześniej od słowa Y” (i kontrastowania z\n",
+ "relacją typu „słowo X występuje około 15 słów wcześniej od słowa Y”).\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "##### Analogie z reprezentacją czasu\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Co ciekawe, istnieją analogie między sposobami, w jakie można reprezentować pozycji\n",
+ "i technikami reprezentacji czasu, wypracowywanymi przez ludzkość (od setek lat!).\n",
+ "\n",
+ "Przede wszystkim, jesteśmy przyzwyczajeni do reprezentacji czasu, z\n",
+ "natury ciągłego, za pomocą serii coraz dłuższych cykli (dotyczy to nie\n",
+ "tylko kultury zachodniej, lecz także na przykład cywilizacji Majów!).\n",
+ "\n",
+ "Na przykład znacznik czasowy dla konkretnej chwili w czasie może mieć postać: `2022-06-13 09:11:23.12`,\n",
+ "co można by reprezentować za pomocą 7-elementowego wektora:\n",
+ "\n",
+ "$$[2022,06,13,09,11,23,12].$$\n",
+ "\n",
+ "Dla spójności elementy wektora można by znormalizować względem czasu\n",
+ "trwania danego cyklu, otrzymamy wówczas (załóżmy, że dla lat nadrzędnym cyklem są stulecia):\n",
+ "\n",
+ "$$[0.220,0.500,0.433,0.375,0.183,0.383,0.120]$$\n",
+ "\n",
+ "(np. dla godzin $9/24=0,375$).\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "##### Analogowa reprezentacja czasu\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Zauważmy, że powyższa reprezentacja jest „cyfrowa”, nieciągła. Na\n",
+ "przykład w sylwestra 2022 roku pierwsza pozycja nagle „przeskoczy”\n",
+ "na 2023. Matematycznie oznacza to nieciągłość, która nie jest pożądana\n",
+ "z punktu widzenia procesu propagacji wstecznej. Lepiej gdyby wszystkie\n",
+ "pozycje wektora zmieniają się w sposób ciągły, analogowy, jak\n",
+ "wskazówki zegara! W zwykłym bowiem zegarze analogowym wszystkie\n",
+ "wskazówki się cały czas obracają, jedne szybciej, drugie wolniej. Na\n",
+ "przykład 30 czerwca 2022 roku nie oznaczałby tak naprawdę roku 2022,\n",
+ "tylko 2022,5.\n",
+ "\n",
+ "A zatem właściwa reprezentacja wektorowa przykładowego momentu w czasie powinna mieć raczej postać:\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[0.22537174740226337, 0.5371747402263375, 0.4460968827160494, 0.3829064814814815, 0.18975555555555554, 0.38533333333333336, 0.12]"
+ ]
+ }
+ ],
+ "source": [
+ "def to_analog(tv):\n",
+ " cycles = [100,12,30,24,60,60,100]\n",
+ " analog_tv = []\n",
+ "\n",
+ " prev = 0.0\n",
+ "\n",
+ " for ix in range(len(tv)-1, -1, -1):\n",
+ " v = tv[ix]/cycles[ix] + prev * (1 / cycles[ix])\n",
+ " analog_tv.append(v)\n",
+ " prev = v\n",
+ "\n",
+ " analog_tv = analog_tv[-1::-1]\n",
+ " return analog_tv\n",
+ "\n",
+ "tv = to_analog([22,6,13,9,11,23,12])\n",
+ "tv"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "##### Dodawanie czasu\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Podstawowa operacja dotycząca czasu to przesunięcie momentu czasu o\n",
+ "pewien okres (wprzód lub w tył), właściwie przypomina to zwykłe dodawanie czy odejmowanie,\n",
+ "pojawia się jednak pewne trudność.\n",
+ "Proste dodawanie wektorów nie zawsze da dobry wyniku, np.\n",
+ "jeśli dodamy do naszego znacznika 20 godzin:\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[2.3148148148148147e-05, 0.0023148148148148147, 0.02777777777777778, 0.8333333333333334, 0.0, 0.0, 0.0]"
+ ]
+ }
+ ],
+ "source": [
+ "delta_v = to_analog([0,0,0,20,0,0,0])\n",
+ "delta_v"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[0.22539489555041153, 0.5394895550411523, 0.4738746604938272, 1.2162398148148148, 0.18975555555555554, 0.38533333333333336, 0.12]"
+ ]
+ }
+ ],
+ "source": [
+ "def vsum(a, b):\n",
+ " return [ai+bi for ai, bi in zip(a, b)]\n",
+ "\n",
+ "vsum(tv, delta_v)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Problem polega na tym, że na czwartej pozycji pojawiła się wartość\n",
+ "większa od 1. Powinniśmy zostawić tylko część ułamkową\n",
+ "(0.2162398148148148). Możemy tak uczynić, ale wtedy oznacza to\n",
+ "nieciągłość między 0.99 a 1.00 (czyli 0.00 bo obcięciu do części\n",
+ "ułamkowej). Znowu powracamy do problemu nieciągłości po wypełnieniu\n",
+ "cyklu (tak naprawdę „rozwiązaliśmy” go tylko dla najdłuższego cyklu).\n",
+ "Gdybyśmy mogli tylko utożsamić wartość 1 z 0… podobnie jak $2\\pi$ z 0\n",
+ "dla funkcji trygonometrycznych. Albo gdyby reprezentować czas\n",
+ "dosłownie za pomocą wskazówek, które po wypełnieniu cyklu w ciągły\n",
+ "sposób powracają do pozycji początkowej…\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "##### Czas reprezentowany przez wskazówki zegara\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Pozycja wskazówki jest reprezentowana w sposób jednoznaczny przez\n",
+ "współrzędne końca, dla każdego cyklu możemy wprowadzić dwie wartości\n",
+ "(znormalizowane) względem długości wskazówki. To znaczy, gdyby\n",
+ "przyjąć, że długość wskazówki wynosi 1, wówczas współrzędne jej końca mają wartość:\n",
+ "\n",
+ "$$x = \\cos\\phi, y = \\sin\\phi,$$\n",
+ "\n",
+ "gdzie $phi$ jest kątem wskazówki.\n",
+ "\n",
+ "W ten sposób otrzymamy dwa razy dłuższy wektor:\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[0.9379890645739346, 0.34666484497236694, 0.6646342658032391, 0.7471688515457462, 0.7643734166510766, 0.6447738207442666, 0.8245057772081804, 0.5658535352459454, 0.9559058477167625, 0.2936733053937619, 0.8223427069797843, 0.5689925063453478, 0.9822872507286887, 0.1873813145857246]"
+ ]
+ }
+ ],
+ "source": [
+ "import math\n",
+ "\n",
+ "def to_hand_coord(atv):\n",
+ " out = []\n",
+ " for v in atv:\n",
+ " phi = v / 2*math.pi\n",
+ " out.append(math.cos(phi))\n",
+ " out.append(math.sin(phi))\n",
+ "\n",
+ " return out\n",
+ "\n",
+ "to_hand_coord(tv)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "##### Obrót jako mnożenie macierzy\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Okazuje się, że obrót w przestrzeni euklidesowej można wyrazić za pomocą mnożenia macierzy,\n",
+ "na przykład, aby obliczyć współrzędne na płaszczyźnie po obrocie o 90 stopnia, wystarczy przemnożyć\n",
+ "wektor współrzędnych przez macierz:\n",
+ "\n",
+ "\\begin{matrix}\n",
+ "0 & -1 \\\\\n",
+ "1 & 0 \\\\\n",
+ "\\end{matrix}\n",
+ "\n",
+ "W ogólnym przypadku obrót o kąt $\\phi$ oznacza przemnożenie przez macierz:\n",
+ "\n",
+ "\\begin{matrix}\n",
+ "\\cos\\phi & -\\sin\\phi \\\\\n",
+ "\\sin\\phi & \\cos\\phi \\\\\n",
+ "\\end{matrix}\n",
+ "\n",
+ "Jest to bardzo dobra wiadomość! Okazuje się, że „przemieszczanie” się\n",
+ "w czasie można zrealizować za pomocą mnożenia macierzy — operacji, do\n",
+ "której stworzono karty graficzne!\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "##### Reprezentacja pozycji tokenów\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Analogicznie do czasu, można reprezentować pozycję wyrazów. Zamiast naturalnych cykli\n",
+ "lat, miesięcy, dni, itd. musimy tylko narzucić z góry cykle. Jeśli rozmiar\n",
+ "embeddingu wynosi $m$, musimy wprowadzić $m/2$ cykli (dlaczego?).\n",
+ "\n",
+ "Można na przykład wprowadzić narastające geometrycznie cykle o\n",
+ "długości od 1 do 10000 (10000 to arbitralnie wybrana liczba), tj.\n",
+ "$k$-ty cykl będzie miał długość $10000^{2k/m}$, wtedy dla parzystej pozycji wektora zanurzeń:\n",
+ "\n",
+ "$$E_p(i)_2k = \\sin(\\frac{i}{10000^{2k/m}),$$\n",
+ "\n",
+ "dla nieparzystej zaś:\n",
+ "\n",
+ "$$E_p(i)_{2k+1} = \\sin(\\frac{i}{10000^{2k/m}),$$\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Zanurzenia względne\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Inne podejście polega na skupieniu się na tym, by Transformer był w\n",
+ "stanie operować na **względnych** pozycjach. W tym podejściu informacja\n",
+ "o pozycji nie jest dodawana do zanurzeń, lecz jest „wstrzykiwana” do\n",
+ "atencji jako pozycyjne obciążenie (*positional bias*), tj. np. w modelu T5 model uczy\n",
+ "się serii skalarnych obciążeń $b_{\\Delta}$, gdzie $Δ ∈\n",
+ "\\\\{-Δ\\operatorname{max},…,-1,0,1,…,Δ\\operatorname{max}\\\\}.\n",
+ "\n",
+ "Obciążenie te po prostu są dodawane do atencji:\n",
+ "\n",
+ "$$\\hat{\\alpha}_{i,j} = \\vec{q_i}^T\\vec{k_j} + b_{j-i}.$$\n",
+ "\n",
+ "Zalety takiego podejścia:\n",
+ "\n",
+ "- stosunkowo niski koszt obliczeniowy,\n",
+ "- względne pozycje są uwzględniane nie tylko na początku obliczeń, lecz w każdej warstwie.\n",
+ "\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "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.10.5"
+ },
+ "org": null
+ },
+ "nbformat": 4,
+ "nbformat_minor": 1
+}
diff --git a/wyk/12_Pozycyjne_zanurzenia.org b/wyk/15_Pozycyjne_zanurzenia.org
similarity index 100%
rename from wyk/12_Pozycyjne_zanurzenia.org
rename to wyk/15_Pozycyjne_zanurzenia.org