878 lines
31 KiB
Plaintext
878 lines
31 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Modele języka i ich zastosowania\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Przypomnienie\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Przypomnijmy, że model języka zwraca prawdopodobieństwo dla danego\n",
|
|
"ciągu symboli (tokenów, wyrazów itp.) $w_1\\ldots w_N$ (o długości $N$):\n",
|
|
"\n",
|
|
"$$P_M(w_1\\ldots w_N) = ?$$\n",
|
|
"\n",
|
|
"W dalszym ciągu będziemy zakładali, że będziemy operować na wyrazach.\n",
|
|
"Zbiór wszystkich wyrazów nazywa się **słownikiem** (ang. *vocabulary*,\n",
|
|
"nie *dictionary!*), w literaturze dotyczącej modelowania języka\n",
|
|
"zazwyczaj oznacza się go literą $V$ (częściej niż $\\Sigma$).\n",
|
|
"Dale zakładamy, że słownik jest skończony.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Co jeszcze potrafi model języka?\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Przewidywanie kolejnego słowa\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"$$P_M(w_N|w_1\\ldots w_{N-1}) = \\frac{P_M(w_1\\dots w_{N-1}w_N*)}{P_M(w_1\\dots w_{n-1}*)} = \\frac{\\sum_{\\alpha \\in\n",
|
|
" \\Sigma^*}P_M(w_1\\dots w_N\\alpha)}{\\sum_{\\alpha\\in\\Sigma^*}P(w_1\\dots w_{n-1}\\alpha)}$$\n",
|
|
"\n",
|
|
"$P_M(w_N|w_1\\ldots w_{N-1})$ to właściwie skrót notacyjny, pełny zapis powinien mieć następujący kształt:\n",
|
|
"\n",
|
|
"$$P_M(X_N=w_N|X_1=w_1,\\ldots,X_{N-1}=w_{N-1}),$$\n",
|
|
"\n",
|
|
"gdzie $P_M(X_i=w)$ oznacza prawdopodobieństwo, że na $i$-tej pozycji wystąpi słowo $w$.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Odgadywanie słowa w luce\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"$$P_M(w_1\\dots w_{i-1}?w_{i+1}\\dots w_N) = \\operatorname{argmax}_w P_M(w_1\\ldots w_{i-1}ww_{i+1}\\dots w_N)$$\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Przykład dla autentycznego modelu języku\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Zobaczmy przykładowe zastosowania i wyniki dla modelu języku\n",
|
|
"wyuczonego na tekstach z II poł. XX w.\n",
|
|
"\n",
|
|
"![img](./04_Ngramowy_model/tabelka.png)\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Do czego stosujemy model języka?\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Model języka sam w sobie nie jest zbyt użyteczny. To raczej środek do celu\n",
|
|
"niż cel sam w sobie.\n",
|
|
"\n",
|
|
"Model języka:\n",
|
|
"\n",
|
|
"- ma zastosowanie w kryptoanalizie\n",
|
|
" - Oxmynsxq mkx lo kmrsofon li cdenisxq sdc kvzrklodsm mrkbkmdobc kxn bozvkmsxq okmr yxo li dro 13dr voddob zvkmon pebdrob kvyxq sx dro kvzrklod.\n",
|
|
"- pomaga(ł) wybrać właściwe tłumaczenie w tłumaczeniu maszynowym\n",
|
|
" czy transkrypcję w systemach rozpoznawania mowy (ASR)\n",
|
|
" (zanim zaczęto używać do tego sieci neuronowych, gdzie nie\n",
|
|
" ma już wyraźnego rozróżnienia między modelem tłumaczenia\n",
|
|
" czy modelem akustycznym a modelem języka),\n",
|
|
"- pomaga znaleźć „podejrzane” miejsca w tekście\n",
|
|
" (korekta pisowni/gramatyki),\n",
|
|
"- może być stosowany jako klasyfikator (potrzeba wtedy więcej niż jednego modelu,\n",
|
|
" np. model języka spamów kontra model języka niespamów),\n",
|
|
"- może być stosowany w kompresji danych,\n",
|
|
"- bardzo dobry model języka **musi** mieć **w środku** bardzo dobrą **wiedzę**\n",
|
|
" o języku i o świecie, można wziąć **„wnętrzności”** modelu, nie dbając o prawdopodobieństwa\n",
|
|
" i użyć modelu w zupełnie innym celu.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### N-gramowy model języka\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Zawsze prawdziwe:\n",
|
|
"\n",
|
|
"$$P_M(w_1\\dots w_N) = P_M(w_1)P_M(w_2|w_1)\\dots P_M(w_N|w_1\\dots w_{N-1}).$$\n",
|
|
"\n",
|
|
"Można aproksymować prawdopodobieństwa używając $n$-gramów:\n",
|
|
"\n",
|
|
"$$P_M(w_1\\dots w_N) \\approx P_M(w_1)\\dots P_M(w_i|w_{i-n+1}\\dots w_{i-1})\\dots P_M(w_N|w_{N-n+1}\\dots w_{N-1}).$$\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Model trigramowy\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Dla $n=3$:\n",
|
|
"\n",
|
|
"$$P_M(w_1\\dots w_N) = P_M(w_1)P_M(w_2|w_1)P_M(w_3|w_1w_2)\\dots P_M(w_i|w_{i-2}w_{i-1})\\dots P_M(w_N|w_{N-2}w_{N-1}).$$\n",
|
|
"\n",
|
|
"Zauważmy, że model trigramowy oznacza modelowanie kolejnego wyrazu przy znajomości\n",
|
|
"2 (nie 3!) poprzedzających wyrazów (**razem** mamy 3 wyrazy).\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Model digramowy/bigramowy\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Dla $n=2$:\n",
|
|
"\n",
|
|
"$$P_M(w_1\\dots w_N) = P_M(w_1)P_M(w_2|w_1)P_M(w_3|w_2)\\dots P_M(w_i|w_{i-1})\\dots P_M(w_N|w_{N-1})$$\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Model unigramowy\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Dla $n=1$ uzyskujemy przypadek szczególny:\n",
|
|
"\n",
|
|
"$$P_M(w_1\\dots w_N) = P_M(w_1)P_M(w_2)P_M(w_3)\\dots P_M(w_N) = \\prod_{i=1}^N P_M(w_i)$$\n",
|
|
"\n",
|
|
"Zauważmy, że w modelu unigramowym w ogóle nie bierzemy pod uwagę kolejności wyrazów.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Estymacja prawdopodobieństw\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Dla $n$-gramowego modelu potrzebujmy estymować wartości:\n",
|
|
"\n",
|
|
"$$P_M(w_i|w_{i-n+1}\\dots w_{i-1}).$$\n",
|
|
"\n",
|
|
"Prawdopodobieństwa te estymujemy na podstawie jakiegoś **korpusu tekstów**\n",
|
|
"(możemy nazywać go również **zbiorem uczącym**).\n",
|
|
"\n",
|
|
"Najprostszy sposób:\n",
|
|
"\n",
|
|
"$$P_M(w_i|w_{i-n+1}\\dots w_{i-1}) = \\frac{\\# w_{i-n+1}\\dots w_{i-1}w_i}{\\# w_{i-n+1}\\dots w_{i-1}},$$\n",
|
|
"\n",
|
|
"gdzie $\\# w_1\\dots w_k$ oznacza liczbę wystąpień w korpusie.\n",
|
|
"\n",
|
|
"Na przykład, jeśli model $M$ zostanie wyuczony na tekście *do be do be do do*, wówczas\n",
|
|
"$P_M(\\mathit{be}|\\mathit{do})=\\frac{2}{3}$.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Ewaluacja modeli języka\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Jak już widzimy, możemy mieć różne modele języka. Nawet jeśli\n",
|
|
"pozostajemy tylko na gruncie najprostszych, $n$-gramowych modeli\n",
|
|
"języka, inne prawdopodobieństwa uzyskamy dla modelu digramowego, a\n",
|
|
"inny dla trigramowego. Jedne modele będą lepsze, inne — gorsze. Jak\n",
|
|
"obiektywnie odróżnić dobry model od złego? Innymi słowy, jak ewaluować\n",
|
|
"modele języka?\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Ewaluacja zewnętrzna i wewnętrzna\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"W ewaluacji zewnętrznej (ang. *extrinsic*) ewaluację modelu języka sprowadzamy\n",
|
|
"do ewaluacji większego systemu, którego częścią jest model języka, na przykład\n",
|
|
"systemu tłumaczenia maszynowego albo systemu ASR.\n",
|
|
"\n",
|
|
"Ewaluacja wewnętrzna (ang. *intrinsic*) polega na ewaluacji modelu języka jako takiego.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Podział zbioru\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Po pierwsze, jak zazwyczaj bywa w uczeniu maszynowym, powinniśmy\n",
|
|
"podzielić nasz zbiór danych. W modelowaniu języka zbiorem danych jest\n",
|
|
"zbiór tekstów w danym języku, czyli korpus języka.\n",
|
|
"Powinniśmy podzielić nasz korpus na część uczącą (*training set*) $C = \\{w_1\\ldots w_N\\}$ i testową\n",
|
|
"(*test set*) $C' = \\{w_1'\\ldots w_{N'}'\\}$.\n",
|
|
"\n",
|
|
"Warto też wydzielić osobny „deweloperski” zbiór testowy (*dev set*) —\n",
|
|
"do testowania na bieżąco, optymalizacji hiperparametrów itd. Zbiory\n",
|
|
"testowe nie muszą być bardzo duże, np. kilka tysięcy zdań może w zupełności wystarczyć.\n",
|
|
"\n",
|
|
"Tak podzielony korpus możemy traktować jako **wyzwanie modelowania języka**.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Przykład wyzwania modelowania języka\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Wyzwanie\n",
|
|
"[https://gonito.net/challenge/challenging-america-word-gap-prediction|Challenging America word-gap prediction](https://gonito.net/challenge/challenging-america-word-gap-prediction|Challenging America word-gap prediction)\n",
|
|
"to wyzwanie modelowania amerykańskiej odmiany języka angielskiego, używanej w gazetach w XIX w. i I poł. XX w.\n",
|
|
"\n",
|
|
" $ git clone git://gonito.net/challenging-america-word-gap-prediction\n",
|
|
" $ cd challenging-america-word-gap-prediction\n",
|
|
" $ xzcat train/in.tsv.xz | wc\n",
|
|
" 432022 123677147 836787912\n",
|
|
" $ xzcat dev-0/in.tsv.xz | wc\n",
|
|
" 10519 3076536 20650825\n",
|
|
" $ xzcat test-A/in.tsv.xz | wc\n",
|
|
" 7414 2105734 14268877\n",
|
|
"\n",
|
|
"Dodajmy, że poszczególne zbiory zawierają teksty z różnych gazet. Jest\n",
|
|
"to właściwe podejście, jeśli chcemy mierzyć rzeczywistą skuteczność modeli języka.\n",
|
|
"(Teksty z jednej gazety mogłyby być zbyt proste).\n",
|
|
"\n",
|
|
"Oto przykład tekstu z wyzwania:\n",
|
|
"\n",
|
|
" $ xzcat train/in.tsv.xz | head -n 1 | fold\n",
|
|
" 4e04702da929c78c52baf09c1851d3ff\tST\tChronAm\t1919.6041095573314\n",
|
|
" 30.47547\t-90.100911\tcame fiom the last place to this\\nplace, and thi\n",
|
|
" s place is Where We\\nWere, this is the first road I ever\\nwas on where you can r\n",
|
|
" ide elsewhere\\nfrom anywhere and be nowhere.\\nHe says, while this train stops ev\n",
|
|
" ery-\\nwhere, it never stops anywhere un-\\nless its somewhere. Well, I says,\\nI'm\n",
|
|
" glad to hear that, but, accord-\\ning to your figures, I left myself\\nwhere 1 wa\n",
|
|
" s, which is five miles near-\\ner to myself than I was when we\\nwere where we are\n",
|
|
" now.\\nWe have now reached Slidell.\\nThat's a fine place. The people\\ndown there\n",
|
|
" remind me of bananas-\\nthey come and go in bunches. 811-\\ndell used to be noted\n",
|
|
" for her tough\\npeople. Now she is noted for be,\\ntough steaks. Well, I certainl\n",
|
|
" y got\\none there. When the waiter brought\\nit in it was so small I thought. It\\n\n",
|
|
" was a crack in the plate. I skid,\\nwaiter what else have you got? +He\\nbrought m\n",
|
|
" e in two codfish and one\\nsmelt. I said, waiter have you got\\npigs feet? He said\n",
|
|
" no, rheumatism\\nmakes me walk that way. I sald,\\nhow is the pumpkin pie?\n",
|
|
" said\\nit's all squash. The best I could get\\nin that hotel was a soup sandwich.\\\n",
|
|
" nAfter the table battle the waiter and\\nI signed an armistice. I then went\\nover\n",
|
|
" to the hotel clerk and asked for\\na room. He said with or without a\\nbed? I sai\n",
|
|
" d, with a bed. He said,\\nI don't think I 'have' a bed long\\nenough for you. I sa\n",
|
|
" id, well, I'll\\naddtwo feettoitwhenIgetinit.\\nHe gave me a lovely room on the\\nt\n",
|
|
" op floor. It was one of those rooms\\nthat stands on each side. If you\\nhappen to\n",
|
|
" get up in the middle of\\nthe night you want to be sure and\\nget up in the middl\n",
|
|
" e of the room.\\nThat night I dreamt I was eating\\nflannel cakes. When I woke up\n",
|
|
" half\\nof the blanket was gone. I must\\nhave got up on the wrong side of the\\nbed\n",
|
|
" , for next morning I had an awful\\nheadache. I told the manager about\\nit. He sa\n",
|
|
" id, you have rheumatic\\npains. I said, no, I think it is on,\\nof those attic roo\n",
|
|
" m pains. I nad to\\ngetupat5a.m.inthemorningso\\nthey could use the sheet to set t\n",
|
|
" he\\nbreakfast table.\n",
|
|
"\n",
|
|
"Zauważmy, że mamy nie tylko tekst, lecz również metadane (czas i\n",
|
|
"współrzędne geograficzne). W modelowaniu języka można uwzględnić\n",
|
|
"również takie dodatkowe parametry (np. prawdopodobieństwa wystąpienia\n",
|
|
"słowa *koronawirus* wzrasta po roku 2019).\n",
|
|
"\n",
|
|
"Zauważmy również, że tekst zawiera błędy OCR-owe (np. *nad* zamiast\n",
|
|
"*had*). Czy w takim razie jest to sensowne wyzwanie modelowania\n",
|
|
"języka? Tak, w niektórych przypadkach możemy chcieć modelować tekst z\n",
|
|
"uwzględnieniem „zaszumień” wprowadzanych przez ludzi bądź komputery\n",
|
|
"(czy II prawo termodynamiki!).\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Co podlega ocenie?\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Ogólnie ocenie powinno podlegać prawdopodobieństwo $P_M(C')$, czyli\n",
|
|
"prawdopodobieństwo przypisane zbiorowi testowemu $C'$ przez model\n",
|
|
"(wyuczony na zbiorze $C$).\n",
|
|
"\n",
|
|
"Jeśli oceniamy przewidywania, które człowiek lub komputer czynią, to\n",
|
|
"im większe prawdopodobieństwo przypisane do tego, co miało miejsce,\n",
|
|
"tym lepiej. Zatem im wyższe $P_M(C')$, tym lepiej.\n",
|
|
"\n",
|
|
"Zazwyczaj będziemy rozbijali $P_M(C')$ na prawdopodobieństwa\n",
|
|
"przypisane do poszczególnych słów:\n",
|
|
"\n",
|
|
"$$P_M(w_1'\\dots w_{N'}') = P_M(w'_1)P_M(w'_2|w'_1)\\dots P_M(w'_{N'}|w'_1\\dots w'_{N'-1}) = \\prod_{i=1}^{N'} P_M(w'_i|w'_1\\ldots w'_{i-1}).$$\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Entropia krzyżowa\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Można powiedzieć, że dobry model języka „wnosi” informację o języku. Jeśli zarówno\n",
|
|
"nadawca i odbiorca tekstu mają do dyspozycji ten sam model języka…\n",
|
|
"\n",
|
|
"![img](./04_Ngramowy_model/lm-communication.drawio.png)\n",
|
|
"\n",
|
|
"… powinni być w stanie zaoszczędzić na długości komunikatu.\n",
|
|
"\n",
|
|
"W skrajnym przypadku, jeśli model jest pewny kolejnego słowa, tj.\n",
|
|
"$P_M(w'_i|w'_1\\ldots w'_{i-1}) = 1$, wówczas w $i$-tym kroku w ogóle\n",
|
|
"nic nie trzeba przesyłać przez kanał komunikacji. Taka sytuacja może\n",
|
|
"realnie wystąpić, na przykład: z prawdopodobieństwem zbliżonym do 1 po wyrazie\n",
|
|
"*Hong* wystąpi słowo *Kong*, a po wyrazie *przede* — wyraz *wszystkim*.\n",
|
|
"\n",
|
|
"Model języka może pomóc również w mniej skrajnym przypadkach, np.\n",
|
|
"jeżeli na danej pozycji w tekście model redukuje cały słownik do dwóch\n",
|
|
"wyrazów z prawdopodobieństwem 1/2, wówczas nadawca może zakodować tę\n",
|
|
"pozycję za pomocą jednego bitu.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Wzór na entropię krzyżową\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Przypomnijmy, że symbol o prawdopodobieństwie $p$ można zakodować za\n",
|
|
"pomocą (średnio) $-\\log_2(p)$ bitów, tak więc jeśli nadawca i odbiorca dysponują\n",
|
|
"modelem $M$, wówczas można przesłać cały zbiór testowy $C$ za pomocą następującej liczby bitów:\n",
|
|
"\n",
|
|
"$$-\\sum_{i=1}^{N'} log P_M(w'_i|w'_1\\ldots w'_{i-1}).$$\n",
|
|
"\n",
|
|
"Aby móc porównywać wyniki dla korpusów dla różnej długości, warto znormalizować\n",
|
|
"tę wartość, tzn. podzielić przez długość tekstu:\n",
|
|
"\n",
|
|
"$$H(M) = -\\frac{\\sum_{i=1}^{N'} log P_M(w'_i|w'_1\\ldots w'_{i-1})}{N'}.$$\n",
|
|
"\n",
|
|
"Tę wartość nazywamy **entropią krzyżową** modelu $M$. Entropia krzyżowa\n",
|
|
"mierzy naszą niewiedzę przy założeniu, że dysponujemy modelem $M$. Im niższa wartość\n",
|
|
"entropii krzyżowej, tym lepiej, im bowiem mniejsza nasza niewiedza,\n",
|
|
"tym lepiej.\n",
|
|
"\n",
|
|
"Entropią krzyżową jest często nazywaną funkcją **log loss**, zwłaszcza w\n",
|
|
"kontekście jej użycia jako funkcji straty przy uczeniu neuronowych modeli języka\n",
|
|
"(o których dowiemy się później).\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Wiarygodność\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Innym sposobem mierzenia jakości modelu języka jest odwołanie się do\n",
|
|
"**wiarygodności** (ang. *likelihood*). Wiarygodność to\n",
|
|
"prawdopodobieństwo przypisane zdarzeniom niejako „po fakcie”. Jak już\n",
|
|
"wspomnieliśmy, im wyższe prawdopodobieństwo (wiarygodność) przypisane\n",
|
|
"testowej części korpusu, tym lepiej. Innymi słowy, jako metrykę ewaluacji\n",
|
|
"używać będziemy prawdopodobieństwa:\n",
|
|
"\n",
|
|
"$$P_M(w_1'\\dots w_{N'}') = P_M(w'_1)P_M(w'_2|w'_1)\\dots P_M(w'_{N'}|w'_1\\dots w'_{N'-1}) = \\prod_{i=1}^{N'} P_M(w'_i|w'_1\\ldots w'_{i-1}),$$\n",
|
|
"\n",
|
|
"z tym, że znowu warto znormalizować to prawdopodobieństwo względem rozmiaru korpusu.\n",
|
|
"Ze względu na to, że prawdopodobieństwa przemnażamy, zamiast średniej arytmetycznej\n",
|
|
"lepiej użyć **średniej geometrycznej**:\n",
|
|
"\n",
|
|
"$$\\sqrt[N']{P_M(w_1'\\dots w_{N'}')} = \\sqrt[N']{\\prod_{i=1}^{N'} P_M(w'_i|w'_1\\ldots w'_{i-1})}.$$\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Interpretacja wiarygodności\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Co ciekawe, wiarygodność jest używana jako metryka ewaluacji modeli\n",
|
|
"języka rzadziej niż entropia krzyżowa (log loss), mimo tego, że wydaje\n",
|
|
"się nieco łatwiejsza do interpretacji dla człowieka. Otóż wiarygodność\n",
|
|
"to **średnia geometryczna prawdopodobieństw przypisanych przez model języka do słów, które rzeczywiście wystąpiły**.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Związek między wiarygodnością a entropią krzyżową\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Istnieje bardzo prosty związek między entropią krzyżową a wiarygodnością.\n",
|
|
"Otóż entropia krzyżowa to po prostu logarytm wiarygodności (z minusem):\n",
|
|
"\n",
|
|
"-$$\\log_2\\sqrt[N']{P_M(w_1'\\dots w_N')} = -\\frac{\\log_2\\prod_{i=1}^{N'} P_M(w'_i|w'_1\\ldots w'_{i-1})}{N'} = -\\frac{\\sum_{i=1}^{N'} \\log_2 P_M(w'_i|w'_1\\ldots w'_{i-1})}{N'}.$$\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### „log-proby”\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"W modelowaniu języka bardzo często używa się logarytmów prawdopodobieństw (z angielskiego skrótowo *log probs*),\n",
|
|
"zamiast wprost operować na prawdopodobieństwach:\n",
|
|
"\n",
|
|
"- dodawanie log probów jest tańsze obliczeniowo niż mnożenie prawdopodobieństw,\n",
|
|
"- bardzo małe prawdopodobieństwa znajdują się na granicy dokładności reprezentacji\n",
|
|
" liczb zmiennopozycyjnych, log proby są liczbami ujemnymi o „poręczniejszych”\n",
|
|
" rzędach wielkości.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Perplexity\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Tak naprawdę w literaturze przedmiotu na ogół używa się jeszcze innej metryki ewaluacji —\n",
|
|
"**perplexity**. Perplexity jest definiowane jako:\n",
|
|
"\n",
|
|
"$$\\operatorname{PP}(M) = 2^{H(M)}.$$\n",
|
|
"\n",
|
|
"Intuicyjnie można sobie wyobrazić, że perplexity to liczba możliwości\n",
|
|
"prognozowanych przez model z równym prawdopodobieństwem. Na przykład,\n",
|
|
"jeśli model przewiduje, że w danym miejscu tekstu może wystąpić z\n",
|
|
"równym prawdopodobieństwem jedno z 32 słów, wówczas (jeśli\n",
|
|
"rzeczywiście któreś z tych słów wystąpiło) entropia wynosi 5 bitów, a\n",
|
|
"perplexity — 32.\n",
|
|
"\n",
|
|
"Inaczej: perplexity to po prostu odwrotność wiarygodności:\n",
|
|
"\n",
|
|
"$$\\operatorname{PP}(M) = \\sqrt[N']{P_M(w_1'\\dots w_N')}.$$\n",
|
|
"\n",
|
|
"Perplexity zależy oczywiście od języka i modelu, ale typowe wartości\n",
|
|
"zazwyczaj zawierają się w przedziale 20-400.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Perplexity — przykład\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Wyuczmy model języka przy użyciu gotowego narzędzia [https://github.com/kpu/kenlm|KenLM](https://github.com/kpu/kenlm|KenLM).\n",
|
|
"KenLM to zaawansowane narzędzie do tworzenia n-gramowych modeli języka\n",
|
|
"(zaimplementowano w nim techniki wygładzania, które omówimy na kolejnym wykładzie).\n",
|
|
"\n",
|
|
"Wyuczmy na zbiorze uczącym wspomnianego wyzwania *Challenging America word-gap prediction*\n",
|
|
"dwa modele, jeden 3-gramowy, drugi 4-gramowy.\n",
|
|
"\n",
|
|
"Z powodu, który za chwilę stanie się jasny, teksty w zbiorze uczącym musimy sobie „poskładać” z kilku „kawałków”.\n",
|
|
"\n",
|
|
" $ cd train\n",
|
|
" $ xzcat in.tsv.xz | paste expected.tsv - | perl -ne 'chomp;s/\\\\n/ /g;s/<s>/ /g;@f=split/\\t/;print \"$f[7] $f[0] $f[8]\\n\"' | lmplz -o 3 --skip-symbols > model3.arpa\n",
|
|
" $ xzcat in.tsv.xz | paste expected.tsv - | perl -ne 'chomp;s/\\\\n/ /g;s/<s>/ /g;@f=split/\\t/;print \"$f[7] $f[0] $f[8]\\n\"' | lmplz -o 4 --skip-symbols > model4.arpa\n",
|
|
" $ cd ../dev-0\n",
|
|
" $ xzcat in.tsv.xz | paste expected.tsv - | perl -ne 'chomp;s/\\\\n/ /g;s/<s>/ /g;@f=split/\\t/;print \"$f[7] $f[0] $f[8]\\n\"' | query ../train/model3.arpa\n",
|
|
" Perplexity including OOVs:\t976.9905056314793\n",
|
|
" Perplexity excluding OOVs:\t616.5864921901557\n",
|
|
" OOVs:\t125276\n",
|
|
" Tokens:\t3452929\n",
|
|
" $ xzcat in.tsv.xz | paste expected.tsv - | perl -ne 'chomp;s/\\\\n/ /g;s/<s>/ /g;@f=split/\\t/;print \"$f[7] $f[0] $f[8]\\n\"' | query ../train/model4.arpa\n",
|
|
" Perplexity including OOVs:\t888.698932611321\n",
|
|
" Perplexity excluding OOVs:\t559.1231510292068\n",
|
|
" OOVs:\t125276\n",
|
|
" Tokens:\t3452929\n",
|
|
"\n",
|
|
"Jak widać model 4-gramowy jest lepszy (ma niższe perplexity) niż model 3-gramowy, przynajmniej\n",
|
|
"jeśli wierzyć raportowi programu KenLM.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Entropia krzyżowa, wiarygodność i perplexity — podsumowanie\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Trzy omawiane metryki ewaluacji modeli języka (entropia krzyżowa,\n",
|
|
"wiarygodność i perplexity) są ze sobą ściśle związane, w gruncie\n",
|
|
"rzeczy to po prostu jedna miara.\n",
|
|
"\n",
|
|
"| Metryka|Kierunek|Najlepsza wartość|Najgorsza wartość|\n",
|
|
"|---|---|---|---|\n",
|
|
"| entropia krzyżowa|im mniej, tym lepiej|0|$\\infty$|\n",
|
|
"| wiarygodność|im więcej, tym lepiej|1|0|\n",
|
|
"| perplexity|im mniej, tym lepiej|1|$\\infty$|\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Uwaga na zerowe prawdopodobieństwa\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Entropia krzyżowa, wiarygodność czy perplexity są bardzo czułe na zbyt\n",
|
|
"dużą pewność siebie. Wystarczy, że dla **jednej** pozycji w zbiorze\n",
|
|
"przypiszemy zerowe prawdopodobieństwo, wówczas wszystko „eksploduje”.\n",
|
|
"Perplexity i entropia krzyżowa „wybuchają” do nieskończoności,\n",
|
|
"wiarygodność spada do zera — bez względu na to, jak dobre są\n",
|
|
"przewidywania dotyczące innych pozycji w tekście!\n",
|
|
"\n",
|
|
"W przypadku wiarygodności wiąże się to z tym, że wiarygodność\n",
|
|
"definiujemy jako iloczyn prawdopodobieństwa, oczywiście wystarczy, że\n",
|
|
"jedna liczba w iloczynie była zerem, żeby iloczyn przyjął wartość\n",
|
|
"zero. Co więcej, nawet jeśli pominiemy taki skrajny przypadek, to\n",
|
|
"średnia geometryczna „ciągnie” w dół, bardzo niska wartość\n",
|
|
"prawdopodobieństwa przypisana do rzeczywistego słowa może drastycznie obniżyć\n",
|
|
"wartość wiarygodności (i podwyższyć perplexity).\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Słowa spoza słownika\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Prostym sposobem przeciwdziałania zerowaniu/wybuchaniu metryk jest\n",
|
|
"przypisywanie każdemu możliwemu słowu przynajmniej niskiego\n",
|
|
"prawdopodobieństwa $\\epsilon$. Niestety, zawsze może pojawić się\n",
|
|
"słowa, którego nie było w zbiorze uczącym — **słowo spoza słownika**\n",
|
|
"(*out-of-vocabulary word*, *OOV*). W takim przypadku znowu może\n",
|
|
"pojawić się zerowy/nieskończony wynik.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Ewaluacja modeli języka w warunkach konkursu\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Jeśli używać tradycyjnych metryk ewaluacji modeli języka (perplexity\n",
|
|
"czy wiarygodność), bardzo łatwo można „oszukać” — wystarczy\n",
|
|
"zaraportować prawdopodobieństwo 1! Oczywiście to absurd, bo albo\n",
|
|
"wszystkim innym tekstom przypisujemy prawdopodobieństwo 0, albo —\n",
|
|
"jeśli „oszukańczy” system każdemu innemu tekstowi przypisze\n",
|
|
"prawdopodobieństwo 1 — nie mamy do czynienia z poprawnym rozkładem\n",
|
|
"prawdopodobieństwa.\n",
|
|
"\n",
|
|
"Co gorsza, nawet jeśli wykluczymy scenariusz świadomego oszustwa,\n",
|
|
"łatwo *samego siebie* wprowadzić w błąd. Na przykład przez pomyłkę\n",
|
|
"można zwracać zawyżone prawdopodobieństwo (powiedzmy przemnożone przez 2).\n",
|
|
"\n",
|
|
"Te problemy stają się szczególnie dokuczliwe, jeśli organizujemy\n",
|
|
"wyzwanie, *konkurs* modelowania języka, gdzie chcemy w sposób\n",
|
|
"obiektywny porównywać różne modele języka, tak aby uniknąć celowego\n",
|
|
"bądź nieświadomego zawyżania wyników.\n",
|
|
"\n",
|
|
"Przedstawimy teraz, w jaki sposób poradzono sobie z tym problemem\n",
|
|
"w wyzwaniu *Challenging America word-gap prediction*\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Odgadywanie słowa w luce\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Po pierwsze, jaka sama nazwa wskazuje, w wyzwaniu *Challenging America\n",
|
|
"word-gap prediction* zamiast zwracania prawdopodobieństwa dla całego\n",
|
|
"tekstu oczekuje się podania rozkładu prawdopodobieństwa dla brakującego słowa.\n",
|
|
"\n",
|
|
"Mianowicie, w każdym wierszu wejściu (plik `in.tsv.xz`) w 7. i 8. polu\n",
|
|
"podany jest, odpowiednio, lewy i prawy kontekst słowa do odgadnięcia.\n",
|
|
"(W pozostałych polach znajdują się metadane, o których już wspomnieliśmy,\n",
|
|
"na razie nie będziemy ich wykorzystywać).\n",
|
|
"W pliku z oczekiwanym wyjściem (`expected.tsv`), w odpowiadającym\n",
|
|
"wierszu, podawane jest brakujące słowo. Oczywiście w ostatecznym\n",
|
|
"teście `test-A` plik `expected.tsv` jest niedostępny, ukryty przed uczestnikami konkursu.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Zapis rozkładu prawdopodobieństwa\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Dla każdego wiersza wejścia podajemy rozkład prawdopodobieństwa dla\n",
|
|
"słowa w luce w formacie:\n",
|
|
"\n",
|
|
" wyraz1:prob1 wyraz2:prob2 ... wyrazN:probN :prob0\n",
|
|
"\n",
|
|
"gdzie wyraz1, …, wyrazN to konkretne wyrazy, prob1, …, probN ich prawdopodobieństwa.\n",
|
|
"Można podać dowolną liczbę wyrazów.\n",
|
|
"Z kolei prob0 to „resztowe” prawdopodobieństwo przypisane do wszystkich pozostałych wyrazów,\n",
|
|
"prawdopodobieństwo to pozwala uniknąć problemów związanych ze słowami OOV, trzeba jeszcze tylko dokonać\n",
|
|
"modyfikacji metryki\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Metryka LikelihoodHashed\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Metryka LikelihoodHashed jest wariantem metryki Likelihood\n",
|
|
"(wiarygodności) opracowanym z myślą o wyzwaniach czy konkursach\n",
|
|
"modelowania języka. W tej metryce każde słowo wpada pseudolosowo do\n",
|
|
"jednego z $2^{10}=1024$ „kubełków”. Numer kubełka jest wyznaczony na\n",
|
|
"podstawie funkcji haszującej MurmurHash.\n",
|
|
"\n",
|
|
"Prawdopodobieństwa zwrócone przez ewaluowany model są sumowane w\n",
|
|
"każdym kubełku, następnie ewaluator zagląda do pliku \\`expected.tsv\\` i\n",
|
|
"uwzględnia prawdopodobieństwo z kubełka, do którego „wpada” oczekiwane\n",
|
|
"słowo. Oczywiście czasami więcej niż jedno słowo może wpaść do\n",
|
|
"kubełka, model mógł też „wrzucić” do kubełka tak naprawdę inne słowo\n",
|
|
"niż oczekiwane (przypadkiem oba słowa wpadają do jednego kubełka).\n",
|
|
"Tak więc LikelihoodHashed będzie nieco zawyżone w stosunku do Likelihood.\n",
|
|
"\n",
|
|
"Dlaczego więc taka komplikacja? Otóż LikelihoodHashed nie zakłada\n",
|
|
"żadnego słownika, znika problem słów OOV — prawdopodobieństwa resztowe prob0\n",
|
|
"są rozkładane równomiernie między wszystkie 1024 kubełki.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"##### Alternatywne metryki\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"LikelihoodHashed została zaimplementowana w narzędziu ewaluacyjnym\n",
|
|
"[https://gitlab.com/filipg/geval|GEval](https://gitlab.com/filipg/geval|GEval). Są tam również dostępne\n",
|
|
"analogiczne warianty entropii krzyżowej (log loss) i perplexity\n",
|
|
"(LogLossHashed i PerplexityHashed).\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.2"
|
|
},
|
|
"org": null
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 1
|
|
}
|