Up
@ -9,7 +9,7 @@ Używać będziemy generatorów.
|
||||
|
||||
*Pytanie* Dlaczego generatory zamiast list?
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
import requests
|
||||
|
||||
url = 'https://wolnelektury.pl/media/book/txt/pan-tadeusz.txt'
|
||||
@ -31,7 +31,7 @@ Powrót pani
|
||||
|
||||
*** Znaki
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from itertools import islice
|
||||
|
||||
def get_characters(t):
|
||||
@ -45,7 +45,7 @@ Powrót pani
|
||||
['K', 's', 'i', 'ę', 'g', 'a', ' ', 'p', 'i', 'e', 'r', 'w', 's', 'z', 'a', '\r', '\n', '\r', '\n', '\r', '\n', '\r', '\n', 'G', 'o', 's', 'p', 'o', 'd', 'a', 'r', 's', 't', 'w', 'o', '\r', '\n', '\r', '\n', 'P', 'o', 'w', 'r', 'ó', 't', ' ', 'p', 'a', 'n', 'i']
|
||||
:end:
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from collections import Counter
|
||||
|
||||
c = Counter(get_characters(pan_tadeusz))
|
||||
@ -65,7 +65,7 @@ Napiszmy pomocniczą funkcję, która zwraca *listę frekwencyjną*.
|
||||
Counter({' ': 63444, 'a': 30979, 'i': 29353, 'e': 25343, 'o': 23050, 'z': 22741, 'n': 15505, 'r': 15328, 's': 15255, 'w': 14625, 'c': 14153, 'y': 13732, 'k': 12362, 'd': 11465, '\r': 10851, '\n': 10851, 't': 10757, 'm': 10269, 'ł': 10059, ',': 9130, 'p': 8031, 'u': 7699, 'l': 6677, 'j': 6586, 'b': 5753, 'ę': 5534, 'ą': 4794, 'g': 4775, 'h': 3915, 'ż': 3334, 'ó': 3097, 'ś': 2524, '.': 2380, 'ć': 1956, ';': 1445, 'P': 1265, 'W': 1258, ':': 1152, '!': 1083, 'S': 1045, 'T': 971, 'I': 795, 'N': 793, 'Z': 785, 'J': 729, '—': 720, 'A': 698, 'K': 683, 'ń': 651, 'M': 585, 'B': 567, 'O': 567, 'C': 556, 'D': 552, '«': 540, '»': 538, 'R': 489, '?': 441, 'ź': 414, 'f': 386, 'G': 358, 'L': 316, 'H': 309, 'Ż': 219, 'U': 184, '…': 157, '*': 150, '(': 76, ')': 76, 'Ś': 71, 'F': 47, 'é': 43, '-': 33, 'Ł': 24, 'E': 23, '/': 19, 'Ó': 13, '8': 10, '9': 8, '2': 6, 'v': 5, 'Ź': 4, '1': 4, '3': 3, 'x': 3, 'V': 3, '7': 2, '4': 2, '5': 2, 'q': 2, 'æ': 2, 'à': 1, 'Ć': 1, '6': 1, '0': 1})
|
||||
:end:
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from collections import Counter
|
||||
from collections import OrderedDict
|
||||
|
||||
@ -88,7 +88,7 @@ OrderedDict([(' ', 63444), ('a', 30979), ('i', 29353), ('e', 25343), ('o', 23050
|
||||
:end:
|
||||
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
import matplotlib.pyplot as plt
|
||||
from collections import OrderedDict
|
||||
|
||||
@ -119,7 +119,7 @@ Co rozumiemy pod pojęciem słowa czy wyrazu, nie jest oczywiste. W praktyce zal
|
||||
Załóżmy, że przez wyraz rozumieć będziemy nieprzerwany ciąg liter bądź cyfr (oraz gwiazdek
|
||||
— to za chwilę ułatwi nam analizę pewnego tekstu…).
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
from itertools import islice
|
||||
import regex as re
|
||||
|
||||
@ -138,7 +138,7 @@ Załóżmy, że przez wyraz rozumieć będziemy nieprzerwany ciąg liter bądź
|
||||
Zobaczmy 20 najczęstszych wyrazów.
|
||||
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
rang_freq_with_labels('pt-words-20', get_words(pan_tadeusz), top=20)
|
||||
#+END_SRC
|
||||
|
||||
@ -147,7 +147,7 @@ Zobaczmy 20 najczęstszych wyrazów.
|
||||
|
||||
Zobaczmy pełny obraz, już bez etykiet.
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
import matplotlib.pyplot as plt
|
||||
from math import log
|
||||
|
||||
@ -172,7 +172,7 @@ Zobaczmy pełny obraz, już bez etykiet.
|
||||
Widać, jak różne skale obejmuje ten wykres. Zastosujemy logarytm,
|
||||
najpierw tylko do współrzędnej $y$.
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
import matplotlib.pyplot as plt
|
||||
from math import log
|
||||
|
||||
@ -222,7 +222,7 @@ logarytmicznej dla **obu** osi, otrzymamy kształt zbliżony do linii prostej.
|
||||
|
||||
Tę własność tekstów nazywamy **prawem Zipfa**.
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
import matplotlib.pyplot as plt
|
||||
from math import log
|
||||
|
||||
@ -249,7 +249,7 @@ Tę własność tekstów nazywamy **prawem Zipfa**.
|
||||
Powiązane z prawem Zipfa prawo językowe opisuje zależność między
|
||||
częstością użycia słowa a jego długością. Generalnie im krótsze słowo, tym częstsze.
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
def freq_vs_length(name, g, top=None):
|
||||
freq = freq_list(g)
|
||||
|
||||
@ -294,7 +294,7 @@ po prostu na jednostkach, nie na ich podciągach.
|
||||
|
||||
Statystyki, które policzyliśmy dla pojedynczych liter czy wyrazów, możemy powtórzyć dla n-gramów.
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
def ngrams(iter, size):
|
||||
ngram = []
|
||||
for item in iter:
|
||||
@ -317,7 +317,7 @@ Zawsze powinniśmy się upewnić, czy jest jasne, czy chodzi o n-gramy znakowe c
|
||||
|
||||
*** 3-gramy znakowe
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
log_rang_log_freq('pt-3-char-ngrams-log-log', ngrams(get_characters(pan_tadeusz), 3))
|
||||
#+END_SRC
|
||||
|
||||
@ -326,7 +326,7 @@ Zawsze powinniśmy się upewnić, czy jest jasne, czy chodzi o n-gramy znakowe c
|
||||
|
||||
*** 2-gramy wyrazowe
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
log_rang_log_freq('pt-2-word-ngrams-log-log', ngrams(get_words(pan_tadeusz), 2))
|
||||
#+END_SRC
|
||||
|
||||
@ -348,7 +348,7 @@ transkrybować manuskrypt, pozostaje sprawą dyskusyjną, natomiast wybór
|
||||
takiego czy innego systemu transkrypcji nie powinien wpływać
|
||||
dramatycznie na analizę statystyczną.
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
import requests
|
||||
|
||||
voynich_url = 'http://www.voynich.net/reeds/gillogly/voynich.now'
|
||||
@ -370,28 +370,28 @@ dramatycznie na analizę statystyczną.
|
||||
9 OR 9FAM ZO8 QOAR9 Q*R 8ARAM 29 [O82*]OM OPCC9 OP
|
||||
:end:
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
rang_freq_with_labels('voy-chars', get_characters(voynich))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:02_Jezyki/voy-chars.png]]
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
log_rang_log_freq('voy-log-log', get_words(voynich))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:02_Jezyki/voy-log-log.png]]
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
rang_freq_with_labels('voy-words-20', get_words(voynich), top=20)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:02_Jezyki/voy-words-20.png]]
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
log_rang_log_freq('voy-words-log-log', get_words(voynich))
|
||||
#+END_SRC
|
||||
|
||||
@ -406,7 +406,7 @@ Podstawowe litery są tylko cztery, reprezentują one nukleotydy, z których zbu
|
||||
a, g, c, t.
|
||||
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
import requests
|
||||
|
||||
dna_url = 'https://raw.githubusercontent.com/egreen18/NanO_GEM/master/rawGenome.txt'
|
||||
@ -423,7 +423,7 @@ a, g, c, t.
|
||||
TATAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTA
|
||||
:end:
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
rang_freq_with_labels('dna-chars', get_characters(dna))
|
||||
#+END_SRC
|
||||
|
||||
@ -436,7 +436,7 @@ Nukleotydy rzeczywiście są jak litery, same w sobie nie niosą
|
||||
znaczenia. Dopiero ciągi trzech nukleotydów, /tryplety/, kodują jeden
|
||||
z dwudziestu aminokwasów.
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
genetic_code = {
|
||||
'ATA':'I', 'ATC':'I', 'ATT':'I', 'ATG':'M',
|
||||
'ACA':'T', 'ACC':'T', 'ACG':'T', 'ACT':'T',
|
||||
@ -472,7 +472,7 @@ Z aminokwasów zakodowanych przez tryplet budowane są białka.
|
||||
Maszyneria budująca białka czyta sekwencję aż do napotkania
|
||||
trypletu STOP (_ powyżej). Taka sekwencja to /gen/.
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
#+BEGIN_SRC python :session mysession :results file
|
||||
def get_genes(triplets):
|
||||
gene = []
|
||||
for ammino in triplets:
|
||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 14 KiB |
657
wyk/03_Entropia.ipynb
Normal file
@ -11,12 +11,12 @@ W termodynamice entropia jest miarą nieuporządkowania układów
|
||||
fizycznych, na przykład pojemników z gazem. Przykładowo, wyobraźmy
|
||||
sobie dwa pojemniki z gazem, w którym panuje różne temperatury.
|
||||
|
||||
[[./03_Jezyki/gas-low-entropy.drawio.png]]
|
||||
[[./03_Entropia/gas-low-entropy.drawio.png]]
|
||||
|
||||
Jeśli usuniemy przegrodę między pojemnikami, temperatura się wyrówna,
|
||||
a uporządkowanie się zmniejszy.
|
||||
|
||||
[[./03_Jezyki/gas-high-entropy.drawio.png]]
|
||||
[[./03_Entropia/gas-high-entropy.drawio.png]]
|
||||
|
||||
Innymi słowy, zwiększy się stopień nieuporządkowania układu, czyli właśnie entropia.
|
||||
|
||||
@ -46,7 +46,7 @@ losowania do odbiorcy $O$ używając zer i jedynek (bitów).
|
||||
Teorioinformacyjną entropię można zdefiniować jako średnią liczbę
|
||||
bitów wymaganych do przesłania komunikatu.
|
||||
|
||||
[[./03_Jezyki/communication.drawio.png]]
|
||||
[[./03_Entropia/communication.drawio.png]]
|
||||
|
||||
*** Obliczanie entropii — proste przykłady
|
||||
|
||||
@ -187,6 +187,25 @@ Załóżmy, że chcemy zmierzyć entropię języka polskiego na przykładzie
|
||||
„Pana Tadeusza” — na poziomie znaków. W pierwszym przybliżeniu można
|
||||
by policzyć liczbę wszystkich znaków…
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
import requests
|
||||
from itertools import islice
|
||||
|
||||
url = 'https://wolnelektury.pl/media/book/txt/pan-tadeusz.txt'
|
||||
pan_tadeusz = requests.get(url).content.decode('utf-8')
|
||||
|
||||
def get_characters(t):
|
||||
yield from t
|
||||
|
||||
list(islice(get_characters(pan_tadeusz), 100, 150))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
['K', 's', 'i', 'ę', 'g', 'a', ' ', 'p', 'i', 'e', 'r', 'w', 's', 'z', 'a', '\r', '\n', '\r', '\n', '\r', '\n', '\r', '\n', 'G', 'o', 's', 'p', 'o', 'd', 'a', 'r', 's', 't', 'w', 'o', '\r', '\n', '\r', '\n', 'P', 'o', 'w', 'r', 'ó', 't', ' ', 'p', 'a', 'n', 'i']
|
||||
:end:
|
||||
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
chars_in_pan_tadeusz = len(set(get_characters(pan_tadeusz)))
|
||||
chars_in_pan_tadeusz
|
||||
@ -241,6 +260,30 @@ Policzmy entropię przy takim założeniu:
|
||||
|
||||
*** Ile wynosi entropia rękopisu Wojnicza?
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
import requests
|
||||
import re
|
||||
|
||||
voynich_url = 'http://www.voynich.net/reeds/gillogly/voynich.now'
|
||||
voynich = requests.get(voynich_url).content.decode('utf-8')
|
||||
|
||||
voynich = re.sub(r'\{[^\}]+\}|^<[^>]+>|[-# ]+', '', voynich, flags=re.MULTILINE)
|
||||
|
||||
voynich = voynich.replace('\n\n', '#')
|
||||
voynich = voynich.replace('\n', ' ')
|
||||
voynich = voynich.replace('#', '\n')
|
||||
|
||||
voynich = voynich.replace('.', ' ')
|
||||
|
||||
voynich[100:150]
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
9 OR 9FAM ZO8 QOAR9 Q*R 8ARAM 29 [O82*]OM OPCC9 OP
|
||||
:end:
|
||||
|
||||
|
||||
#+BEGIN_SRC python :session mysession :exports both :results raw drawer
|
||||
unigram_entropy(get_characters(voynich))
|
||||
#+END_SRC
|
||||
|
@ -50,15 +50,15 @@ Model języka:
|
||||
czy transkrypcję w systemach rozpoznawania mowy (ASR)
|
||||
(zanim zaczęto używać do tego sieci neuronowych, gdzie nie
|
||||
ma już wyraźnego rozróżnienia między modelem tłumaczenia
|
||||
czy modelem akustycznym a modelem języka
|
||||
czy modelem akustycznym a modelem języka),
|
||||
- pomaga znaleźć „podejrzane” miejsca w tekście
|
||||
(korekta pisowni/gramatyki)
|
||||
(korekta pisowni/gramatyki),
|
||||
- może być stosowany jako klasyfikator (potrzeba wtedy więcej niż jednego modelu,
|
||||
np. model języka spamów kontra model języka niespamów)
|
||||
- może być stosowany w kompresji danych
|
||||
np. model języka spamów kontra model języka niespamów),
|
||||
- może być stosowany w kompresji danych,
|
||||
- bardzo dobry model języka *musi* mieć *w środku* bardzo dobrą *wiedzę*
|
||||
o języku i o świecie, można wziąć *„wnętrzności”* modelu, nie dbając o prawdopodobieństwa
|
||||
i użyć modelu w zupełnie innym celu
|
||||
i użyć modelu w zupełnie innym celu.
|
||||
|
||||
** N-gramowy model języka
|
||||
|
||||
@ -120,13 +120,21 @@ inny dla trigramowego. Jedne modele będą lepsze, inne — gorsze. Jak
|
||||
obiektywnie odróżnić dobry model od złego? Innymi słowy, jak ewaluować
|
||||
modele języka?
|
||||
|
||||
*** Ewaluacja zewnętrzna i wewnętrzna
|
||||
|
||||
W ewaluacji zewnętrznej (ang. /extrinsic/) ewaluację modelu języka sprowadzamy
|
||||
do ewaluacji większego systemu, którego częścią jest model języka, na przykład
|
||||
systemu tłumaczenia maszynowego albo systemu ASR.
|
||||
|
||||
Ewaluacja wewnętrzna (ang. /intrinsic/) polega na ewaluacji modelu języka jako takiego.
|
||||
|
||||
*** Podział zbioru
|
||||
|
||||
Po pierwsze, jak zazwyczaj bywa w uczeniu maszynowym, powinniśmy
|
||||
podzielić nasz zbiór danych. W modelowaniu języka zbiorem danych jest
|
||||
zbiór tekstów w danym języku, czyli korpus języka.
|
||||
Powinniśmy podzielić nasz korpus na część uczącą (/training set/) $C = \{w_1\ldots w_N\}$ i testową
|
||||
(/test set/) $C' = \{w_1'\ldots w_N'\}$.
|
||||
(/test set/) $C' = \{w_1'\ldots w_{N'}'\}$.
|
||||
|
||||
Warto też wydzielić osobny „deweloperski” zbiór testowy (/dev set/) —
|
||||
do testowania na bieżąco, optymalizacji hiperparametrów itd. Zbiory
|
||||
@ -212,7 +220,7 @@ tym lepiej. Zatem im wyższe $P_M(C')$, tym lepiej.
|
||||
Zazwyczaj będziemy rozbijali $P_M(C')$ na prawdopodobieństwa
|
||||
przypisane do poszczególnych słów:
|
||||
|
||||
$$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}).$$
|
||||
$$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}).$$
|
||||
|
||||
*** Entropia krzyżowa
|
||||
|
||||
@ -230,7 +238,7 @@ realnie wystąpić, na przykład: z prawdopodobieństwem zbliżonym do 1 po wyra
|
||||
/Hong/ wystąpi słowo /Kong/, a po wyrazie /przede/ — wyraz /wszystkim/.
|
||||
|
||||
Model języka może pomóc również w mniej skrajnym przypadkach, np.
|
||||
jeśli na danej pozycji w tekście redukuje cały słownik do dwóch
|
||||
jeżeli na danej pozycji w tekście model redukuje cały słownik do dwóch
|
||||
wyrazów z prawdopodobieństwem 1/2, wówczas nadawca może zakodować tę
|
||||
pozycję za pomocą jednego bitu.
|
||||
|
||||
@ -248,7 +256,7 @@ tę wartość, tzn. podzielić przez długość tekstu:
|
||||
$$H(M) = -\frac{\sum_{i=1}^{N'} log P_M(w'_i|w'_1\ldots w'_{i-1})}{N'}.$$
|
||||
|
||||
Tę wartość nazywamy *entropią krzyżową* modelu $M$. Entropia krzyżowa
|
||||
mierzy naszą niewiedzę przy posiadaniu modelu $M$. Im niższa wartość
|
||||
mierzy naszą niewiedzę przy założeniu, że dysponujemy modelem $M$. Im niższa wartość
|
||||
entropii krzyżowej, tym lepiej, im bowiem mniejsza nasza niewiedza,
|
||||
tym lepiej.
|
||||
|
||||
@ -265,13 +273,13 @@ wspomnieliśmy, im wyższe prawdopodobieństwo (wiarygodność) przypisane
|
||||
testowej części korpusu, tym lepiej. Innymi słowy, jako metrykę ewaluacji
|
||||
używać będziemy prawdopodobieństwa:
|
||||
|
||||
$$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}),$$
|
||||
$$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}),$$
|
||||
|
||||
z tym, że znowu warto znormalizować to prawdopodobieństwo względem rozmiaru korpusu.
|
||||
Ze względu na to, że prawdopodobieństwa przemnażamy zamiast średniej arytmetycznej
|
||||
Ze względu na to, że prawdopodobieństwa przemnażamy, zamiast średniej arytmetycznej
|
||||
lepiej użyć *średniej geometrycznej*:
|
||||
|
||||
$$\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})}.$$
|
||||
$$\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})}.$$
|
||||
|
||||
**** Interpretacja wiarygodności
|
||||
|
||||
@ -283,9 +291,9 @@ to *średnia geometryczna prawdopodobieństw przypisanych przez model języka do
|
||||
**** Związek między wiarygodnością a entropią krzyżową
|
||||
|
||||
Istnieje bardzo prosty związek między entropią krzyżową a wiarygodnością.
|
||||
Otóż entropia krzyżowa to po prostu logarytm wiarygodności:
|
||||
Otóż entropia krzyżowa to po prostu logarytm wiarygodności (z minusem):
|
||||
|
||||
$$\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'}.$$
|
||||
-$$\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'}.$$
|
||||
|
||||
**** „log-proby”
|
||||
|
||||
@ -302,7 +310,7 @@ zamiast wprost operować na prawdopodobieństwach:
|
||||
Tak naprawdę w literaturze przedmiotu na ogół używa się jeszcze innej metryki ewaluacji —
|
||||
*perplexity*. Perplexity jest definiowane jako:
|
||||
|
||||
$$PP(M) = 2^{H(M)}.$$
|
||||
$$\operatorname{PP}(M) = 2^{H(M)}.$$
|
||||
|
||||
Intuicyjnie można sobie wyobrazić, że perplexity to liczba możliwości
|
||||
prognozowanych przez model z równym prawdopodobieństwem. Na przykład,
|
||||
@ -313,7 +321,7 @@ perplexity — 32.
|
||||
|
||||
Inaczej: perplexity to po prostu odwrotność wiarygodności:
|
||||
|
||||
$$\OperatorName{PP}(M) = \sqrt[N']{P_M(w_1'\dots w_N').}
|
||||
$$\operatorname{PP}(M) = \sqrt[N']{P_M(w_1'\dots w_N')}.$$
|
||||
|
||||
Perplexity zależy oczywiście od języka i modelu, ale typowe wartości
|
||||
zazwyczaj zawierają się w przedziale 20-400.
|
||||
@ -330,10 +338,25 @@ dwa modele, jeden 3-gramowy, drugi 4-gramowy.
|
||||
Z powodu, który za chwilę stanie się jasny, teksty w zbiorze uczącym musimy sobie „poskładać” z kilku „kawałków”.
|
||||
|
||||
#+BEGIN_SRC
|
||||
xzcat in.tsv.xz | paste expected.tsv - | perl -ne 'chomp;s/\\n/ /g;@f=split/\t/;print "$f[7] $f[0] $f[8]"' | lmplz -o 3 > model3.arpa
|
||||
xzcat in.tsv.xz | paste expected.tsv - | perl -ne 'chomp;s/\\n/ /g;@f=split/\t/;print "$f[7] $f[0] $f[8]"' | lmplz -o 4 > model3.arpa
|
||||
$ cd train
|
||||
$ 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
|
||||
$ 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
|
||||
$ cd ../dev-0
|
||||
$ 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
|
||||
Perplexity including OOVs: 976.9905056314793
|
||||
Perplexity excluding OOVs: 616.5864921901557
|
||||
OOVs: 125276
|
||||
Tokens: 3452929
|
||||
$ 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
|
||||
Perplexity including OOVs: 888.698932611321
|
||||
Perplexity excluding OOVs: 559.1231510292068
|
||||
OOVs: 125276
|
||||
Tokens: 3452929
|
||||
#+END_SRC
|
||||
|
||||
Jak widać model 4-gramowy jest lepszy (ma niższe perplexity) niż model 3-gramowy, przynajmniej
|
||||
jeśli wierzyć raportowi programu KenLM.
|
||||
|
||||
*** Entropia krzyżowa, wiarygodność i perplexity — podsumowanie
|
||||
|
||||
Trzy omawiane metryki ewaluacji modeli języka (entropia krzyżowa,
|
||||
@ -342,9 +365,9 @@ rzeczy to po prostu jedna miara.
|
||||
|
||||
|Metryka | Kierunek |Najlepsza wartość | Najgorsza wartość |
|
||||
|------------------+----------------------+------------------+-------------------|
|
||||
|entropia krzyżowa | im mniej, tym lepiej | 0 | $\inf$ |
|
||||
|entropia krzyżowa | im mniej, tym lepiej | 0 | $\infty$ |
|
||||
|wiarygodność | im więcej, tym lepiej| 1 | 0 |
|
||||
|perplexity | im mniej, tym lepiej | 1 | $\inf$ |
|
||||
|perplexity | im mniej, tym lepiej | 1 | $\infty$ |
|
||||
|
||||
**** Uwaga na zerowe prawdopodobieństwa
|
||||
|
||||
@ -403,6 +426,50 @@ tekstu oczekuje się podania rozkładu prawdopodobieństwa dla brakującego sło
|
||||
|
||||
Mianowicie, w każdym wierszu wejściu (plik ~in.tsv.xz~) w 7. i 8. polu
|
||||
podany jest, odpowiednio, lewy i prawy kontekst słowa do odgadnięcia.
|
||||
(W pozostałych polach znajdują się metadane, o których już wspomnieliśmy,
|
||||
na razie nie będziemy ich wykorzystywać).
|
||||
W pliku z oczekiwanym wyjściem (~expected.tsv~), w odpowiadającym
|
||||
wierszu, podawane jest brakujące słowo. Oczywiście w ostatecznym
|
||||
teście ~test-A~ plik ~expected.tsv~ jest niedostępny, ukryty przed uczestnikami konkursu
|
||||
teście ~test-A~ plik ~expected.tsv~ jest niedostępny, ukryty przed uczestnikami konkursu.
|
||||
|
||||
**** Zapis rozkładu prawdopodobieństwa
|
||||
|
||||
Dla każdego wiersza wejścia podajemy rozkład prawdopodobieństwa dla
|
||||
słowa w luce w formacie:
|
||||
|
||||
#+BEGIN_SRC
|
||||
wyraz1:prob1 wyraz2:prob2 ... wyrazN:probN :prob0
|
||||
#+END_SRC
|
||||
|
||||
gdzie wyraz1, …, wyrazN to konkretne wyrazy, prob1, …, probN ich prawdopodobieństwa.
|
||||
Można podać dowolną liczbę wyrazów.
|
||||
Z kolei prob0 to „resztowe” prawdopodobieństwo przypisane do wszystkich pozostałych wyrazów,
|
||||
prawdopodobieństwo to pozwala uniknąć problemów związanych ze słowami OOV, trzeba jeszcze tylko dokonać
|
||||
modyfikacji metryki
|
||||
|
||||
**** Metryka LikelihoodHashed
|
||||
|
||||
Metryka LikelihoodHashed jest wariantem metryki Likelihood
|
||||
(wiarygodności) opracowanym z myślą o wyzwaniach czy konkursach
|
||||
modelowania języka. W tej metryce każde słowo wpada pseudolosowo do
|
||||
jednego z $2^{10}=1024$ „kubełków”. Numer kubełka jest wyznaczony na
|
||||
podstawie funkcji haszującej MurmurHash.
|
||||
|
||||
Prawdopodobieństwa zwrócone przez ewaluowany model są sumowane w
|
||||
każdym kubełku, następnie ewaluator zagląda do pliku `expected.tsv` i
|
||||
uwzględnia prawdopodobieństwo z kubełka, do którego „wpada” oczekiwane
|
||||
słowo. Oczywiście czasami więcej niż jedno słowo może wpaść do
|
||||
kubełka, model mógł też „wrzucić” do kubełka tak naprawdę inne słowo
|
||||
niż oczekiwane (przypadkiem oba słowa wpadają do jednego kubełka).
|
||||
Tak więc LikelihoodHashed będzie nieco zawyżone w stosunku do Likelihood.
|
||||
|
||||
Dlaczego więc taka komplikacja? Otóż LikelihoodHashed nie zakłada
|
||||
żadnego słownika, znika problem słów OOV — prawdopodobieństwa resztowe prob0
|
||||
są rozkładane równomiernie między wszystkie 1024 kubełki.
|
||||
|
||||
**** Alternatywne metryki
|
||||
|
||||
LikelihoodHashed została zaimplementowana w narzędziu ewaluacyjnym
|
||||
[[https://gitlab.com/filipg/geval|GEval]]. Są tam również dostępne
|
||||
analogiczne warianty entropii krzyżowej (log loss) i perplexity
|
||||
(LogLossHashed i PerplexityHashed).
|
||||
|
1
wyk/04_Ngramowy_model/lm-communication.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2022-03-18T21:08:49.892Z" agent="5.0 (X11)" etag="RzIxxXjLYk9oBS8CnMsQ" version="16.2.2" type="device"><diagram id="E-zPRpFz5prVeiZgI5WF" name="Page-1">7VjbUtswEP0aP4bxJU7IIyQUhkJhYIbCEyPbii0iW0GWE4evr2TJVzmBcm1n4CFoj+S1tGePdhPDmcb5MQXL6JwEEBu2GeSGMzNsezK0+KcANhJwbVcCIUWBhKwauEZPUIGmQjMUwLS1kBGCGVq2QZ8kCfRZCwOUknV72Zzg9luXIIQacO0DrKO/UcAiie7b4xo/gSiMyjdbo4mciUG5WJ0kjUBA1g3IOTKcKSWEyVGcTyEWsSvjIp/7sWW22hiFCXvJA3R1NohuBmByf3NxZV/f0+Or04Gj9sY25YFhwM+vTEJZREKSAHxUo4eUZEkAhVeTW/WaM0KWHLQ4+AAZ2ygyQcYIhyIWYzULc8RuxeN7rrLulDMxnuVNY9MwLiFFMWSQlljC6Oa2adw1jcKR61amcDWuZrvO5iRhasf2kNsyMCIaW+OtoJRk1FerflL7Mb8zT7xgha5wkmWrU3tQ5i2gIWQ7yLCqrOBqgoTvjm74cxRiwNCqvQ+g8jqs1tXU84Fivz8Tdm1yBXCm3vQLBGDtAy1DeCIvxTCL8YHPCA/g4QpShrhozoAH8SVJEUMk4Us8whiJGwsOMArFBBOp0swJkjGMEjitZGxWHPSEXLiDeQPSo6Zm7aGS36Zjr2s1OwqKGkIemW+Pcy/J7rfiPl5xwxcqbviVihtqirsIPETo/y451/k6yfUG2tUCvTXAcwzzA9E2FEkbqOHMxyBNkd+OX1uVWwPXSWg9bI2wuD1hKbEXJ6V6wyVBfCf1RbjfYWXcCbcUlXqq2Ud0HLn2M46k6jRHBXXVsV/P5khjcwESYExdY1/gCxJnCVoA/wH13rSFXtpEAqUQn1MHaY90YhQE8iKGKXoCXuFPkL4UhyyO7R4a7qw3DXamZFdUVSOrXtLqFfvENjD3rLKlfm2GlEvIfJ7CD+Fs/98petbuotdf4Paczl+r4pmtgre13r2+nI31crarh3v2xvmc+jbWhHoME0iBqF/80JvYI1jX6NvrWnmX83S+5F/PVH0rimY7p1KZOTI/3qHwWWb7ZrRGeuEbfWavqff0hj3CTPVerbiPHjNSTgxkYA74Anu4zOtJPgrF//PSDd+V9CTxrWXVzzwh6XWEGLxegiLZ1xR0iPMkO2deBQB/ERacXcheReEBoIsL7gaxQnB7ptsG7QK1qh31XLMa0du/QXRZdXRWJz2sdsviu7Gq943frP41q8PJp7HKzfpXHllR65/KnKM/</diagram></mxfile>
|
BIN
wyk/04_Ngramowy_model/lm-communication.drawio.png
Normal file
After Width: | Height: | Size: 16 KiB |