diff --git a/wyk/15_Pozycyjne_zanurzenia.ipynb b/wyk/15_Pozycyjne_zanurzenia.ipynb index 50dda59..d2acf48 100644 --- a/wyk/15_Pozycyjne_zanurzenia.ipynb +++ b/wyk/15_Pozycyjne_zanurzenia.ipynb @@ -1,5 +1,20 @@ { "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", + "

15. Pozycyjne zanurzenia [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": {}, @@ -28,7 +43,7 @@ "\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", + "polega na uzupełnieniu zanurzeń o element pozycyjny. Taki element\n", "sieci neuronowej nazywamy **zanurzeniami (embeddingami) pozycyjnymi**\n", "(*position(al) embeddings, encodings*).\n", "\n" @@ -71,17 +86,17 @@ "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", + "\\mathcal{R}^m$, to jest zanurzenia zależnego tylko od pozycji tokena\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", + "tokena 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", + "Rzecz jasna rozmiar embeddingu pozycyjnego musi być identyczny z\n", + "rozmiarem zwykłego embeddingu ($m$).\n", "\n" ] }, @@ -103,16 +118,16 @@ "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", + "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", + " - 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", + " $E^p_{p{\\operatorname{max}}+i} = E^p(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", @@ -249,7 +264,7 @@ "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", + "pojawia się jednak pewna trudność.\n", "Proste dodawanie wektorów nie zawsze da dobry wyniku, np.\n", "jeśli dodamy do naszego znacznika 20 godzin:\n", "\n" @@ -417,11 +432,11 @@ "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", + "$$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", + "$$E_{p(i)_{2k+1}} = \\sin(\\frac{i}{10000^{2k/m}}),$$\n", "\n" ] }, @@ -444,7 +459,7 @@ "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", + "Obciążenia 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", diff --git a/wyk/15_Pozycyjne_zanurzenia.org b/wyk/15_Pozycyjne_zanurzenia.org index 43bda8d..0005f15 100644 --- a/wyk/15_Pozycyjne_zanurzenia.org +++ b/wyk/15_Pozycyjne_zanurzenia.org @@ -10,7 +10,7 @@ permutacja tekstu dawałaby identyczny wynik. Oznacza to, że pozycje wyrazów (tokenów) muszą być w jakiś sposób, celowo „wstrzyknięte” do sieci Transformer. Standardowa procedura -polega na uzupełnieniu zanurzeń do element pozycyjny. Taki element +polega na uzupełnieniu zanurzeń o element pozycyjny. Taki element sieci neuronowej nazywamy *zanurzeniami (embeddingami) pozycyjnymi* (/position(al) embeddings, encodings/). @@ -29,17 +29,17 @@ Opracowano kilka różnych typów embeddingów pozycyjnych, najczęściej stosow Najprostszy sposób uwzględnienia pozycji tokena polega na zdefiniowaniu pewnej funkcji $E_p(i) \colon \mathcal{N} \rightarrow -\mathcal{R}^m$, to jest zanurzenia zależnego tylko od pozycji tokenu +\mathcal{R}^m$, to jest zanurzenia zależnego tylko od pozycji tokena $i$. Następnie takie zanurzenie $E^p$ jest po prostu dodawane do standardowego embeddingu „semantycznego” $E^s$, by ostatecznie otrzymać embeddingu -tokenu na konkretnej pozycji: +tokena na konkretnej pozycji: $$E(w_i) = E^p(i) + E^s(w_i).$$ -Rzecz jasna rozmiar embeddingu pozycyjnego musi być identyczny jak -rozmiar zwykłego embeddingu ($m$). +Rzecz jasna rozmiar embeddingu pozycyjnego musi być identyczny z +rozmiarem zwykłego embeddingu ($m$). *** Wyuczalne embeddingi pozycyjne @@ -49,16 +49,16 @@ $\{1,\dots,p_{\operatorname{max}}\}$) osobnego wyuczalnego wektora. Przypomina to zwykły embedding wyuczalny dla poszczególnych słów: podobnie jak słowa /a/, /aby/, /abrakadabra/,…,/żyzny/ mają swoje embeddingi, tak i pozycje będą miały swoje embeddingi (pozycja 1 ma -swój embedding, pozycja 2 — inny, itd., oczywiście nie należy tego -mylić z embeddingami tokenów złożonych z cyfr /1/, /2/, itd.). +swój embedding, pozycja 2 — inny itd., oczywiście nie należy tego +mylić z embeddingami tokenów złożonych z cyfr /1/, /2/ itd.). Zaletą tego podejścia jest prostota, wady to: - nie generalizuje się na sekwencje dowolnej długości - - jeśli zdarzy się zdanie dłuższe niż $p_{\operatorname{max}}\}$, + - jeśli zdarzy się zdanie dłuższe niż $p_{\operatorname{max}}$, embeddingu po prostu… nie ma - … wprawdzie można po prostu zdefiniować cyklicznie embeddingi - $E^p_{p{\operatorname{max}}+i} = E^p(i) + $E^p_{p{\operatorname{max}}+i} = E^p(i)$ - … ma to jednak swoje wady (na pozycji $p{\operatorname{max}}+1$ sztucznie „wracamy” na początek tekstu, - sieć musi uczyć się osobno dla sąsiadujących pozycji, na przykład @@ -111,7 +111,7 @@ tylko 2022,5. A zatem właściwa reprezentacja wektorowa przykładowego momentu w czasie powinna mieć raczej postać: -#+BEGIN_SRC python :session mysession :exports both :results raw drawer +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer def to_analog(tv): cycles = [100,12,30,24,60,60,100] analog_tv = [] @@ -139,11 +139,11 @@ A zatem właściwa reprezentacja wektorowa przykładowego momentu w czasie powin Podstawowa operacja dotycząca czasu to przesunięcie momentu czasu o pewien okres (wprzód lub w tył), właściwie przypomina to zwykłe dodawanie czy odejmowanie, -pojawia się jednak pewne trudność. +pojawia się jednak pewna trudność. Proste dodawanie wektorów nie zawsze da dobry wyniku, np. jeśli dodamy do naszego znacznika 20 godzin: -#+BEGIN_SRC python :session mysession :exports both :results raw drawer +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer delta_v = to_analog([0,0,0,20,0,0,0]) delta_v #+END_SRC @@ -153,7 +153,7 @@ jeśli dodamy do naszego znacznika 20 godzin: [2.3148148148148147e-05, 0.0023148148148148147, 0.02777777777777778, 0.8333333333333334, 0.0, 0.0, 0.0] :end: -#+BEGIN_SRC python :session mysession :exports both :results raw drawer +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer def vsum(a, b): return [ai+bi for ai, bi in zip(a, b)] @@ -189,7 +189,7 @@ gdzie $phi$ jest kątem wskazówki. W ten sposób otrzymamy dwa razy dłuższy wektor: -#+BEGIN_SRC python :session mysession :exports both :results raw drawer +#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer import math def to_hand_coord(atv): @@ -241,11 +241,11 @@ Można na przykład wprowadzić narastające geometrycznie cykle o długości od 1 do 10000 (10000 to arbitralnie wybrana liczba), tj. $k$-ty cykl będzie miał długość $10000^{2k/m}$, wtedy dla parzystej pozycji wektora zanurzeń: -$$E_p(i)_2k = \sin(\frac{i}{10000^{2k/m}),$$ +$$E_{p(i)_2k} = \sin(\frac{i}{10000^{2k/m}}),$$ dla nieparzystej zaś: -$$E_p(i)_{2k+1} = \sin(\frac{i}{10000^{2k/m}),$$ +$$E_{p(i)_{2k+1}} = \sin(\frac{i}{10000^{2k/m}}),$$ *** Zanurzenia względne @@ -256,7 +256,7 @@ atencji jako pozycyjne obciążenie (/positional bias/), tj. np. w modelu T5 mod się serii skalarnych obciążeń $b_{\Delta}$, gdzie $\Delta \in \{-\Delta_{\operatorname{max}},\dots,-1,0,1,\dots,\Delta_{\operatorname{max}}\}. -Obciążenie te po prostu są dodawane do atencji: +Obciążenia te po prostu są dodawane do atencji: $$\hat{\alpha}_{i,j} = \vec{q_i}^T\vec{k_j} + b_{j-i}.$$