Wykłady
496
wyk/03_Ngramy.ipynb
Normal file
225
wyk/03_Ngramy.org
Normal file
@ -0,0 +1,225 @@
|
||||
* N-gramy
|
||||
|
||||
W modelowaniu języka często rozpatruje się n-gramy, czyli podciągi o
|
||||
rozmiarze $n$.
|
||||
|
||||
Na przykład /digramy/ (/bigramy/) to zbitki dwóch jednostek, np. liter albo wyrazów.
|
||||
|
||||
|$n$| $n$-gram| nazwa |
|
||||
|---+---------+---------------|
|
||||
| 1 | 1-gram | unigram |
|
||||
| 2 | 2-gram | digram/bigram |
|
||||
| 3 | 3-gram | trigram |
|
||||
| 4 | 4-gram | tetragram |
|
||||
| 5 | 5-gram | pentagram |
|
||||
|
||||
|
||||
*Pytanie:* Jak nazywa się 6-gram?
|
||||
|
||||
Jak widać, dla symetrii mówimy czasami o unigramach, jeśli operujemy
|
||||
po prostu na jednostkach, nie na ich podciągach.
|
||||
|
||||
*** N-gramy z Pana Tadeusza
|
||||
|
||||
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
|
||||
def ngrams(iter, size):
|
||||
ngram = []
|
||||
for item in iter:
|
||||
ngram.append(item)
|
||||
if len(ngram) == size:
|
||||
yield tuple(ngram)
|
||||
ngram = ngram[1:]
|
||||
|
||||
list(ngrams("kotek", 3))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
[('k', 'o', 't'), ('o', 't', 'e'), ('t', 'e', 'k')]
|
||||
:end:
|
||||
|
||||
Zauważmy, że policzyliśmy wszystkie n-gramy, również częściowo się pokrywające.
|
||||
|
||||
Zawsze powinniśmy się upewnić, czy jest jasne, czy chodzi o n-gramy znakowe czy wyrazowe
|
||||
|
||||
*** 3-gramy znakowe
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
log_rang_log_freq('pt-3-char-ngrams-log-log', ngrams(get_characters(pan_tadeusz), 3))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:03_Ngramy/pt-3-char-ngrams-log-log.png]]
|
||||
|
||||
*** 2-gramy wyrazowe
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
log_rang_log_freq('pt-2-word-ngrams-log-log', ngrams(get_words(pan_tadeusz), 2))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:03_Ngramy/pt-2-word-ngrams-log-log.png]]
|
||||
|
||||
** Tajemniczy język Manuskryptu Wojnicza
|
||||
|
||||
[[https://pl.wikipedia.org/wiki/Manuskrypt_Wojnicza][Manuskrypt Wojnicza]] to powstały w XV w. manuskrypt spisany w
|
||||
tajemniczym alfabecie, do dzisiaj nieodszyfrowanym. Rękopis stanowi
|
||||
jedną z największych zagadek historii (i lingwistyki).
|
||||
|
||||
[[./02_Jezyki/voynich135.jpg][Źródło: https://commons.wikimedia.org/wiki/File:Voynich_Manuscript_(135).jpg]]
|
||||
|
||||
Sami zbadajmy statystyczne własności tekstu manuskryptu. Użyjmy
|
||||
transkrypcji Vnow, gdzie poszczególne znaki tajemniczego alfabetu
|
||||
zamienione na litery alfabetu łacińskiego, cyfry i gwiazdkę. Jak
|
||||
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
|
||||
import requests
|
||||
|
||||
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 ipython :session mysession :results file
|
||||
rang_freq_with_labels('voy-chars', get_characters(voynich))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:03_Ngramy/voy-chars.png]]
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
log_rang_log_freq('voy-log-log', get_words(voynich))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:03_Ngramy/voy-log-log.png]]
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
rang_freq_with_labels('voy-words-20', get_words(voynich), top=20)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:03_Ngramy/voy-words-20.png]]
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
log_rang_log_freq('voy-words-log-log', get_words(voynich))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:03_Ngramy/voy-words-log-log.png]]
|
||||
|
||||
** Język DNA
|
||||
|
||||
Kod genetyczny przejawia własności zaskakująco podobne do języków naturalnych.
|
||||
Przede wszystkim ma charakter dyskretny, genotyp to ciąg symboli ze skończonego alfabetu.
|
||||
Podstawowe litery są tylko cztery, reprezentują one nukleotydy, z których zbudowana jest nić DNA:
|
||||
a, g, c, t.
|
||||
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
import requests
|
||||
|
||||
dna_url = 'https://raw.githubusercontent.com/egreen18/NanO_GEM/master/rawGenome.txt'
|
||||
dna = requests.get(dna_url).content.decode('utf-8')
|
||||
|
||||
dna = ''.join(dna.split('\n')[1:])
|
||||
dna = dna.replace('N', 'A')
|
||||
|
||||
dna[0:100]
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
TATAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTAACCCTA
|
||||
:end:
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
rang_freq_with_labels('dna-chars', get_characters(dna))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:03_Ngramy/dna-chars.png]]
|
||||
|
||||
*** Tryplety — znaczące cząstki genotypu
|
||||
|
||||
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
|
||||
genetic_code = {
|
||||
'ATA':'I', 'ATC':'I', 'ATT':'I', 'ATG':'M',
|
||||
'ACA':'T', 'ACC':'T', 'ACG':'T', 'ACT':'T',
|
||||
'AAC':'N', 'AAT':'N', 'AAA':'K', 'AAG':'K',
|
||||
'AGC':'S', 'AGT':'S', 'AGA':'R', 'AGG':'R',
|
||||
'CTA':'L', 'CTC':'L', 'CTG':'L', 'CTT':'L',
|
||||
'CCA':'P', 'CCC':'P', 'CCG':'P', 'CCT':'P',
|
||||
'CAC':'H', 'CAT':'H', 'CAA':'Q', 'CAG':'Q',
|
||||
'CGA':'R', 'CGC':'R', 'CGG':'R', 'CGT':'R',
|
||||
'GTA':'V', 'GTC':'V', 'GTG':'V', 'GTT':'V',
|
||||
'GCA':'A', 'GCC':'A', 'GCG':'A', 'GCT':'A',
|
||||
'GAC':'D', 'GAT':'D', 'GAA':'E', 'GAG':'E',
|
||||
'GGA':'G', 'GGC':'G', 'GGG':'G', 'GGT':'G',
|
||||
'TCA':'S', 'TCC':'S', 'TCG':'S', 'TCT':'S',
|
||||
'TTC':'F', 'TTT':'F', 'TTA':'L', 'TTG':'L',
|
||||
'TAC':'Y', 'TAT':'Y', 'TAA':'_', 'TAG':'_',
|
||||
'TGC':'C', 'TGT':'C', 'TGA':'_', 'TGG':'W',
|
||||
}
|
||||
|
||||
def get_triplets(t):
|
||||
for triplet in re.finditer(r'.{3}', t):
|
||||
yield genetic_code[triplet.group(0)]
|
||||
|
||||
rang_freq_with_labels('dna-aminos', get_triplets(dna))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:03_Ngramy/dna-aminos.png]]
|
||||
|
||||
*** „Zdania” w języku DNA
|
||||
|
||||
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
|
||||
def get_genes(triplets):
|
||||
gene = []
|
||||
for ammino in triplets:
|
||||
if ammino == '_':
|
||||
yield gene
|
||||
gene = []
|
||||
else:
|
||||
gene.append(ammino)
|
||||
|
||||
plt.figure().clear()
|
||||
plt.hist([len(g) for g in get_genes(get_triplets(dna))], bins=100)
|
||||
|
||||
fname = '03_Ngramy/dna_length.png'
|
||||
|
||||
plt.savefig(fname)
|
||||
|
||||
fname
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:03_Ngramy/dna_length.png]]
|
BIN
wyk/03_Ngramy/dna-aminos.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
wyk/03_Ngramy/dna-chars.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
wyk/03_Ngramy/dna_length.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
wyk/03_Ngramy/pt-2-word-ngrams-log-log.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
wyk/03_Ngramy/pt-3-char-ngrams-log-log.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
wyk/03_Ngramy/voy-chars.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
wyk/03_Ngramy/voy-log-log.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
wyk/03_Ngramy/voy-words-20.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
wyk/03_Ngramy/voy-words-log-log.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
wyk/03_Ngramy/voynich135.jpg
Normal file
After Width: | Height: | Size: 3.3 MiB |
19
wyk/04_Entropia.ipynb
Normal file
347
wyk/04_Entropia.org
Normal file
@ -0,0 +1,347 @@
|
||||
* Entropia
|
||||
|
||||
*Entropia* ($E$) to miara nieuporządkowania, niepewności, niewiedzy. Im
|
||||
większa entropia, tym mniej wiemy. Pojęcie to pierwotnie wywodzi się z
|
||||
termodynamiki, później znaleziono wiele zaskakujących analogii i zastosowań w
|
||||
innych dyscyplinach nauki.
|
||||
|
||||
*** Entropia w fizyce
|
||||
|
||||
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.
|
||||
|
||||
[[./04_Entropia/gas-low-entropy.drawio.png]]
|
||||
|
||||
Jeśli usuniemy przegrodę między pojemnikami, temperatura się wyrówna,
|
||||
a uporządkowanie się zmniejszy.
|
||||
|
||||
[[./04_Entropia/gas-high-entropy.drawio.png]]
|
||||
|
||||
Innymi słowy, zwiększy się stopień nieuporządkowania układu, czyli właśnie entropia.
|
||||
|
||||
*** II prawo termodynamiki
|
||||
|
||||
Jedno z najbardziej fundamentalnych praw fizyki, II prawo
|
||||
termodynamiki głosi, że w układzie zamkniętym entropia nie spada.
|
||||
|
||||
**Pytanie**: Czy to, że napisałem te materiały do wykładu i
|
||||
/uporządkowałem/ wiedzę odnośnie do statystycznych własności języka, nie
|
||||
jest sprzeczne z II prawem termodynamiki?
|
||||
|
||||
Konsekwencją II prawa termodynamiki jest śmierć cieplna Wszechświata
|
||||
(zob. [wizualizacja przyszłości Wszechświata](https://www.youtube.com/watch?v=uD4izuDMUQA)).
|
||||
|
||||
*** Entropia w teorii informacji
|
||||
|
||||
Pojęcie entropii zostało „odkryte” na nowo przez Claude'a Shannona,
|
||||
gdy wypracował ogólną teorię informacji.
|
||||
|
||||
Teoria informacji zajmuje się między innymi zagadnieniem optymalnego kodowania komunikatów.
|
||||
|
||||
Wyobraźmy sobie pewne źródło (generator) losowych komunikatów z
|
||||
zamkniętego zbioru symboli ($\Sigma$; nieprzypadkowo używamy oznaczeń
|
||||
z poprzedniego wykładu). Nadawca $N$ chce przesłać komunikat o wyniku
|
||||
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.
|
||||
|
||||
[[./04_Entropia/communication.drawio.png]]
|
||||
|
||||
*** Obliczanie entropii — proste przykłady
|
||||
|
||||
Załóżmy, że nadawca chce przekazać odbiorcy informację o wyniku rzutu monetą.
|
||||
Entropia wynosi wówczas rzecz jasna 1 — na jedno losowanie wystarczy jeden bit
|
||||
(informację o tym, że wypadł orzeł, możemy zakodować na przykład za pomocą zera,
|
||||
zaś to, że wypadła reszka — za pomocą jedynki).
|
||||
|
||||
Rozpatrzmy przypadek, gdy nadawca rzuca ośmiościenną kością. Aby przekazać
|
||||
wynik, potrzebuje wówczas 3 bity (a więc entropia ośmiościennej kości
|
||||
wynosi 3 bity). Przykładowe kodowanie może mieć następującą postać:
|
||||
|
||||
| Wynik | Kodowanie |
|
||||
|-------+-----------|
|
||||
| 1 | 001 |
|
||||
| 2 | 010 |
|
||||
| 3 | 011 |
|
||||
| 4 | 100 |
|
||||
| 5 | 101 |
|
||||
| 6 | 110 |
|
||||
| 7 | 111 |
|
||||
| 8 | 000 |
|
||||
|
||||
*** Obliczenie entropii — trudniejszy przykład
|
||||
|
||||
Załóżmy, że $\Sigma = \{A, B, C, D\}$, natomiast poszczególne komunikaty
|
||||
są losowane zgodnie z następującym rozkładem prawdopodobieństwa:
|
||||
$P(A)=1/2$, $P(B)=1/4$, $P(C)=1/8$, $P(D)=1/8$. Ile wynosi entropia w
|
||||
takim przypadku? Można by sądzić, że 2, skoro wystarczą 2 bity do
|
||||
przekazania wyniku losowania przy zastosowaniu następującego kodowania:
|
||||
|
||||
| Wynik | Kodowanie |
|
||||
|-------+-----------|
|
||||
| A | 00 |
|
||||
| B | 01 |
|
||||
| C | 10 |
|
||||
| D | 11 |
|
||||
|
||||
Problem w tym, że w rzeczywistości nie jest to /optymalne/ kodowanie.
|
||||
Możemy sprytnie zmniejszyć średnią liczbę bitów wymaganych do
|
||||
przekazania losowego wyniku przypisując częstszym wynikom krótsze
|
||||
kody, rzadszym zaś — dłuższe. Oto takie optymalne kodowanie:
|
||||
|
||||
| Wynik | Kodowanie |
|
||||
|-------+-----------|
|
||||
| A | 0 |
|
||||
| B | 10 |
|
||||
| C | 110 |
|
||||
| D | 111 |
|
||||
|
||||
|
||||
Używając takiego kodowanie średnio potrzebujemy:
|
||||
|
||||
$$\frac{1}{2}1 + \frac{1}{4}2 + \frac{1}{8}3 + \frac{1}{8}3 = 1,75$$
|
||||
|
||||
bita. Innymi słowy, entropia takiego źródła wynosi 1,75 bita.
|
||||
|
||||
*** Kodowanie musi być jednoznaczne!
|
||||
|
||||
Można by sądzić, że da się stworzyć jeszcze krótsze kodowanie dla omawianego rozkładu nierównomiernego:
|
||||
|
||||
| Wynik | Kodowanie |
|
||||
|-------+-----------|
|
||||
| A | 0 |
|
||||
| B | 1 |
|
||||
| C | 01 |
|
||||
| D | 11 |
|
||||
|
||||
Niestety, nie jest to właściwe rozwiązanie — kodowanie musi być
|
||||
jednoznaczne nie tylko dla pojedynczego komunikatu, lecz dla całej sekwencji.
|
||||
Na przykład ciąg 0111 nie jest jednoznaczny przy tym kodowaniu (ABBB czy CD?).
|
||||
Podane wcześniej kodowanie spełnia warunek jednoznaczności, ciąg 0111 można odkodować tylko
|
||||
jako AD.
|
||||
|
||||
|
||||
*** Ogólny wzór na entropię.
|
||||
|
||||
Na podstawie poprzedniego przykładu można dojść do intuicyjnego wniosku, że
|
||||
optymalny kod dla wyniku o prawdopodobieństwie $p$ ma długość $-\log_2(p)$, a zatem ogólnie
|
||||
entropia źródła o rozkładzie prawdopodobieństwa $\{p_1,\ldots,p_|\Sigma|\}$ wynosi:
|
||||
|
||||
$$E = -\sum_{i=1}^{|\Sigma|} p_i\log_2(p_i)$$.
|
||||
|
||||
Zauważmy, że jest to jeden z nielicznych przypadków, gdy w nauce naturalną
|
||||
podstawą logarytmu jest 2 zamiast… podstawy logarytmu naturalnego ($e$).
|
||||
|
||||
Teoretycznie można mierzyć entropię używając logarytmu naturalnego
|
||||
($\ln$), jednostką entropii będzie wówczas *nat* zamiast bita,
|
||||
niewiele to jednak zmienia i jest mniej poręczne i trudniejsze do interpretacji
|
||||
(przynajmniej w kontekście informatyki) niż operowanie na bitach.
|
||||
|
||||
**Pytanie** Ile wynosi entropia zwykłej sześciennej kostki? Jak wygląda
|
||||
optymalne kodowanie wyników rzutu taką kostką?
|
||||
|
||||
*** Entropia dla próby Bernoulliego
|
||||
|
||||
Wiemy już, że entropia dla rzutu monetą wynosi 1 bit. A jaki będzie wynik dla źle wyważonej monety?
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :results file
|
||||
import matplotlib.pyplot as plt
|
||||
from math import log
|
||||
import numpy as np
|
||||
|
||||
def binomial_entropy(p):
|
||||
return -(p * log(p, 2) + (1-p) * log(1-p, 2))
|
||||
|
||||
x = list(np.arange(0.001,1,0.001))
|
||||
y = [binomial_entropy(x) for x in x]
|
||||
plt.figure().clear()
|
||||
plt.xlabel('prawdopodobieństwo wylosowania orła')
|
||||
plt.ylabel('entropia')
|
||||
plt.plot(x, y)
|
||||
|
||||
fname = f'04_Entropia/binomial-entropy.png'
|
||||
|
||||
plt.savefig(fname)
|
||||
|
||||
fname
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
[[file:04_Entropia/binomial-entropy.png]]
|
||||
|
||||
*Pytanie* Dla oszukańczej monety (np. dla której wypada zawsze orzeł) entropia
|
||||
wynosi 0, czy to wynik zgodny z intuicją?
|
||||
|
||||
** Entropia a język
|
||||
|
||||
Tekst w danym języku możemy traktować jako ciąg symboli (komunikatów) losowanych według jakiegoś
|
||||
rozkładu prawdopodobieństwa. W tym sensie możemy mówić o entropii języka.
|
||||
|
||||
Oczywiście, jak zawsze, musimy jasno stwierdzić, czym są symbole
|
||||
języka: literami, wyrazami czy jeszcze jakimiś innymi jednostkami.
|
||||
|
||||
*** Pomiar entropii języka — pierwsze przybliżenie
|
||||
|
||||
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 ipython :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 ipython :session mysession :exports both :results raw drawer
|
||||
chars_in_pan_tadeusz = len(set(get_characters(pan_tadeusz)))
|
||||
chars_in_pan_tadeusz
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
95
|
||||
:end:
|
||||
|
||||
… założyć jednostajny rozkład prawdopodobieństwa i w ten sposób policzyć entropię:
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
from math import log
|
||||
|
||||
95 * (1/95) * log(95, 2)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
6.569855608330948
|
||||
:end:
|
||||
|
||||
*** Mniej rozrzutne kodowanie
|
||||
|
||||
Przypomnijmy sobie jednak, że rozkład jednostek języka jest zawsze
|
||||
skrajnie nierównomierny! Jeśli uwzględnić ten nierównomierny rozkład
|
||||
znaków, można opracować o wiele efektywniejszy sposób zakodowania znaków składających się na „Pana Tadeusza”
|
||||
(częste litery, np. „a” i „e” powinny mieć krótkie kody, a rzadkie, np. „ź” — dłuższe).
|
||||
|
||||
Policzmy entropię przy takim założeniu:
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
from collections import Counter
|
||||
from math import log
|
||||
|
||||
def unigram_entropy(t):
|
||||
counter = Counter(t)
|
||||
|
||||
total = counter.total()
|
||||
return -sum((p := count / total) * log(p, 2) for count in counter.values())
|
||||
|
||||
unigram_entropy(get_characters(pan_tadeusz))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
4.938605272823633
|
||||
:end:
|
||||
|
||||
(Jak dowiemy się na kolejnym wykładzie, zastosowaliśmy tutaj *unigramowy model języka*).
|
||||
|
||||
*** Ile wynosi entropia rękopisu Wojnicza?
|
||||
|
||||
#+BEGIN_SRC ipython :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 ipython :session mysession :exports both :results raw drawer
|
||||
unigram_entropy(get_characters(voynich))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
3.902708104423842
|
||||
:end:
|
||||
|
||||
*** Rzeczywista entropia?
|
||||
|
||||
W rzeczywistości entropia jest jeszcze mniejsza, tekst nie jest
|
||||
generowany przecież według rozkładu wielomianowego. Istnieją rzecz
|
||||
jasna pewne zależności między znakami, np. niemożliwe, żeby po „ń”
|
||||
wystąpiły litera „a” czy „e”. Na poziomie wyrazów zależności mogę mieć
|
||||
jeszcze bardziej skrajny charakter, np. po wyrazie „przede” prawie na
|
||||
pewno wystąpi „wszystkim”, co oznacza, że w takiej sytuacji słowo
|
||||
„wszystkim” może zostać zakodowane za pomocą 0 (!) bitów.
|
||||
|
||||
Można uwzględnić takie zależności i uzyskać jeszcze lepsze kodowanie,
|
||||
a co za tym idzie lepsze oszacowanie entropii. (Jak wkrótce się
|
||||
dowiemy, oznacza to użycie digramowego, trigramowego, etc. modelu języka).
|
||||
|
||||
*** Rozmiar skompresowanego pliku jako przybliżenie entropii
|
||||
|
||||
Celem algorytmów kompresji jest właściwie wyznaczanie efektywnych
|
||||
sposobów kodowania danych. Możemy więc użyć rozmiaru skompresowanego pliku w bitach
|
||||
(po podzieleniu przez oryginalną długość) jako dobrego przybliżenia entropii.
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
import zlib
|
||||
|
||||
def entropy_by_compression(t):
|
||||
compressed = zlib.compress(t.encode('utf-8'))
|
||||
return 8 * len(compressed) / len(t)
|
||||
|
||||
entropy_by_compression(pan_tadeusz)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
3.673019884633768
|
||||
:end:
|
||||
|
||||
Dla porównania wynik dla rękopisu Wojnicza:
|
||||
|
||||
#+BEGIN_SRC ipython :session mysession :exports both :results raw drawer
|
||||
entropy_by_compression(voynich)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
:results:
|
||||
2.942372881355932
|
||||
:end:
|
||||
|
||||
*** Gra Shannona
|
||||
|
||||
Innym sposobem oszacowania entropii tekstu jest użycie… ludzi. Można poprosić rodzimych użytkowników
|
||||
danego języka o przewidywanie kolejnych liter (bądź wyrazów) i w ten sposób oszacować entropię.
|
||||
|
||||
*Projekt* Zaimplementuj aplikację webową, która umożliwi „rozegranie” gry Shannona.
|
BIN
wyk/04_Entropia/binomial-entropy.png
Normal file
After Width: | Height: | Size: 26 KiB |
1
wyk/04_Entropia/communication.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2022-03-05T13:05:15.969Z" agent="5.0 (X11)" etag="T1jv8GjlxjBRy82UXK3g" version="16.2.2" type="device"><diagram id="E-zPRpFz5prVeiZgI5WF" name="Page-1">1VbbcpswEP0aHpMxEGznMbFzmTZtPc1Dk0cZrUGJ0LpC2JCvrwTC3OzcO9P6waM9klbsObtaOf4sya8kWcffkAJ3vBHNHX/ueN7piav/DVBUQOAFFRBJRivIbYBb9gQWHFk0YxTSzkKFyBVbd8EQhYBQdTAiJW67y1bIu6euSQQD4DYkfIj+YlTFFTr1Jg1+DSyK65Pd8Wk1k5B6sY0kjQnFbQvyLxx/JhFVNUryGXDDXc1Lte/ywOzuwyQI9ZoNX6X3O78fXS/phv3kIss2X7wj62VDeGYD/k4o2YbEfrMqaiL056/NMEv4WahQOv75BqRimqobsgS+wJQphkIvWaJSmLQWnHEWmQmFa43GKuHacPUQM8WZgNlOvJEG7SfpvZAfjNXdMagzDzABJQu9xG7wTizpRc/eNhr6Fopb8o0tRmzWRDvPDbF6YLl9A88nA55/0CVD+b8THfj/GNHBgOiDBK845GfmitBUgKB2OA85SVMWdvmTmAkKtEMc0MHV8SJtLVqCPbTUmAROFNt03e/jyp6wQKYPbtJ/2lNl0qM7xUyGYHe174yeo8B7wZEiMgI1cFRKtwv7/WqOB2o+EkGcWeBMDf6ISSbYIwkf2EBlo05ZL10hia2QUCsFck/pJIxS4+NcQsqeyLL0Z0RfmyDLsINzJ5g/Vz+2GdnNTQtoJ8jh7D1YbEejY7dun+/NkHoJrlYp/BXNpnuluLUmShVjhILwiwbtlVez5gbNRVYK9wBKFfZ9QDKFXVkhZ+rObD8OrHXfmpnn1nNpFLUhdKB3beO+9OD3fvVs46W0Om4WIJkmzmTUm24IzVNZis/waV8aVaW91MqHufPqRPnQtTsZFOoVCJDE9C8dY5EskQ9r9ON9rb7LdTov9FPM9reyaXZzKq0yp8qPT2h8bu+F4U6GjW/8OY1Pm80rsarS5qntX/wB</diagram></mxfile>
|
BIN
wyk/04_Entropia/communication.drawio.png
Normal file
After Width: | Height: | Size: 10 KiB |
1
wyk/04_Entropia/gas-high-entropy.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2022-03-05T10:14:12.443Z" agent="5.0 (X11)" etag="UjtYN9dZJ1n-mtJw7vZr" version="16.2.2" type="device"><diagram id="zkchOmJWayHcCaytrl_I" name="Page-1">jZPfb4MgEMf/Gh+bKFS3vs513bLsqUv2TIQKLXiO0mr31w/l/JVmydAofO444HtHRHPT7iyr5QdwoSMS8zaizxEhm3Xivx24BZCSNIDSKh5QMoG9+hEIY6QXxcV54egAtFP1EhZQVaJwC8ashWbpdgC9XLVmpbgD+4Lpe/qluJOBPpKHib8KVcph5STbBIthgzOGOEvGoQmoPxzdRjS3AC70TJsL3Wk36BIUePnDOm7Misr9Z8LpuNrG5ppe31ylDf1+P+6yFR7jyvQFDxyRtX8/ww937m6DHBYuFRddxDiiT41UTuxrVnTWxuffM+mM9qPEd8/OwmmUjXpyUFrnoMH20egh7Z6OQ+VmPLQxwsyS9c1bcN/COtH+KUgyyuzLU4ARzt68C04gFGsMS5OmOG6mRJM1MjlLcoaMYW2VY+hJft/BDAzDKdO9bXZd6PYX</diagram></mxfile>
|
BIN
wyk/04_Entropia/gas-high-entropy.drawio.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
1
wyk/04_Entropia/gas-low-entropy.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2022-03-05T10:11:11.528Z" agent="5.0 (X11)" etag="-eu0Wo5sdhkbwVuXUHS7" version="16.2.2" type="device"><diagram id="zkchOmJWayHcCaytrl_I" name="Page-1">5ZVRT8IwEMc/zR5NtpUVeBRENMYnTHw0db1t1W7FUhj46b3RbmMwEk3UmJgQcv3f7a79/QvzyDTfzjVbZveKg/RCn289cuWF4XgQ4Hcl7KwQhZEVUi24lYJWWIh3cKLv1LXgsOoUGqWkEcuuGKuigNh0NKa1KrtliZLdqUuWwomwiJk8VR8FN5lVR+Gw1W9ApFk9OaBjm8lZXexarDLGVWml/eHIzCNTrZSxUb6dgqzY1Vwsgesz2WZjGgrzmQdeXy5mfr6JNremkDl5u3uZ04vQdtkwuXYHdps1u5qAVuuCQ9XE98ikzISBxZLFVbZEy1HLTC5xFWC4Mlq9NqQIKomQcqqk0vtuJEmAxnFTeZDhw/GzX41wWwJtYHv2rEFDEG8eqByM3mGJeyAk7vrsjtZl62HgePnZgX/Uacxdm7Rp3ZLFwMH9Amjy26A5g1HSC5rGI3hOvgc0if4a6KgHNJU4dcLFBsPU7E8+wM/DU2CDugIHdoqODEJMps+Fmm2hCjgywklMirTAZYxYAfVJBV3gv8ylS+SC82pMr+3di/EdPw965NogOnGN9phGfso0+hXTwv9pGhn9mmm4bN9L+9zBy53MPgA=</diagram></mxfile>
|
BIN
wyk/04_Entropia/gas-low-entropy.drawio.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
19
wyk/05_Ngramowy_model.ipynb
Normal file
112
wyk/05_Ngramowy_model.org
Normal file
@ -0,0 +1,112 @@
|
||||
|
||||
* N-gramowe modele języka i ich zastosowania
|
||||
|
||||
*** Przypomnienie
|
||||
|
||||
Przypomnijmy, że model języka zwraca prawdopodobieństwo dla danego
|
||||
ciągu symboli (tokenów, wyrazów itp.) $w_1\ldots w_N$ (o długości $N$):
|
||||
|
||||
$$P_M(w_1\ldots w_N) = ?$$
|
||||
|
||||
W dalszym ciągu będziemy zakładali, że będziemy operować na wyrazach.
|
||||
Zbiór wszystkich wyrazów nazywa się *słownikiem* (ang. /vocabulary/,
|
||||
nie /dictionary!/), w literaturze dotyczącej modelowania języka
|
||||
zazwyczaj oznacza się go literą $V$ (częściej niż $\Sigma$).
|
||||
Dale zakładamy, że słownik jest skończony.
|
||||
|
||||
*** Co jeszcze potrafi model języka?
|
||||
|
||||
**** Przewidywanie kolejnego słowa
|
||||
|
||||
$$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
|
||||
\Sigma^*}P_M(w_1\dots w_N\alpha)}{\sum_{\alpha\in\Sigma^*}P(w_1\dots w_{n-1}\alpha)}$$
|
||||
|
||||
$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:
|
||||
|
||||
$$P_M(X_N=w_N|X_1=w_1,\ldots,X_{N-1}=w_{N-1}),$$
|
||||
|
||||
gdzie $P_M(X_i=w)$ oznacza prawdopodobieństwo, że na $i$-tej pozycji wystąpi słowo $w$.
|
||||
|
||||
**** Odgadywanie słowa w luce
|
||||
|
||||
$$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)$$
|
||||
|
||||
*** Przykład dla autentycznego modelu języku
|
||||
|
||||
Zobaczmy przykładowe zastosowania i wyniki dla modelu języku
|
||||
wyuczonego na tekstach z II poł. XX w.
|
||||
|
||||
[[./05_Ngramowy_model/tabelka.png]]
|
||||
|
||||
*** Do czego stosujemy model języka?
|
||||
|
||||
Model języka sam w sobie nie jest zbyt użyteczny. To raczej środek do celu
|
||||
niż cel sam w sobie.
|
||||
|
||||
Model języka:
|
||||
- ma zastosowanie w kryptoanalizie
|
||||
- Oxmynsxq mkx lo kmrsofon li cdenisxq sdc kvzrklodsm mrkbkmdobc kxn bozvkmsxq okmr yxo li dro 13dr voddob zvkmon pebdrob kvyxq sx dro kvzrklod.
|
||||
- pomaga(ł) wybrać właściwe tłumaczenie w tłumaczeniu maszynowym
|
||||
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),
|
||||
- pomaga znaleźć „podejrzane” miejsca w tekście
|
||||
(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,
|
||||
- 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.
|
||||
|
||||
** N-gramowy model języka
|
||||
|
||||
Zawsze prawdziwe:
|
||||
|
||||
$$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}).$$
|
||||
|
||||
Można aproksymować prawdopodobieństwa używając $n$-gramów:
|
||||
|
||||
$$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}).$$
|
||||
|
||||
*** Model trigramowy
|
||||
|
||||
Dla $n=3$:
|
||||
|
||||
$$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}).$$
|
||||
|
||||
Zauważmy, że model trigramowy oznacza modelowanie kolejnego wyrazu przy znajomości
|
||||
2 (nie 3!) poprzedzających wyrazów (*razem* mamy 3 wyrazy).
|
||||
|
||||
*** Model digramowy/bigramowy
|
||||
|
||||
Dla $n=2$:
|
||||
|
||||
$$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})$$
|
||||
|
||||
*** Model unigramowy
|
||||
|
||||
Dla $n=1$ uzyskujemy przypadek szczególny:
|
||||
|
||||
$$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)$$
|
||||
|
||||
Zauważmy, że w modelu unigramowym w ogóle nie bierzemy pod uwagę kolejności wyrazów.
|
||||
|
||||
*** Estymacja prawdopodobieństw
|
||||
|
||||
Dla $n$-gramowego modelu potrzebujmy estymować wartości:
|
||||
|
||||
$$P_M(w_i|w_{i-n+1}\dots w_{i-1}).$$
|
||||
|
||||
Prawdopodobieństwa te estymujemy na podstawie jakiegoś *korpusu tekstów*
|
||||
(możemy nazywać go również *zbiorem uczącym*).
|
||||
|
||||
Najprostszy sposób:
|
||||
|
||||
$$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}},$$
|
||||
|
||||
gdzie $\# w_1\dots w_k$ oznacza liczbę wystąpień w korpusie.
|
||||
|
||||
Na przykład, jeśli model $M$ zostanie wyuczony na tekście /do be do be do do/, wówczas
|
||||
$P_M(\mathit{be}|\mathit{do})=\frac{2}{3}$.
|
BIN
wyk/05_Ngramowy_model/tabelka.pdf
Normal file
BIN
wyk/05_Ngramowy_model/tabelka.png
Normal file
After Width: | Height: | Size: 242 KiB |
19
wyk/06_Ewaluacja.ipynb
Normal file
363
wyk/06_Ewaluacja.org
Normal file
@ -0,0 +1,363 @@
|
||||
* Ewaluacja modeli języka
|
||||
|
||||
Jak już widzimy, możemy mieć różne modele języka. Nawet jeśli
|
||||
pozostajemy tylko na gruncie najprostszych, $n$-gramowych modeli
|
||||
języka, inne prawdopodobieństwa uzyskamy dla modelu digramowego, a
|
||||
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'}'\}$.
|
||||
|
||||
Warto też wydzielić osobny „deweloperski” zbiór testowy (/dev set/) —
|
||||
do testowania na bieżąco, optymalizacji hiperparametrów itd. Zbiory
|
||||
testowe nie muszą być bardzo duże, np. kilka tysięcy zdań może w zupełności wystarczyć.
|
||||
|
||||
Tak podzielony korpus możemy traktować jako *wyzwanie modelowania języka*.
|
||||
|
||||
*** Przykład wyzwania modelowania języka
|
||||
|
||||
Wyzwanie
|
||||
[[https://gonito.net/challenge/challenging-america-word-gap-prediction|Challenging America word-gap prediction]]
|
||||
to wyzwanie modelowania amerykańskiej odmiany języka angielskiego, używanej w gazetach w XIX w. i I poł. XX w.
|
||||
|
||||
#+BEGIN_SRC
|
||||
$ git clone git://gonito.net/challenging-america-word-gap-prediction
|
||||
$ cd challenging-america-word-gap-prediction
|
||||
$ xzcat train/in.tsv.xz | wc
|
||||
432022 123677147 836787912
|
||||
$ xzcat dev-0/in.tsv.xz | wc
|
||||
10519 3076536 20650825
|
||||
$ xzcat test-A/in.tsv.xz | wc
|
||||
7414 2105734 14268877
|
||||
#+END_SRC
|
||||
|
||||
Dodajmy, że poszczególne zbiory zawierają teksty z różnych gazet. Jest
|
||||
to właściwe podejście, jeśli chcemy mierzyć rzeczywistą skuteczność modeli języka.
|
||||
(Teksty z jednej gazety mogłyby być zbyt proste).
|
||||
|
||||
Oto przykład tekstu z wyzwania:
|
||||
|
||||
#+BEGIN_SRC
|
||||
$ xzcat train/in.tsv.xz | head -n 1 | fold
|
||||
4e04702da929c78c52baf09c1851d3ff ST ChronAm 1919.6041095573314
|
||||
30.47547 -90.100911 came fiom the last place to this\nplace, and thi
|
||||
s place is Where We\nWere, this is the first road I ever\nwas on where you can r
|
||||
ide elsewhere\nfrom anywhere and be nowhere.\nHe says, while this train stops ev
|
||||
ery-\nwhere, it never stops anywhere un-\nless its somewhere. Well, I says,\nI'm
|
||||
glad to hear that, but, accord-\ning to your figures, I left myself\nwhere 1 wa
|
||||
s, which is five miles near-\ner to myself than I was when we\nwere where we are
|
||||
now.\nWe have now reached Slidell.\nThat's a fine place. The people\ndown there
|
||||
remind me of bananas-\nthey come and go in bunches. 811-\ndell used to be noted
|
||||
for her tough\npeople. Now she is noted for be,\ntough steaks. Well, I certainl
|
||||
y got\none there. When the waiter brought\nit in it was so small I thought. It\n
|
||||
was a crack in the plate. I skid,\nwaiter what else have you got? +He\nbrought m
|
||||
e in two codfish and one\nsmelt. I said, waiter have you got\npigs feet? He said
|
||||
no, rheumatism\nmakes me walk that way. I sald,\nhow is the pumpkin pie?
|
||||
said\nit's all squash. The best I could get\nin that hotel was a soup sandwich.\
|
||||
nAfter the table battle the waiter and\nI signed an armistice. I then went\nover
|
||||
to the hotel clerk and asked for\na room. He said with or without a\nbed? I sai
|
||||
d, with a bed. He said,\nI don't think I 'have' a bed long\nenough for you. I sa
|
||||
id, well, I'll\naddtwo feettoitwhenIgetinit.\nHe gave me a lovely room on the\nt
|
||||
op floor. It was one of those rooms\nthat stands on each side. If you\nhappen to
|
||||
get up in the middle of\nthe night you want to be sure and\nget up in the middl
|
||||
e of the room.\nThat night I dreamt I was eating\nflannel cakes. When I woke up
|
||||
half\nof the blanket was gone. I must\nhave got up on the wrong side of the\nbed
|
||||
, for next morning I had an awful\nheadache. I told the manager about\nit. He sa
|
||||
id, you have rheumatic\npains. I said, no, I think it is on,\nof those attic roo
|
||||
m pains. I nad to\ngetupat5a.m.inthemorningso\nthey could use the sheet to set t
|
||||
he\nbreakfast table.
|
||||
#+END_SRC
|
||||
|
||||
Zauważmy, że mamy nie tylko tekst, lecz również metadane (czas i
|
||||
współrzędne geograficzne). W modelowaniu języka można uwzględnić
|
||||
również takie dodatkowe parametry (np. prawdopodobieństwa wystąpienia
|
||||
słowa /koronawirus/ wzrasta po roku 2019).
|
||||
|
||||
Zauważmy również, że tekst zawiera błędy OCR-owe (np. /nad/ zamiast
|
||||
/had/). Czy w takim razie jest to sensowne wyzwanie modelowania
|
||||
języka? Tak, w niektórych przypadkach możemy chcieć modelować tekst z
|
||||
uwzględnieniem „zaszumień” wprowadzanych przez ludzi bądź komputery
|
||||
(czy II prawo termodynamiki!).
|
||||
|
||||
** Co podlega ocenie?
|
||||
|
||||
Ogólnie ocenie powinno podlegać prawdopodobieństwo $P_M(C')$, czyli
|
||||
prawdopodobieństwo przypisane zbiorowi testowemu $C'$ przez model
|
||||
(wyuczony na zbiorze $C$).
|
||||
|
||||
Jeśli oceniamy przewidywania, które człowiek lub komputer czynią, to
|
||||
im większe prawdopodobieństwo przypisane do tego, co miało miejsce,
|
||||
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}).$$
|
||||
|
||||
** Entropia krzyżowa
|
||||
|
||||
Można powiedzieć, że dobry model języka „wnosi” informację o języku. Jeśli zarówno
|
||||
nadawca i odbiorca tekstu mają do dyspozycji ten sam model języka…
|
||||
|
||||
[[./06_Ewaluacja/lm-communication.drawio.png]]
|
||||
|
||||
… powinni być w stanie zaoszczędzić na długości komunikatu.
|
||||
|
||||
W skrajnym przypadku, jeśli model jest pewny kolejnego słowa, tj.
|
||||
$P_M(w'_i|w'_1\ldots w'_{i-1}) = 1$, wówczas w $i$-tym kroku w ogóle
|
||||
nic nie trzeba przesyłać przez kanał komunikacji. Taka sytuacja może
|
||||
realnie wystąpić, na przykład: z prawdopodobieństwem zbliżonym do 1 po wyrazie
|
||||
/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ż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.
|
||||
|
||||
*** Wzór na entropię krzyżową
|
||||
|
||||
Przypomnijmy, że symbol o prawdopodobieństwie $p$ można zakodować za
|
||||
pomocą (średnio) $-\log_2(p)$ bitów, tak więc jeśli nadawca i odbiorca dysponują
|
||||
modelem $M$, wówczas można przesłać cały zbiór testowy $C$ za pomocą następującej liczby bitów:
|
||||
|
||||
$$-\sum_{i=1}^{N'} log P_M(w'_i|w'_1\ldots w'_{i-1}).$$
|
||||
|
||||
Aby móc porównywać wyniki dla korpusów dla różnej długości, warto znormalizować
|
||||
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 założeniu, że dysponujemy modelem $M$. Im niższa wartość
|
||||
entropii krzyżowej, tym lepiej, im bowiem mniejsza nasza niewiedza,
|
||||
tym lepiej.
|
||||
|
||||
Entropią krzyżową jest często nazywaną funkcją *log loss*, zwłaszcza w
|
||||
kontekście jej użycia jako funkcji straty przy uczeniu neuronowych modeli języka
|
||||
(o których dowiemy się później).
|
||||
|
||||
** Wiarygodność
|
||||
|
||||
Innym sposobem mierzenia jakości modelu języka jest odwołanie się do
|
||||
*wiarygodności* (ang. /likelihood/). Wiarygodność to
|
||||
prawdopodobieństwo przypisane zdarzeniom niejako „po fakcie”. Jak już
|
||||
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}),$$
|
||||
|
||||
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
|
||||
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})}.$$
|
||||
|
||||
*** Interpretacja wiarygodności
|
||||
|
||||
Co ciekawe, wiarygodność jest używana jako metryka ewaluacji modeli
|
||||
języka rzadziej niż entropia krzyżowa (log loss), mimo tego, że wydaje
|
||||
się nieco łatwiejsza do interpretacji dla człowieka. Otóż wiarygodność
|
||||
to *średnia geometryczna prawdopodobieństw przypisanych przez model języka do słów, które rzeczywiście wystąpiły*.
|
||||
|
||||
*** 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 (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-proby”
|
||||
|
||||
W modelowaniu języka bardzo często używa się logarytmów prawdopodobieństw (z angielskiego skrótowo /log probs/),
|
||||
zamiast wprost operować na prawdopodobieństwach:
|
||||
|
||||
- dodawanie log probów jest tańsze obliczeniowo niż mnożenie prawdopodobieństw,
|
||||
- bardzo małe prawdopodobieństwa znajdują się na granicy dokładności reprezentacji
|
||||
liczb zmiennopozycyjnych, log proby są liczbami ujemnymi o „poręczniejszych”
|
||||
rzędach wielkości.
|
||||
|
||||
** Perplexity
|
||||
|
||||
Tak naprawdę w literaturze przedmiotu na ogół używa się jeszcze innej metryki ewaluacji —
|
||||
*perplexity*. Perplexity jest definiowane jako:
|
||||
|
||||
$$\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,
|
||||
jeśli model przewiduje, że w danym miejscu tekstu może wystąpić z
|
||||
równym prawdopodobieństwem jedno z 32 słów, wówczas (jeśli
|
||||
rzeczywiście któreś z tych słów wystąpiło) entropia wynosi 5 bitów, a
|
||||
perplexity — 32.
|
||||
|
||||
Inaczej: perplexity to po prostu odwrotność wiarygodności:
|
||||
|
||||
$$\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.
|
||||
|
||||
*** Perplexity — przykład
|
||||
|
||||
Wyuczmy model języka przy użyciu gotowego narzędzia [[https://github.com/kpu/kenlm|KenLM]].
|
||||
KenLM to zaawansowane narzędzie do tworzenia n-gramowych modeli języka
|
||||
(zaimplementowano w nim techniki wygładzania, które omówimy na kolejnym wykładzie).
|
||||
|
||||
Wyuczmy na zbiorze uczącym wspomnianego wyzwania /Challenging America word-gap prediction/
|
||||
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
|
||||
$ 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,
|
||||
wiarygodność i perplexity) są ze sobą ściśle związane, w gruncie
|
||||
rzeczy to po prostu jedna miara.
|
||||
|
||||
|Metryka | Kierunek |Najlepsza wartość | Najgorsza wartość |
|
||||
|------------------+----------------------+------------------+-------------------|
|
||||
|entropia krzyżowa | im mniej, tym lepiej | 0 | $\infty$ |
|
||||
|wiarygodność | im więcej, tym lepiej| 1 | 0 |
|
||||
|perplexity | im mniej, tym lepiej | 1 | $\infty$ |
|
||||
|
||||
*** Uwaga na zerowe prawdopodobieństwa
|
||||
|
||||
Entropia krzyżowa, wiarygodność czy perplexity są bardzo czułe na zbyt
|
||||
dużą pewność siebie. Wystarczy, że dla *jednej* pozycji w zbiorze
|
||||
przypiszemy zerowe prawdopodobieństwo, wówczas wszystko „eksploduje”.
|
||||
Perplexity i entropia krzyżowa „wybuchają” do nieskończoności,
|
||||
wiarygodność spada do zera — bez względu na to, jak dobre są
|
||||
przewidywania dotyczące innych pozycji w tekście!
|
||||
|
||||
W przypadku wiarygodności wiąże się to z tym, że wiarygodność
|
||||
definiujemy jako iloczyn prawdopodobieństwa, oczywiście wystarczy, że
|
||||
jedna liczba w iloczynie była zerem, żeby iloczyn przyjął wartość
|
||||
zero. Co więcej, nawet jeśli pominiemy taki skrajny przypadek, to
|
||||
średnia geometryczna „ciągnie” w dół, bardzo niska wartość
|
||||
prawdopodobieństwa przypisana do rzeczywistego słowa może drastycznie obniżyć
|
||||
wartość wiarygodności (i podwyższyć perplexity).
|
||||
|
||||
|
||||
*** Słowa spoza słownika
|
||||
|
||||
Prostym sposobem przeciwdziałania zerowaniu/wybuchaniu metryk jest
|
||||
przypisywanie każdemu możliwemu słowu przynajmniej niskiego
|
||||
prawdopodobieństwa $\epsilon$. Niestety, zawsze może pojawić się
|
||||
słowa, którego nie było w zbiorze uczącym — *słowo spoza słownika*
|
||||
(/out-of-vocabulary word/, /OOV/). W takim przypadku znowu może
|
||||
pojawić się zerowy/nieskończony wynik.
|
||||
|
||||
|
||||
** Ewaluacja modeli języka w warunkach konkursu
|
||||
|
||||
Jeśli używać tradycyjnych metryk ewaluacji modeli języka (perplexity
|
||||
czy wiarygodność), bardzo łatwo można „oszukać” — wystarczy
|
||||
zaraportować prawdopodobieństwo 1! Oczywiście to absurd, bo albo
|
||||
wszystkim innym tekstom przypisujemy prawdopodobieństwo 0, albo —
|
||||
jeśli „oszukańczy” system każdemu innemu tekstowi przypisze
|
||||
prawdopodobieństwo 1 — nie mamy do czynienia z poprawnym rozkładem
|
||||
prawdopodobieństwa.
|
||||
|
||||
Co gorsza, nawet jeśli wykluczymy scenariusz świadomego oszustwa,
|
||||
łatwo /samego siebie/ wprowadzić w błąd. Na przykład przez pomyłkę
|
||||
można zwracać zawyżone prawdopodobieństwo (powiedzmy przemnożone przez 2).
|
||||
|
||||
Te problemy stają się szczególnie dokuczliwe, jeśli organizujemy
|
||||
wyzwanie, /konkurs/ modelowania języka, gdzie chcemy w sposób
|
||||
obiektywny porównywać różne modele języka, tak aby uniknąć celowego
|
||||
bądź nieświadomego zawyżania wyników.
|
||||
|
||||
Przedstawimy teraz, w jaki sposób poradzono sobie z tym problemem
|
||||
w wyzwaniu /Challenging America word-gap prediction/
|
||||
|
||||
*** Odgadywanie słowa w luce
|
||||
|
||||
Po pierwsze, jaka sama nazwa wskazuje, w wyzwaniu /Challenging America
|
||||
word-gap prediction/ zamiast zwracania prawdopodobieństwa dla całego
|
||||
tekstu oczekuje się podania rozkładu prawdopodobieństwa dla brakującego słowa.
|
||||
|
||||
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.
|
||||
|
||||
*** 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/06_Ewaluacja/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/06_Ewaluacja/lm-communication.drawio.png
Normal file
After Width: | Height: | Size: 16 KiB |