aitech-moj/cw/07_biblioteki_STM.ipynb

11 KiB

Logo 1

Modelowanie Języka

7. biblioteki STM [ćwiczenia]

Jakub Pokrywka (2022)

Logo 2

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