11 KiB
Modelowanie Języka
6. biblioteki LM [ćwiczenia]
Jakub Pokrywka (2022)
KENLM
W praktyce korzysta się z gotowych bibliotek do statystycznych modeli językowych. Najbardziej popularną biblioteką jest KENLM ( https://kheafield.com/papers/avenue/kenlm.pdf ). Repozytorium znajduje się https://github.com/kpu/kenlm a dokumentacja https://kheafield.com/code/kenlm/
Na komputerach wydziałowych nie powinno być problemu ze skompilowaniem biblioteki.
Najprostszy scenariusz użycia
KENLM_BUILD_PATH='/home/kuba/kenlm/build'
!wget https://wolnelektury.pl/media/book/txt/lalka-tom-pierwszy.txt
!wget https://wolnelektury.pl/media/book/txt/lalka-tom-drugi.txt
budowa modelu
!$KENLM_BUILD_PATH/bin/lmplz -o 4 < lalka-tom-pierwszy.txt > lalka_tom_pierwszy_lm.arpa
plik arpa
Powyższa komenda tworzy model językowy z wygładzaniem i zapisuje go do pliku tekstowego arpa. Parametr -o 4 odpowiada za maksymalną ilość n-gramów w modelu: 4-gramy.
Plik arpa zawiera w sobie prawdopodobieństwa dla poszczególnych n-gramów. W zasadzie są to logarytmy prawdopodbieństw o podstawie 10.
Podejrzyjmy plik arpa:
!head -n 30 lalka_tom_pierwszy_lm.arpa
Linijka to kolejno: prawdopodobieństwo (log10), n-gram, waga back-off (log10).
Aby spradzić prawdopodobieństwo sekwencji (a także PPL modelu) należy użyć komendy query
test_str=!(head -n 17 lalka-tom-drugi.txt | tail -n 1)
test_str = test_str[0]
test_str
test_str
!echo $test_str | $KENLM_BUILD_PATH/bin/query lalka_tom_pierwszy_lm.arpa 2> /dev/null
Zgodnie z dokumentacją polecenia query, format wyjściowy to dla każdego słowa:
word=vocab_id ngram_length log10(p(word|context))
A co jeśli trochę zmienimy początek zdania?
test2_str = "Lubię placki i wcale by mnie nie zdziwiło, gdyby około grudnia wybuchła wojna."
!echo $test2_str | $KENLM_BUILD_PATH/bin/query lalka_tom_pierwszy_lm.arpa 2> /dev/null
A co jeśli trochę zmienimy wejście?
Trochę bardziej zaawansowane użycie
Pierwsza rzecz, która rzuca się w oczy: tokeny zawierają znaki interpunkcyjne. Użyjemy zatem popularnego tokenizera i detokenizera moses z https://github.com/moses-smt/mosesdecoder
https://github.com/moses-smt/mosesdecoder/tree/master/scripts/tokenizer
tokenizacja i lowercasing
TOKENIZER_SCRIPTS='/home/kuba/mosesdecoder/scripts/tokenizer'
!echo $test_str
!echo $test_str | $TOKENIZER_SCRIPTS/tokenizer.perl --language pl
W łatwy sposób można odzyskać tekst źródłowy:
!echo $test_str | $TOKENIZER_SCRIPTS/tokenizer.perl --language pl | $TOKENIZER_SCRIPTS/detokenizer.perl --language pl
W naszym przykładzie stworzymy model językowy lowercase. Można osobno wytrenować też truecaser (osobny model do przywracania wielkości liter), jeżeli jest taka potrzeba.
!echo $test_str | $TOKENIZER_SCRIPTS/tokenizer.perl --language pl | $TOKENIZER_SCRIPTS/lowercase.perl
!cat lalka-tom-pierwszy.txt | $TOKENIZER_SCRIPTS/tokenizer.perl --language pl | $TOKENIZER_SCRIPTS/lowercase.perl > lalka-tom-pierwszy-tokenized-lowercased.txt
!cat lalka-tom-drugi.txt | $TOKENIZER_SCRIPTS/tokenizer.perl --language pl | $TOKENIZER_SCRIPTS/lowercase.perl > lalka-tom-drugi-tokenized-lowercased.txt
!$KENLM_BUILD_PATH/bin/lmplz -o 4 --prune 1 1 1 1 < lalka-tom-pierwszy-tokenized-lowercased.txt > lalka_tom_pierwszy_lm.arpa
test_str=!(head -n 17 lalka-tom-drugi-tokenized-lowercased.txt | tail -n 1)
test_str=test_str[0]
test_str
model binarny
Konwertując model do postaci binarnej, inferencja będzie szybsza
!$KENLM_BUILD_PATH/bin/build_binary lalka_tom_pierwszy_lm.arpa lalka_tom_pierwszy_lm.binary
!echo $test_str | $KENLM_BUILD_PATH/bin/query lalka_tom_pierwszy_lm.binary
sprawdzanie dokumentacji
Najłatwiej sprawdzić wywołując bezpośrednio komendę
!$KENLM_BUILD_PATH/bin/lmplz
wrapper pythonowy
!pip install https://github.com/kpu/kenlm/archive/master.zip
import kenlm
model = kenlm.Model('lalka_tom_pierwszy_lm.binary')
print(model.score(test_str, bos = True, eos = True))
for i in model.full_scores(test_str):
print(i)
Zadanie
Stworzyć model językowy za pomocą gotowej biblioteki (KENLM lub inna)
Warunki zaliczenia:
- wynik widoczny na platformie zarówno dla dev i dla test
- wynik dla dev i test lepszy (niższy) niż 1024.00 (liczone przy pomocy geval)
- deadline do końca dnia 17.04
- commitując rozwiązanie proszę również umieścić rozwiązanie w pliku /run.py (czyli na szczycie katalogu). Można przekonwertować jupyter do pliku python przez File → Download as → Python. Rozwiązanie nie musi być w pythonie, może być w innym języku.
- zadania wykonujemy samodzielnie
- w nazwie commita podaj nr indeksu
- w tagach podaj kenlm!
- uwaga na specjalne znaki \\n w pliku 'in.tsv' oraz pierwsze kolumny pliku in.tsv (które należy usunąć)
Punktacja:
- podstawa: 40 punktów
- 50 punktów z najlepszy wynik z 2 grup
- 20 punktów za znalezienie się w pierwszej połowie, ale poza najlepszym wynikiem