1175 lines
34 KiB
Plaintext
1175 lines
34 KiB
Plaintext
|
{
|
||
|
"cells": [
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## Wygładzanie w n-gramowych modelach języka\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"### Dlaczego wygładzanie?\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Wyobraźmy sobie urnę, w której znajdują się kule w $m$ kolorach\n",
|
||
|
"(ściślej: w co najwyżej $m$ kolorach, może w ogóle nie być kul w danym\n",
|
||
|
"kolorze). Nie wiemy, ile jest ogółem kul w urnie i w jakiej liczbie\n",
|
||
|
"występuje każdy z kolorów.\n",
|
||
|
"\n",
|
||
|
"Losujemy ze zwracaniem (to istotne!) $T$ kul, załóżmy, że\n",
|
||
|
"wylosowaliśmy w poszczególnych kolorach $\\{k_1,\\dots,k_m\\}$ kul\n",
|
||
|
"(tzn. pierwszą kolor wylosowaliśmy $k_1$ razy, drugi kolor — $k_2$ razy itd.).\n",
|
||
|
"Rzecz jasna, $\\sum_{i=1}^m k_i = T$.\n",
|
||
|
"\n",
|
||
|
"Jak powinniśmy racjonalnie szacować prawdopodobieństwa wylosowania kuli w $i$-tym kolorze ($p_i$)?\n",
|
||
|
"\n",
|
||
|
"Wydawałoby się, że wystarczy liczbę wylosowanych kul w danym kolorze\n",
|
||
|
"podzielić przez liczbę wszystkich prób:\n",
|
||
|
"\n",
|
||
|
"$$p_i = \\frac{k_i}{T}.$$\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Wygładzanie — przykład\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Rozpatrzmy przykład z 3 kolorami (wiemy, że w urnie mogą być kule\n",
|
||
|
"żółte, zielone i czerwone, tj. $m=3$) i 4 losowaniami ($T=4$):\n",
|
||
|
"\n",
|
||
|
"![img](./05_Wygladzanie/urna.drawio.png)\n",
|
||
|
"\n",
|
||
|
"Gdybyśmy w prosty sposób oszacowali prawdopodobieństwa, doszlibyśmy do\n",
|
||
|
"wniosku, że prawdopodobieństwo wylosowania kuli czerwonej wynosi 3/4, żółtej — 1/4,\n",
|
||
|
"a zielonej — 0. Wartości te są jednak dość problematyczne:\n",
|
||
|
"\n",
|
||
|
"- Za bardzo przywiązujemy się do naszej skromnej próby,\n",
|
||
|
" potrzebowalibyśmy większej liczby losowań, żeby być bardziej pewnym\n",
|
||
|
" naszych estymacji.\n",
|
||
|
"- W szczególności stwierdzenie, że prawdopodobieństwo wylosowania kuli\n",
|
||
|
" zielonej wynosi 0, jest bardzo mocnym stwierdzeniem (twierdzimy, że\n",
|
||
|
" **NIEMOŻLIWE** jest wylosowanie kuli zielonej), dopiero większa liczba\n",
|
||
|
" prób bez wylosowania zielonej kuli mogłaby sugerować\n",
|
||
|
" prawdopodobieństwo bliskie zeru.\n",
|
||
|
"- Zauważmy, że niemożliwe jest wylosowanie ułamka kuli, jeśli w\n",
|
||
|
" rzeczywistości 10% kul jest żółtych, to nie oznacza się wylosujemy\n",
|
||
|
" $4\\frac{1}{10} = \\frac{2}{5}$ kuli. Prawdopodobnie wylosujemy jedną\n",
|
||
|
" kulę żółtą albo żadną. Wylosowanie dwóch kul żółtych byłoby możliwe,\n",
|
||
|
" ale mniej prawdopodobne. Jeszcze mniej prawdopodobne byłoby\n",
|
||
|
" wylosowanie 3 lub 4 kul żółtych.\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Idea wygładzania\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Wygładzanie (ang. *smoothing*) polega na tym, że „uszczknąć” nieco\n",
|
||
|
"masy prawdopodobieństwa zdarzeniom wskazywanym przez eksperyment czy\n",
|
||
|
"zbiór uczący i rozdzielić ją między mniej prawdopodobne zdarzenia.\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Wygładzanie +1\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Najprostszy sposób wygładzania to wygładzania +1, nazywane też wygładzaniem\n",
|
||
|
"Laplace'a, zdefiniowane za pomocą następującego wzoru:\n",
|
||
|
"\n",
|
||
|
"$$p_i = \\frac{k_i+1}{T+m}.$$\n",
|
||
|
"\n",
|
||
|
"W naszym przykładzie z urną prawdopodobieństwo wylosowania kuli\n",
|
||
|
"czerwonej określimy na $\\frac{3+1}{4+3} = \\frac{4}{7}$, kuli żółtej —\n",
|
||
|
"$\\frac{1+1}{4+3}=2/7$, zielonej — $\\frac{0+1}{4+3}=1/7$. Tym samym,\n",
|
||
|
"kula zielona uzyskała niezerowe prawdopodobieństwo, żółta — nieco\n",
|
||
|
"zyskała, zaś czerwona — straciła.\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"##### Własności wygładzania +1\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Zauważmy, że większa liczba prób $m$, tym bardziej ufamy naszemu eksperymentowi\n",
|
||
|
"(czy zbiorowi uczącemu) i tym bardziej zbliżamy się do niewygładzonej wartości:\n",
|
||
|
"\n",
|
||
|
"$$\\lim_{m \\rightarrow \\infty} \\frac{k_i +1}{T + m} = \\frac{k_i}{T}.$$\n",
|
||
|
"\n",
|
||
|
"Inna dobra, zdroworozsądkowo, własność to to, że prawdopodobieństwo nigdy nie będzie zerowe:\n",
|
||
|
"\n",
|
||
|
"$$\\frac{k_i + 1}{T + m} > 0.$$\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"### Wygładzanie w unigramowym modelu języku\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Analogia do urny\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Unigramowy model języka, abstrakcyjnie, dokładnie realizuje scenariusz\n",
|
||
|
"losowania kul z urny: $m$ to liczba wszystkich wyrazów (czyli rozmiar słownika $|V|$),\n",
|
||
|
"$k_i$ to ile razy w zbiorze uczącym pojawił się $i$-ty wyraz słownika,\n",
|
||
|
"$T$ — długość zbioru uczącego.\n",
|
||
|
"\n",
|
||
|
"![img](./05_Wygladzanie/urna-wyrazy.drawio.png)\n",
|
||
|
"\n",
|
||
|
"A zatem przy użyciu wygładzania +1 w następujący sposób estymować\n",
|
||
|
"będziemy prawdopodobieństwo słowa $w$:\n",
|
||
|
"\n",
|
||
|
"$$P(w) = \\frac{\\# w + 1}{|C| + |V|}.$$\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Wygładzanie $+\\alpha$\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"W modelowaniu języka wygładzanie $+1$ daje zazwyczaj niepoprawne\n",
|
||
|
"wyniki, dlatego częściej zamiast wartości 1 używa się współczynnika $0\n",
|
||
|
"< \\alpha < 1$:\n",
|
||
|
"\n",
|
||
|
"$$P(w) = \\frac{\\# w + \\alpha}{|C| + \\alpha|V|}.$$\n",
|
||
|
"\n",
|
||
|
"W innych praktycznych zastosowaniach statystyki\n",
|
||
|
"przyjmuje się $\\alpha = \\frac{1}{2}$, ale w przypadku n-gramowych\n",
|
||
|
"modeli języka i to będzie zbyt duża wartość.\n",
|
||
|
"\n",
|
||
|
"W jaki sposób ustalić wartość $\\alpha$? Można $\\alpha$ potraktować $\\alpha$\n",
|
||
|
"jako hiperparametr i dostroić ją na odłożonym zbiorze.\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Jak wybrać wygładzanie?\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Jak ocenić, który sposób wygładzania jest lepszy? Jak wybrać $\\alpha$\n",
|
||
|
"w czasie dostrajania?\n",
|
||
|
"\n",
|
||
|
"Najprościej można sprawdzić estymowane prawdopodobieństwa na zbiorze\n",
|
||
|
"strojącym (developerskim). Dla celów poglądowych bardziej czytelny\n",
|
||
|
"będzie podział zbioru uczącego na dwie równe części — będziemy\n",
|
||
|
"porównywać częstości estymowane na jednej połówce korpusu z\n",
|
||
|
"rzeczywistymi, empirycznymi częstościami z drugiej połówki.\n",
|
||
|
"\n",
|
||
|
"Wyniki będziemy przedstawiać w postaci tabeli, gdzie w poszczególnych\n",
|
||
|
"wierszach będziemy opisywać częstości estymowane dla wszystkich\n",
|
||
|
"wyrazów, które pojawiły się określoną liczbę razy w pierwszej połówce korpusu.\n",
|
||
|
"\n",
|
||
|
"Ostatecznie możemy też po prostu policzyć perplexity na zbiorze testowym\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Przykład\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Użyjemy polskiej części z korpusu równoległego Open Subtitles:\n",
|
||
|
"\n",
|
||
|
" wget -O en-pl.txt.zip 'https://opus.nlpl.eu/download.php?f=OpenSubtitles/v2018/moses/en-pl.txt.zip'\n",
|
||
|
" unzip en-pl.txt.zip\n",
|
||
|
"\n",
|
||
|
"Usuńmy duplikaty (zachowując kolejność):\n",
|
||
|
"\n",
|
||
|
" nl OpenSubtitles.en-pl.pl | sort -k 2 -u | sort -k 1 | cut -f 2- > opensubtitles.pl.txt\n",
|
||
|
"\n",
|
||
|
"Korpus zawiera ponad 28 mln słów, zdania są krótkie, jest to język potoczny, czasami wulgarny.\n",
|
||
|
"\n",
|
||
|
" $ wc opensubtitles.pl.txt\n",
|
||
|
" 28154303 178866171 1206735898 opensubtitles.pl.txt\n",
|
||
|
" $ head -n 10 opensubtitles.pl.txt\n",
|
||
|
" Lubisz curry, prawda?\n",
|
||
|
" Nałożę ci więcej.\n",
|
||
|
" Hey!\n",
|
||
|
" Smakuje ci?\n",
|
||
|
" Hey, brzydalu.\n",
|
||
|
" Spójrz na nią.\n",
|
||
|
" - Wariatka.\n",
|
||
|
" - Zadałam ci pytanie!\n",
|
||
|
" No, tak lepiej!\n",
|
||
|
" - Wygląda dobrze!\n",
|
||
|
"\n",
|
||
|
"Podzielimy korpus na dwie części:\n",
|
||
|
"\n",
|
||
|
" head -n 14077151 < opensubtitles.pl.txt > opensubtitlesA.pl.txt\n",
|
||
|
" tail -n 14077151 < opensubtitles.pl.txt > opensubtitlesB.pl.txt\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"##### Tokenizacja\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Stwórzmy generator, który będzie wczytywał słowa z pliku, dodatkowo:\n",
|
||
|
"\n",
|
||
|
"- ciągi znaków interpunkcyjnych będziemy traktować jak tokeny,\n",
|
||
|
"- sprowadzimy wszystkie litery do małych,\n",
|
||
|
"- dodamy specjalne tokeny na początek i koniec zdania (`<s>` i `</s>`).\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 1,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/plain": [
|
||
|
"['<s>',\n",
|
||
|
" 'lubisz',\n",
|
||
|
" 'curry',\n",
|
||
|
" ',',\n",
|
||
|
" 'prawda',\n",
|
||
|
" '?',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" 'nałożę',\n",
|
||
|
" 'ci',\n",
|
||
|
" 'więcej',\n",
|
||
|
" '.',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" 'hey',\n",
|
||
|
" '!',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" 'smakuje',\n",
|
||
|
" 'ci',\n",
|
||
|
" '?',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" 'hey',\n",
|
||
|
" ',',\n",
|
||
|
" 'brzydalu',\n",
|
||
|
" '.',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" 'spójrz',\n",
|
||
|
" 'na',\n",
|
||
|
" 'nią',\n",
|
||
|
" '.',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" '-',\n",
|
||
|
" 'wariatka',\n",
|
||
|
" '.',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" '-',\n",
|
||
|
" 'zadałam',\n",
|
||
|
" 'ci',\n",
|
||
|
" 'pytanie',\n",
|
||
|
" '!',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" 'no',\n",
|
||
|
" ',',\n",
|
||
|
" 'tak',\n",
|
||
|
" 'lepiej',\n",
|
||
|
" '!',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" '-',\n",
|
||
|
" 'wygląda',\n",
|
||
|
" 'dobrze',\n",
|
||
|
" '!',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" '-',\n",
|
||
|
" 'tak',\n",
|
||
|
" 'lepiej',\n",
|
||
|
" '!',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" 'pasuje',\n",
|
||
|
" 'jej',\n",
|
||
|
" '.',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" '-',\n",
|
||
|
" 'hey',\n",
|
||
|
" '.',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" '-',\n",
|
||
|
" 'co',\n",
|
||
|
" 'do',\n",
|
||
|
" '...?',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" 'co',\n",
|
||
|
" 'do',\n",
|
||
|
" 'cholery',\n",
|
||
|
" 'robisz',\n",
|
||
|
" '?',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" 'zejdź',\n",
|
||
|
" 'mi',\n",
|
||
|
" 'z',\n",
|
||
|
" 'oczu',\n",
|
||
|
" ',',\n",
|
||
|
" 'zdziro',\n",
|
||
|
" '.',\n",
|
||
|
" '</s>',\n",
|
||
|
" '<s>',\n",
|
||
|
" 'przestań',\n",
|
||
|
" 'dokuczać']"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 1,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"from itertools import islice\n",
|
||
|
"import regex as re\n",
|
||
|
"import sys\n",
|
||
|
"\n",
|
||
|
"def get_words_from_file(file_name):\n",
|
||
|
" with open(file_name, 'r') as fh:\n",
|
||
|
" for line in fh:\n",
|
||
|
" line = line.rstrip()\n",
|
||
|
" yield '<s>'\n",
|
||
|
" for m in re.finditer(r'[\\p{L}0-9\\*]+|\\p{P}+', line):\n",
|
||
|
" yield m.group(0).lower()\n",
|
||
|
" yield '</s>'\n",
|
||
|
"\n",
|
||
|
"list(islice(get_words_from_file('opensubtitlesA.pl.txt'), 0, 100))"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"##### Empiryczne wyniki\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Zobaczmy, ile razy, średnio w drugiej połówce korpusu występują\n",
|
||
|
"wyrazy, które w pierwszej wystąpiły określoną liczbę razy.\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 2,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"from collections import Counter\n",
|
||
|
"\n",
|
||
|
"counterA = Counter(get_words_from_file('opensubtitlesA.pl.txt'))"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 3,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/plain": [
|
||
|
"48113"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 3,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"counterA['taki']"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 4,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"max_r = 10\n",
|
||
|
"\n",
|
||
|
"buckets = {}\n",
|
||
|
"for token in counterA:\n",
|
||
|
" buckets.setdefault(counterA[token], 0)\n",
|
||
|
" buckets[counterA[token]] += 1\n",
|
||
|
"\n",
|
||
|
"bucket_counts = {}\n",
|
||
|
"\n",
|
||
|
"counterB = Counter(get_words_from_file('opensubtitlesB.pl.txt'))\n",
|
||
|
"\n",
|
||
|
"for token in counterB:\n",
|
||
|
" bucket_id = counterA[token] if token in counterA else 0\n",
|
||
|
" if bucket_id <= max_r:\n",
|
||
|
" bucket_counts.setdefault(bucket_id, 0)\n",
|
||
|
" bucket_counts[bucket_id] += counterB[token]\n",
|
||
|
" if bucket_id == 0:\n",
|
||
|
" buckets.setdefault(0, 0)\n",
|
||
|
" buckets[0] += 1\n",
|
||
|
"\n",
|
||
|
"nb_of_types = [buckets[ix] for ix in range(0, max_r+1)]\n",
|
||
|
"empirical_counts = [bucket_counts[ix] / buckets[ix] for ix in range(0, max_r)]"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Policzmy teraz jakiej liczby wystąpień byśmy oczekiwali, gdyby użyć wygładzania +1 bądź +0.01.\n",
|
||
|
"(Uwaga: zwracamy liczbę wystąpień, a nie względną częstość, stąd przemnażamy przez rozmiar całego korpusu).\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 5,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/plain": [
|
||
|
"926594"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 5,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"def plus_alpha_smoothing(alpha, m, t, k):\n",
|
||
|
" return t*(k + alpha)/(t + alpha * m)\n",
|
||
|
"\n",
|
||
|
"def plus_one_smoothing(m, t, k):\n",
|
||
|
" return plus_alpha_smoothing(1.0, m, t, k)\n",
|
||
|
"\n",
|
||
|
"vocabulary_size = len(counterA)\n",
|
||
|
"corpus_size = counterA.total()\n",
|
||
|
"\n",
|
||
|
"plus_one_counts = [plus_one_smoothing(vocabulary_size, corpus_size, ix) for ix in range(0, max_r)]\n",
|
||
|
"\n",
|
||
|
"plus_alpha_counts = [plus_alpha_smoothing(0.01, vocabulary_size, corpus_size, ix) for ix in range(0, max_r)]\n",
|
||
|
"\n",
|
||
|
"data = list(zip(nb_of_types, empirical_counts, plus_one_counts, plus_alpha_counts))\n",
|
||
|
"\n",
|
||
|
"vocabulary_size"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 6,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/html": [
|
||
|
"<div>\n",
|
||
|
"<style scoped>\n",
|
||
|
" .dataframe tbody tr th:only-of-type {\n",
|
||
|
" vertical-align: middle;\n",
|
||
|
" }\n",
|
||
|
"\n",
|
||
|
" .dataframe tbody tr th {\n",
|
||
|
" vertical-align: top;\n",
|
||
|
" }\n",
|
||
|
"\n",
|
||
|
" .dataframe thead th {\n",
|
||
|
" text-align: right;\n",
|
||
|
" }\n",
|
||
|
"</style>\n",
|
||
|
"<table border=\"1\" class=\"dataframe\">\n",
|
||
|
" <thead>\n",
|
||
|
" <tr style=\"text-align: right;\">\n",
|
||
|
" <th></th>\n",
|
||
|
" <th>liczba tokenów</th>\n",
|
||
|
" <th>średnia częstość w części B</th>\n",
|
||
|
" <th>estymacje +1</th>\n",
|
||
|
" <th>estymacje +0.01</th>\n",
|
||
|
" </tr>\n",
|
||
|
" </thead>\n",
|
||
|
" <tbody>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>0</th>\n",
|
||
|
" <td>388334</td>\n",
|
||
|
" <td>1.900495</td>\n",
|
||
|
" <td>0.993586</td>\n",
|
||
|
" <td>0.009999</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>1</th>\n",
|
||
|
" <td>403870</td>\n",
|
||
|
" <td>0.592770</td>\n",
|
||
|
" <td>1.987172</td>\n",
|
||
|
" <td>1.009935</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>2</th>\n",
|
||
|
" <td>117529</td>\n",
|
||
|
" <td>1.565809</td>\n",
|
||
|
" <td>2.980759</td>\n",
|
||
|
" <td>2.009870</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>3</th>\n",
|
||
|
" <td>62800</td>\n",
|
||
|
" <td>2.514268</td>\n",
|
||
|
" <td>3.974345</td>\n",
|
||
|
" <td>3.009806</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>4</th>\n",
|
||
|
" <td>40856</td>\n",
|
||
|
" <td>3.504944</td>\n",
|
||
|
" <td>4.967931</td>\n",
|
||
|
" <td>4.009741</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>5</th>\n",
|
||
|
" <td>29443</td>\n",
|
||
|
" <td>4.454098</td>\n",
|
||
|
" <td>5.961517</td>\n",
|
||
|
" <td>5.009677</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>6</th>\n",
|
||
|
" <td>22709</td>\n",
|
||
|
" <td>5.232023</td>\n",
|
||
|
" <td>6.955103</td>\n",
|
||
|
" <td>6.009612</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>7</th>\n",
|
||
|
" <td>18255</td>\n",
|
||
|
" <td>6.157929</td>\n",
|
||
|
" <td>7.948689</td>\n",
|
||
|
" <td>7.009548</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>8</th>\n",
|
||
|
" <td>15076</td>\n",
|
||
|
" <td>7.308039</td>\n",
|
||
|
" <td>8.942276</td>\n",
|
||
|
" <td>8.009483</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>9</th>\n",
|
||
|
" <td>12859</td>\n",
|
||
|
" <td>8.045649</td>\n",
|
||
|
" <td>9.935862</td>\n",
|
||
|
" <td>9.009418</td>\n",
|
||
|
" </tr>\n",
|
||
|
" </tbody>\n",
|
||
|
"</table>\n",
|
||
|
"</div>"
|
||
|
],
|
||
|
"text/plain": [
|
||
|
" liczba tokenów średnia częstość w części B estymacje +1 estymacje +0.01\n",
|
||
|
"0 388334 1.900495 0.993586 0.009999\n",
|
||
|
"1 403870 0.592770 1.987172 1.009935\n",
|
||
|
"2 117529 1.565809 2.980759 2.009870\n",
|
||
|
"3 62800 2.514268 3.974345 3.009806\n",
|
||
|
"4 40856 3.504944 4.967931 4.009741\n",
|
||
|
"5 29443 4.454098 5.961517 5.009677\n",
|
||
|
"6 22709 5.232023 6.955103 6.009612\n",
|
||
|
"7 18255 6.157929 7.948689 7.009548\n",
|
||
|
"8 15076 7.308039 8.942276 8.009483\n",
|
||
|
"9 12859 8.045649 9.935862 9.009418"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 6,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"import pandas as pd\n",
|
||
|
"\n",
|
||
|
"pd.DataFrame(data, columns=[\"liczba tokenów\", \"średnia częstość w części B\", \"estymacje +1\", \"estymacje +0.01\"])"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Wygładzanie Gooda-Turinga\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Inna metoda — wygładzanie Gooda-Turinga — polega na zliczaniu, ile\n",
|
||
|
"$n$-gramów (na razie rozpatrujemy model unigramowy, więc po prostu pojedynczych\n",
|
||
|
"wyrazów) wystąpiło zadaną liczbę razy. Niech $N_r$ oznacza właśnie,\n",
|
||
|
"ile $n$-gramów wystąpiło dokładnie $r$ razy; na przykład $N_1$ oznacza liczbę *hapax legomena*.\n",
|
||
|
"\n",
|
||
|
"W metodzie Gooda-Turinga używamy następującej estymacji:\n",
|
||
|
"\n",
|
||
|
"$$p(w) = \\frac{\\# w + 1}{|C|}\\frac{N_{r+1}}{N_r}.$$\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"##### Przykład\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 7,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/html": [
|
||
|
"<div>\n",
|
||
|
"<style scoped>\n",
|
||
|
" .dataframe tbody tr th:only-of-type {\n",
|
||
|
" vertical-align: middle;\n",
|
||
|
" }\n",
|
||
|
"\n",
|
||
|
" .dataframe tbody tr th {\n",
|
||
|
" vertical-align: top;\n",
|
||
|
" }\n",
|
||
|
"\n",
|
||
|
" .dataframe thead th {\n",
|
||
|
" text-align: right;\n",
|
||
|
" }\n",
|
||
|
"</style>\n",
|
||
|
"<table border=\"1\" class=\"dataframe\">\n",
|
||
|
" <thead>\n",
|
||
|
" <tr style=\"text-align: right;\">\n",
|
||
|
" <th></th>\n",
|
||
|
" <th>liczba tokenów</th>\n",
|
||
|
" <th>średnia częstość w części B</th>\n",
|
||
|
" <th>estymacje +1</th>\n",
|
||
|
" <th>Good-Turing</th>\n",
|
||
|
" </tr>\n",
|
||
|
" </thead>\n",
|
||
|
" <tbody>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>0</th>\n",
|
||
|
" <td>388334</td>\n",
|
||
|
" <td>1.900495</td>\n",
|
||
|
" <td>0.993586</td>\n",
|
||
|
" <td>1.040007</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>1</th>\n",
|
||
|
" <td>403870</td>\n",
|
||
|
" <td>0.592770</td>\n",
|
||
|
" <td>1.987172</td>\n",
|
||
|
" <td>0.582014</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>2</th>\n",
|
||
|
" <td>117529</td>\n",
|
||
|
" <td>1.565809</td>\n",
|
||
|
" <td>2.980759</td>\n",
|
||
|
" <td>1.603009</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>3</th>\n",
|
||
|
" <td>62800</td>\n",
|
||
|
" <td>2.514268</td>\n",
|
||
|
" <td>3.974345</td>\n",
|
||
|
" <td>2.602293</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>4</th>\n",
|
||
|
" <td>40856</td>\n",
|
||
|
" <td>3.504944</td>\n",
|
||
|
" <td>4.967931</td>\n",
|
||
|
" <td>3.603265</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>5</th>\n",
|
||
|
" <td>29443</td>\n",
|
||
|
" <td>4.454098</td>\n",
|
||
|
" <td>5.961517</td>\n",
|
||
|
" <td>4.627721</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>6</th>\n",
|
||
|
" <td>22709</td>\n",
|
||
|
" <td>5.232023</td>\n",
|
||
|
" <td>6.955103</td>\n",
|
||
|
" <td>5.627064</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>7</th>\n",
|
||
|
" <td>18255</td>\n",
|
||
|
" <td>6.157929</td>\n",
|
||
|
" <td>7.948689</td>\n",
|
||
|
" <td>6.606847</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>8</th>\n",
|
||
|
" <td>15076</td>\n",
|
||
|
" <td>7.308039</td>\n",
|
||
|
" <td>8.942276</td>\n",
|
||
|
" <td>7.676506</td>\n",
|
||
|
" </tr>\n",
|
||
|
" <tr>\n",
|
||
|
" <th>9</th>\n",
|
||
|
" <td>12859</td>\n",
|
||
|
" <td>8.045649</td>\n",
|
||
|
" <td>9.935862</td>\n",
|
||
|
" <td>8.557431</td>\n",
|
||
|
" </tr>\n",
|
||
|
" </tbody>\n",
|
||
|
"</table>\n",
|
||
|
"</div>"
|
||
|
],
|
||
|
"text/plain": [
|
||
|
" liczba tokenów średnia częstość w części B estymacje +1 Good-Turing\n",
|
||
|
"0 388334 1.900495 0.993586 1.040007\n",
|
||
|
"1 403870 0.592770 1.987172 0.582014\n",
|
||
|
"2 117529 1.565809 2.980759 1.603009\n",
|
||
|
"3 62800 2.514268 3.974345 2.602293\n",
|
||
|
"4 40856 3.504944 4.967931 3.603265\n",
|
||
|
"5 29443 4.454098 5.961517 4.627721\n",
|
||
|
"6 22709 5.232023 6.955103 5.627064\n",
|
||
|
"7 18255 6.157929 7.948689 6.606847\n",
|
||
|
"8 15076 7.308039 8.942276 7.676506\n",
|
||
|
"9 12859 8.045649 9.935862 8.557431"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 7,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"good_turing_counts = [(ix+1)*nb_of_types[ix+1]/nb_of_types[ix] for ix in range(0, max_r)]\n",
|
||
|
"\n",
|
||
|
"data2 = list(zip(nb_of_types, empirical_counts, plus_one_counts, good_turing_counts))\n",
|
||
|
"\n",
|
||
|
"pd.DataFrame(data2, columns=[\"liczba tokenów\", \"średnia częstość w części B\", \"estymacje +1\", \"Good-Turing\"])"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Wygładzanie metodą Gooda-Turinga, mimo prostoty, daje wyniki zaskakująco zbliżone do rzeczywistych.\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"### Wygładzanie dla $n$-gramów\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Rzadkość danych\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"W wypadku bigramów, trigramów, tetragramów itd. jeszcze dotkliwy staje się problem\n",
|
||
|
"**rzadkości** danych (*data sparsity*). Przestrzeń możliwych zdarzeń\n",
|
||
|
"jest jeszcze większa ($|V|^2$ dla bigramów), więc estymacje stają się\n",
|
||
|
"jeszcze mniej pewne.\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Back-off\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Dla $n$-gramów, gdzie $n>1$, nie jesteśmy ograniczeni do wygładzania $+1$, $+k$ czy Gooda-Turinga.\n",
|
||
|
"W przypadku rzadkich $n$-gramów, w szczególności, gdy $n$-gram w ogóle się nie pojawił w korpusie,\n",
|
||
|
"możemy „zejść” na poziom krótszych $n$-gramów. Na tym polega **back-off**.\n",
|
||
|
"\n",
|
||
|
"Otóż jeśli $\\# w_{i-n+1}\\ldots w_{i-1} > 0$, wówczas estymujemy prawdopodobieństwa\n",
|
||
|
" w tradycyjny sposób:\n",
|
||
|
"\n",
|
||
|
"$$P_B(w_i|w_{i-n+1}\\ldots w_{i-1}) = d_n(w_{i-n+1}\\ldots w_{i-1}\\ldots w_{i-1}) P(w_i|w_{i-n+1}\\ldots w_{i-1})$$\n",
|
||
|
"\n",
|
||
|
"W przeciwnym razie rozpatrujemy rekurencyjnie krótszy $n$-gram:\n",
|
||
|
"\n",
|
||
|
"$$P_B(w_i|w_{i-n+1}\\ldots w_{i-1}) = \\delta_n(w_{i-n+1}\\ldots w_{i-1}\\ldots w_{i-1}) P_B(w_i|w_{i-n+2}\\ldots w_{i-1}).$$\n",
|
||
|
"\n",
|
||
|
"Technicznie, aby $P_B$ stanowiło rozkład prawdopodobieństwa, trzeba dobrać współczynniki $d$ i $\\delta$.\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Interpolacja\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Alternatywą do metody back-off jest **interpolacja** — zawsze z pewnym współczynnikiem uwzględniamy\n",
|
||
|
"prawdopodobieństwa dla krótszych $n$-gramów:\n",
|
||
|
"\n",
|
||
|
"$$P_I(w_i|w_{i-n+1}\\ldots w_{i-1}) = \\lambda P(w_i|w_{i-n+1}\\dots w_{i-1}) + (1-\\lambda)\n",
|
||
|
" P_I(w_i|w_{i-n+2}\\dots w_{i-1}).$$\n",
|
||
|
"\n",
|
||
|
"Na przykład, dla trigramów:\n",
|
||
|
"\n",
|
||
|
"$$P_I(w_i|w_{i-2}w_{i-1}) = \\lambda P_(w_i|w_{i-2}w_{i-1}) + (1-\\lambda)(\\lambda P(w_i|w_{i-1}) + (1-\\lambda)P_I(w_i)).$$\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"### Uwzględnianie różnorodności\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Różnorodność kontynuacji\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Zauważmy, że słowa mogą bardzo różnić się co do różnorodności\n",
|
||
|
"kontynuacji. Na przykład po słowie *szop* spodziewamy się raczej tylko\n",
|
||
|
"słowa *pracz*, każde inne, niewidziane w zbiorze uczącym, będzie\n",
|
||
|
"zaskakujące. Dla porównania słowo *seledynowy* ma bardzo dużo\n",
|
||
|
"możliwych kontynuacji i powinniśmy przeznaczyć znaczniejszą część masy\n",
|
||
|
"prawdopodobieństwa na kontynuacje niewidziane w zbiorze uczącym.\n",
|
||
|
"\n",
|
||
|
"Różnorodność kontynuacji bierze pod uwagę metoda wygładzania\n",
|
||
|
"Wittena-Bella, będącą wersją interpolacji.\n",
|
||
|
"\n",
|
||
|
"Wprowadźmy oznaczenie na liczbę możliwych kontynuacji $n-1$-gramu $w_1\\ldots w_{n-1}$:\n",
|
||
|
"\n",
|
||
|
"$$N_{1+}(w_1\\ldots w_{n-1}\\dot\\bullet) = |\\{w_n : \\# w_1\\ldots w_{n-1}w_n > 0\\}|.$$\n",
|
||
|
"\n",
|
||
|
"Teraz zastosujemy interpolację z następującą wartością parametru\n",
|
||
|
"$1-\\lambda$, sterującego wagą, jaką przypisujemy do krótszych $n$-gramów:\n",
|
||
|
"\n",
|
||
|
"$$1 - \\lambda = \\frac{N_{1+}(w_1\\ldots w_{n-1}\\dot\\bullet)}{N_{1+}(w_1\\ldots w_{n-1}\\dot\\bullet) + \\# w_1\\ldots w_{n-1}}.$$\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Wygładzanie Knesera-Neya\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Zamiast brać pod uwagę różnorodność kontynuacji, możemy rozpatrywać\n",
|
||
|
"różnorodność **historii** — w momencie liczenia prawdopodobieństwa dla\n",
|
||
|
"unigramów dla interpolacji (nie ma to zastosowania dla modeli\n",
|
||
|
"unigramowych). Na przykład dla wyrazu *Jork* spodziewamy się tylko\n",
|
||
|
"bigramu *Nowy Jork*, a zatem przy interpolacji czy back-off prawdopodobieństwo\n",
|
||
|
"unigramowe powinno być niskie.\n",
|
||
|
"\n",
|
||
|
"Wprowadźmy oznaczenia na liczbę możliwych historii:\n",
|
||
|
"\n",
|
||
|
"$$N_{1+}(\\bullet w) = |\\{w_j : \\# w_jw > 0\\}|$$.\n",
|
||
|
"\n",
|
||
|
"W metodzie Knesera-Neya w następujący sposób estymujemy prawdopodobieństwo unigramu:\n",
|
||
|
"\n",
|
||
|
"$$P(w) = \\frac{N_{1+}(\\bullet w)}{\\sum_{w_j} N_{1+}(\\bullet w_j)}.$$\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 8,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/plain": [
|
||
|
"[('k', 'o', 't'), ('o', 't', 'e'), ('t', 'e', 'k')]"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 8,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"def ngrams(iter, size):\n",
|
||
|
" ngram = []\n",
|
||
|
" for item in iter:\n",
|
||
|
" ngram.append(item)\n",
|
||
|
" if len(ngram) == size:\n",
|
||
|
" yield tuple(ngram)\n",
|
||
|
" ngram = ngram[1:]\n",
|
||
|
"\n",
|
||
|
"list(ngrams(\"kotek\", 3))"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 9,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"histories = { }\n",
|
||
|
"for prev_token, token in ngrams(get_words_from_file('opensubtitlesA.pl.txt'), 2):\n",
|
||
|
" histories.setdefault(token, set())\n",
|
||
|
" histories[token].add(prev_token)"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 12,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/plain": [
|
||
|
"321"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 12,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"len(histories['jork'])\n",
|
||
|
"len(histories['zielony'])"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"### Narzędzia $n$-gramowego modelowania języka\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Istnieje kilka narzędzie do modelowania, ze starszych warto wspomnieć\n",
|
||
|
"pakiety [SRILM](http://www.speech.sri.com/projects/srilm/) i [IRSTLM](https://github.com/irstlm-team/irstlm).\n",
|
||
|
"Jest to oprogramowanie bogate w opcje, można wybierać różne opcje wygładzania.\n",
|
||
|
"\n",
|
||
|
"Szczytowym osiągnięciem w zakresie $n$-gramowego modelowania języka\n",
|
||
|
"jest wspomniany już KenLM. Ma on mniej opcji niż SRILM czy ISRLM, jest\n",
|
||
|
"za to precyzyjnie zoptymalizowany zarówno jeśli chodzi jakość, jak i\n",
|
||
|
"szybkość działania. KenLM implementuje nieco zmodyfikowane wygładzanie\n",
|
||
|
"Knesera-Neya połączone z **przycinaniem** słownika n-gramów (wszystkie\n",
|
||
|
"*hapax legomena* dla $n \\geq 3$ są domyślnie usuwane).\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"#### Przykładowe wyniki dla KenLM i korpusu Open Subtitles\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"##### Zmiana perplexity przy zwiększaniu zbioru testowego\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"![img](./05_Wygladzanie/size-perplexity.gif \"Perplexity dla różnych rozmiarów zbioru testowego\")\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"##### Zmiana perplexity przy zwiększaniu zbioru uczącego\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"![img](./05_Wygladzanie/size-perplexity2.gif \"Perplexity dla różnych rozmiarów zbioru uczącego\")\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"##### Zmiana perplexity przy zwiększaniu rządu modelu\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"![img](./05_Wygladzanie/order-perplexity.gif \"Perplexity dla różnych wartości rządu modelu\")\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
|
||
|
}
|