wstęp xiv podziękowania xxvi o książce xxiv o autorach xxxii
o ilustracji na okładce xxxiv
CZĘŚĆ 1 ■ MÓWIĄCE MASZYNY 1
1. Pakiety myśli (przegląd NLP) 3
1.1. Język naturalny a język programowania 4
1.2. Magia 4
1.2.1. Maszyny prowadzące konwersację 5
1.2.2. Matematyka 6
1.3. Zastosowania praktyczne 8
1.4. Język widziany „oczyma” komputera 10
1.4.1. Język zamków 10
1.4.2. Wyrażenia regularne 11
1.4.3. Prosty chatbot 13
1.4.4. Inny sposób 16
1.5. Krótkie spojrzenie na hiperprzestrzeń 20
1.6. Kolejność słów i gramatyka 22
1.7. Potok języka naturalnego chatbota 23
1.8. Szczegóły przetwarzania 26
1.9. IQ języka naturalnego 28
2. Zbuduj swój słownik (tokenizacja słów) 32
2.1. Wyzwania (wprowadzenie do stemmingu) 34
2.2. Tworzenie swojego słownika za pomocą tokenizatora 35
2.2.1. Iloczyn skalarny 44
2.2.2. Pomiar nakładania się wektorów BoW 44
2.2.3. Poprawianie tokenów 45
Jak działają wyrażenia regularne 46 ■ Poprawione wyrażenia regularne do podziału słów 47 ■ Formy skrócone 50
2.2.4. Rozszerzenie słownika za pomocą n-gramów 50 N-gramy 51 ■ Stop listy 54
2.2.5. Normalizacja słownika 57
Ujednolicanie wielkości liter 57 ■ Stemming 59 ■ Lematyzacja 62 ■ Przypadki użycia 64
2.3. Wydźwięk 65
2.3.1. VADER – analizator wydźwięku oparty na regułach 67
2.3.2. Naiwny klasyfikator bayesowski 68
3. Matematyka na słowach (wektory TD-IDF) 73
3.1. Wektor BoW 74
3.2. Wektoryzacja 79
3.2.1. Przestrzenie wektorowe 82
3.3. Prawo Zipfa 87
3.4. Modelowanie tematyczne 89
3.4.1. Powrót Zipfa 92
3.4.2. Ranking trafności 94
3.4.3. Narzędzia 96
3.4.4. Inne możliwości 97
3.4.5. Okapi BM25 98
3.4.6. Co dalej 99
4. Odnajdowanie znaczenia w licznikach słów (analiza semantyczna) 101
4.1. Od liczników słów do wyników dla tematów 103
4.1.1. Wektory TF-IDF i lematyzacja 103
4.1.2. Wektory tematyczne 104
4.1.3. Eksperyment myślowy 105
4.1.4. Algorytm do oceny tematów 110
„Kuzyni” LSA 111
4.1.5. Klasyfikator LDA 111
Inny „kuzyn” 115
4.2. Analiza utajonych własności semantycznych (LSA) 116
4.2.1. Wasz eksperyment myślowy staje się prawdziwy 118
Gra w Mad libs 119
4.3. Rozkład według wartości osobliwej 121
4.3.1. U – lewostronne wektory osobliwe 123
4.3.2. S – wartości osobliwe 124
4.3.3. V T – prawostronne wektory osobliwe 125
4.3.4. Orientacja macierzy SVD 126
4.3.5. Obcinanie tematów 127
4.4. Analiza głównych składowych 128
4.4.1. PCA dla wektorów 3D 130
4.4.2. Przestańmy szaleć i wróćmy do NLP 131
4.4.3. Stosowanie PCA do semantycznej analizy komunikatów SMS 134
4.4.4. Używanie obciętego SVD do analizy semantycznej komunikatu SMS 136
4.4.5. Jak dobrze działa LSA przy klasyfikacji spamu 137
Rozszerzenia LSA i SVD 139
4.5. Ukryta alokacja Dirichleta (LDiA) 140
4.5.1. Idea LDiA 141
4.5.2. Model tematyczny LDiA dla komunikatów SMS 143
4.5.3. LDiA + LDA = klasyfikator spamu 146
4.5.4. Uczciwsze porównanie: 32 tematy LDiA 148
4.6. Odległość i podobieństwo 149
4.7. Sterowanie za pomocą informacji zwrotnej 152
4.7.1. Liniowa analiza dyskryminacyjna 153
4.8. Moc wektorów tematycznych 155
4.8.1. Wyszukiwanie semantyczne 156
4.8.2. Ulepszenia 159
CZĘŚĆ 2 ■ GŁĘBSZE UCZENIE SIĘ (SIECI NEURONOWE) 161
5. Sieci neuronowe krok po kroku (perceptrony i propagacja wsteczna) 163
5.1. Sieci neuronowe – lista składników 164
5.1.1. Perceptron 165
5.1.2. Perceptron numeryczny 165
5.1.3. Zboczenie z drogi spowodowane odchyleniem 166 Neuron w Pythonie 168 ■ Klasa tkwi w sesji 169 ■ Uczenie się logiki to czysta frajda 170 ■ Następny krok 172 ■ Koniec drugiej zimy sztucznej inteligencji 175 ■ Propagacja wsteczna 176 ■ Zróżniczkujmy wszystko 179
5.1.4. Poszusujmy – powierzchnia błędu 181
5.1.5. Z wyciągu prosto na stok 182
5.1.6. Udoskonalmy to nieco 182
5.1.7. Keras: sieci neuronowe w Pythonie 184
5.1.8. Wprzód i w głąb 187
5.1.9. Normalizacja: stylowe wejście 188
6. Wnioskowanie przy użyciu wektorów słów (Word2vec) 190
6.1. Zapytania semantyczne i analogie 191
6.1.1. Pytania o analogię 192
6.2. Wektory słów 193
6.2.1. Wnioskowanie zorientowane wektorowo 197 Jeszcze więcej powodów, by korzystać z wektorów słów 199
6.2.2. Jak obliczać reprezentacje Word2vec 200 Podejście skip-gram 201 ■ Czym jest softmax? 202 ■ W jaki sposób sieć uczy się reprezentacji wektorowej? 203 ■ Odnajdywanie wektorów słów za pomocą algebry liniowej 205 ■ Podejście CBoW 205 ■ Skip-gram a CBoW. Kiedy korzystać z którego podejścia? 207 ■ Triki obliczeniowe Word2vec 207 ■ Częste bigramy 207 ■ Podpróbkowanie często występujących tokenów 208 ■ Próbkowanie negatywne 209
6.2.3. Jak korzystać z modułu gensim.word2vec 209
6.2.4. Jak wygenerować własne reprezentacje wektorów słów 212
Kroki przetwarzania wstępnego 212 ■ Szkolenie dziedzinowego modelu Word2vec 213
6.2.5. Word2vec a GloVe (Global Vectors) 214
6.2.6. fastText 215
Jak korzystać z gotowych modeli fastText 216
6.2.7. Word2vec a LSA 216
6.2.8. Wizualizacja związków między słowami 217
6.2.9. Nienaturalne słowa 224
6.2.10. Doc2vec i podobieństwo dokumentów 225
Jak wyuczyć wektory dokumentów 226
7. Kolejność słów i konwolucyjne sieci neuronowe (CNN) 228
7.1. Uczenie się znaczenia 230
7.2. Zestaw narzędzi 232
7.3. Konwolucyjne sieci neuronowe 233
7.3.1. Elementy składowe 233
7.3.2. Długość kroku 235
7.3.3. Budowa filtra 235
7.3.4. Uzupełnianie 237
Potok konwolucyjny 238
7.3.5. Uczenie 238
7.4. Zaiste, wąskie okna 239
7.4.1. Implementacja w Kerasie: przygotowanie danych 240
7.4.2. Architektura konwolucyjnej sieci neuronowej. 247
7.4.3. Warstwa łącząca (pooling) 247
7.4.4. Dropout 250
7.4.5. Wisienka na torcie 251
Optymalizacja 252 ■ Dopasowanie (fit) 252
7.4.6. Czas zabrać się za naukę (trening) 253
7.4.7. Użycie modelu w potoku 255
7.4.8. Gdzie pójdziecie dalej? 256
8. Zapętlone (rekurencyjne) sieci neuronowe (RNN) 259
8.1. Zapamiętywanie za pomocą sieci rekurencyjnych 262
8.1.1. Propagacja wsteczna przez czas 267
Tl;Dr – Krótka rekapitulacja 269
8.1.2. Kiedy i co aktualizować? 269
Czy jednak obchodzi was to, co wyszło z wcześniejszych kroków? 270
8.1.3. Rekapitulacja 271
8.1.4. Zawsze jest jakiś haczyk 272
8.1.5. Rekurencyjne sieci neuronowe z Kerasem 272
8.2. Składanie w całość 277
8.3. Nauczmy się czegoś o przeszłości 279
8.4. Hiperparametry 279
8.5. Przewidywanie 283
8.5.1. Stanowość 284
8.5.2. Ulica dwukierunkowa 284
8.5.3. Co to takiego? 286
9. Lepsza pamięć dzięki sieciom LSTM 288
9.1. LSTM 290
9.1.1. Propagacja wsteczna przez czas 299 W praktyce 299
9.1.2. Próba ognia 301
9.1.3. Brudne dane 303
9.1.4. Powrót do brudnych danych 306
9.1.5. Słowa są trudne. Litery są prostsze 307
9.1.6. Kolej na rozmowę 312
9.1.7. Zwrot ku klarownej mowie 314 Zwiększanie użyteczności generatora 322
9.1.8. Jak mówić i co mówić 322
9.1.9. Inne rodzaje pamięci 322
9.1.10. Idąc głębiej 323
10. Modele ciąg-ciąg i uwaga (attention) 326
10.1. Architektura koder-dekoder 327
10.1.1. Dekodowanie myśli 328
10.1.2. Wygląda znajomo? 330
10.1.3. Konwersacja ciąg-ciąg 332
10.1.4. Powtórzenie LSTM 332
10.2. Składanie potoku ciąg-ciąg 334
10.2.1. Przygotowanie naszego zbioru danych do szkolenia ciąg-ciąg 334
10.2.2. Model ciąg-ciąg w Kerasie 335
10.2.3. Koder ciągów 336
10.2.4. Koder myśli 337
10.2.5. Składanie sieci ciąg-ciąg 338
10.3. Szkolenie sieci ciąg-ciąg 339
10.3.1. Generowanie ciągów wyjściowych 340
10.4. Budowanie chatbota przy użyciu sieci ciąg-ciąg 341
10.4.1. Przygotowanie korpusu do szkolenia 342
10.4.2. Budowanie słownika znaków 343
10.4.3. Generowanie zbiorów treningowych zakodowanych metodą 1 z n 343
10.4.4. Uczenie chatbota ciąg-ciąg 344
10.4.5. Składanie modelu do generowania ciągów 345
10.4.6. Przewidywanie ciągu 345
10.4.7. Generowanie odpowiedzi 346
10.4.8. Rozmowa z waszym chatbotem 347
10.5. Ulepszenia 347
10.5.1. Redukcja złożoności treningu za pomocą sortowania danych (bucketing) 347
10.5.2. Uwaga (attention) 348
10.6. W świecie rzeczywistym 350
CZĘŚĆ 3 ■ PRZEJŚCIE DO RZECZYWISTOŚCI (PRAWDZIWE PROBLEMY NLP) 353
11. Ekstrakcja informacji (rozpoznawanie jednostek nazewniczych i odpowiadanie na pytania) 355
11.1. Jednostki nazewnicze i relacje 356
11.1.1. Baza wiedzy 356
11.1.2. Ekstrakcja informacji 359
11.2. Regularne wzorce 359
11.2.1. Wyrażenia regularne 360
11.2.2. Ekstrakcja informacji jako ekstrakcja cech z wykorzystaniem uczenia się maszyn 361
11.3. Informacje warte wyodrębnienia 363
11.3.1. Ekstrakcja lokalizacji GPS 363
11.3.2. Ekstrakcja dat 364
11.4. Wyodrębnianie relacji 369
11.4.1. Znakowanie częściami mowy 370
11.4.2. Normalizacja jednostek nazewniczych 374
11.4.3. Normalizacja i wyodrębnianie relacji 375
11.4.4. Wzorce słów 375
11.4.5. Segmentacja 376
Segmentacja na zdania 377
11.4.6. Dlaczego split('.!?') nie będzie działać? 377
11.4.7. Segmentacja na zdania za pomocą wyrażeń regularnych 378
12.2. Podejście polegające na dopasowaniu do wzorców 391
12.2.1. Chatbot oparty na dopasowaniu do wzorca i AIML 392
AIML 1.0 393 ■ Interpreter AIML w Pythonie 394
12.2.2. Sieciowe spojrzenie na dopasowanie do wzorców 399
12.3. Oparcie na wiedzy 400
12.4. Wyszukiwanie 402
12.4.1. Problem kontekstu 403
12.4.2. Przykładowy chatbot oparty na wyszukiwaniu danych 404
12.4.3. Chatbot oparty na wyszukiwaniu 408
12.5. Modele generatywne 410
12.5.1. Czat na temat NLPIA 411
12.5.2. Zalety i wady każdego podejścia 413
12.6. Napęd na cztery koła 414
12.6.1. Will osiąga sukces 414
Instalowanie Willa 414 ■ Hello WILL 414
12.7. Proces projektowania 415
12.8. Sztuczki 418
12.8.1. Zadawanie pytań z przewidywalnymi odpowiedziami 418
12.8.2. Bycie zabawnym 419
12.8.3. Gdy wszystko inne zawiedzie, trzeba wyszukać 419
12.8.4. Bycie popularnym 419
12.8.5. Być łącznikiem 420
12.8.6. Stawanie się emocjonalnym 420
12.9. W świecie rzeczywistym 420
13. Skalowanie (optymalizacja, zrównoleglanie i przetwarzanie wsadowe) 422
13.1. Zbyt wiele dobrego (danych) 423
13.2. Optymalizowanie algorytmów NLP 423
13.2.1. Indeksowanie 424
13.2.2. Zaawansowane indeksowanie 425
13.2.3. Zaawansowane indeksowanie za pomocą Annoy 427
13.2.4. Po co w ogóle stosować indeksy przybliżone? 432
13.2.5. Obejście indeksowania: dyskretyzacja 433
13.3. Algorytmy ze stałą pamięcią RAM 434
13.3.1. Gensim 434
13.3.2. Obliczenia graficzne 435
13.4. Zrównoleglanie waszych obliczeń NLP 436
13.4.1. Trenowanie modeli NLP na procesorach graficznych (GPU) 436
13.4.2. Wynajem a kupno 438
13.4.3. Opcje wynajmu GPU 438
13.4.4. Jednostki przetwarzania tensorowego 439
13.5. Zmniejszanie zużycia pamięci podczas trenowania modeli 440
13.6. Uzyskiwanie wglądu w model za pomocą TensorBoard 442
13.6.1. Jak wizualizować zanurzenia słów 443
dodatek A Nasze narzędzia NLP 447
dodatek B Swawolny Python i wyrażenia regular ne 455
dodatek C Wektor y i macierze (podstawy algebry liniowej) 461
dodatek D Narzędzia i techniki uczenia się maszyn 467
dodatek E Ustawianie własnego AWS GPU 481
dodatek F Mieszanie wrażliwe na lokalizację (LSH) 495
źródła 503
słownik 513
indeks 520
posłowie do wydania polskiego 535
o książce
Przetwarzanie języka naturalnego w akcji to praktyczny przewodnik po przetwarzaniu i generowaniu tekstu w języku naturalnym w realnym świecie. W książce tej dajemy wam wszystkie narzędzia i techniki potrzebne do zbudowania backendowych systemów NLP do obsługi wirtualnego asystenta (chatbota/agenta dialogowego), filtra spamu, moderatora forum, systemu do analizy wydźwięku, generatora baz wiedzy, analizatora tekstów języka naturalnego i każdego innego zastosowania NLP, jakie możecie sobie wyobrazić. Książka ta jest skierowana do deweloperów Pythona, od średnio zaawansowanych do zaawansowanych. Dla czytelników, którzy już umieją projektować i tworzyć złożone systemy, książka także będzie przydatna, gdyż daje wiele przykładów dobrych praktyk oraz wgląd w możliwości najnowszych algorytmów NLP. Wiedza na temat programowania obiektowego w Pythonie będzie przydatna do budowy lepszych systemów, ale nie jest wymagana przy nauce z tej książki.
W przypadku specjalnych tematów podajemy odpowiednią ilość materiału pomocniczego i cytujemy zasoby (tekstowe i online) dla tych, którzy chcą szczegółowo się z nimi zapoznać.
Plan działania
Osoby nieznające Pythona i przetwarzania języka naturalnego powinny najpierw przeczytać część 1, a potem dowolne rozdziały z części 3, które związane są z ich zainteresowaniami lub wyzwaniami w pracy. Jeśli chcecie przyśpieszyć zdobywanie nowych możliwości NLP, na które pozwala deep learning, będziecie chcieli przeczytać po kolei część 2. Buduje ona zrozumienie sieci neuronowych, przyrostowo zwiększając złożoność i możliwości sieci neuronowych.
Gdy znajdziecie rozdział lub część z fragmentem programu, który możecie „uruchomić w głowie”, powinniście wykonać go na swoim komputerze. A jeśli jakieś przykłady
wyglądają, jakby można je było zastosować w swoich dokumentach, powinniście wstawić ten tekst do CSV lub do pliku tekstowego (jeden dokument w wierszu) w katalogu nlpia/src/nlpia/data/. Wtedy możecie użyć funkcji nlpia.data.loaders.get_data() do uzyskania tych danych i wykonania przykładów na swoich danych.
O książce
Rozdziały z części 1 dotyczą logistyki pracy z językiem naturalnym i przekształcania go w liczby, które można wyszukiwać i obliczać. To „tworzenie bloków i chwytanie” słów daje nagrodę w postaci zadziwiająco użytecznych aplikacji, jak wyszukiwanie informacji i analiza wydźwięku. Gdy już dobrze opanujecie podstawy, okaże się, że już przy użyciu prostej arytmetyki wykonywanej w pętli można rozwiązać niektóre dość skomplikowane problemy, jak filtrowanie spamu. Filtry spamu, które zbudujecie w rozdziałach od 2 do 4, są tym, co ocaliło globalny system e-mailowy przed anarchią i stagnacją. Dowiecie się, jak tworzyć filtry spamu o dokładności ponad 90% za pomocą technologii z ery lat dziewięćdziesiątych – obliczając jedynie liczbę słów i proste średnie tych liczb.
Cała ta matematyka dotycząca słów może wydawać się uciążliwa, ale w istocie to dość dobra zabawa. Bardzo szybko będziecie budować algorytmy, które będą mogły podejmować decyzje dotyczące języka naturalnego tak samo dobrze lub lepiej niż my sami (a na pewno dużo szybciej). Może to być pierwszy raz w waszym życiu, gdy będziecie mieli perspektywę, aby ocenić w pełni sposób, w jaki słowa odzwierciedlają i wzmacniają wasze myślenie. Spojrzenie na słowa i myśli przez perspektywę wielowymiarowej przestrzeni wektorowej pozostawi nasz mózg w ruchu w rekurencyjnych pętlach samo-odkrywania. Tempo nauki może osiągnąć najwyższy punkt w połowie książki. Rdzeniem książki w części 2 jest poznawanie skomplikowanej sieci obliczeń i komunikacji z sieciami neuronowymi. Sieciowy efekt małych jednostek logicznych w interakcji z siecią „myślenia” dał maszynom moc rozwiązywania problemów, którymi w przeszłości zajmowali się tylko ludzie, obejmując takie elementy jak pytania o analogie, streszczanie tekstu i tłumaczenia między językami naturalnymi.
W miarę nauki poznacie wektory słów, ale bez obaw, o wiele więcej. Będziecie w stanie dokonać wizualizacji słów, dokumentów i zdań w chmurze powiązanych pojęć, rozciągającej się znacznie poza trzy wymiary, które jesteśmy gotowi ogarnąć. Zaczniecie myśleć o dokumentach i słowach jak o postaciach w grze Dungeons and Dragons, z miriadą losowo wybranych charakterystyk i zdolności, które wyewoluowały i urosły z biegiem czasu, lecz tylko w naszych głowach.
Docenienie tego wielotematycznego świata słów i ich znaczenia stanie się podstawą do coup-de-grace z części 3, gdzie nauczycie się, jak budować maszyny, które prowadzą konwersację i odpowiadają na pytania tak samo dobrze jak ludzie.
O kodzie
Książka zawiera wiele przykładów kodu źródłowego zarówno w ponumerowanych listingach, jak i w wierszach normalnego tekstu. W obu przypadkach kod jest zapisany czcionką o stałej szerokości (jak ta) i oddzielony od reszty tekstu. Czasami kod jest także
xxxi o książce
pogrubiony, aby podkreślić zmiany w stosunku do poprzednich kroków w rozdziale, jak w przypadku dodania nowej funkcji w istniejącym wierszu kodu.
W wielu przypadkach oryginalny kod źródłowy został przeformatowany. Przełamaliśmy wiersze i dodaliśmy wcięcia, aby dostosować do dostępnej szerokości kolumny. W rzadkich przypadkach nawet to nie wystarczyło i listingi zawierają znaczniki kontynuacji kodu (➥). Ponadto w przypadkach, gdy kod jest opisany w tekście, komentarze z kodu źródłowego zostały usunięte z listingów. Wielu listingom towarzyszą adnotacje kodu, aby uwypuklić ważne pojęcia.
Kod źródłowy wszystkich listingów z tej książki jest dostępny do pobrania z witryny wydawnictwa Manning pod adresem https://www.manning.com/books/naturallanguage-processingin-action oraz na GitHub pod adresem https://github.com/ totalgood/nlpia.
Forum dyskusyjne liveBook
Zakupienie tej książki obejmuje bezpłatny dostęp do prywatnego forum sieciowego prowadzonego przez Manning Publications, gdzie możecie komentować książkę, zadawać pytania techniczne i otrzymać pomoc od autorów i innych użytkowników. Aby mieć dostęp do forum, trzeba wejść na stronę https://livebook.manning.com/#!/book/ natural-languageprocessing-in-action/discussion. Więcej o forum Manninga i obowiązujących tam zasadach można się dowiedzieć na stronie https://livebook.manning. com/#!/discussion.
Manning zobowiązuje się zapewnić czytelnikom forum, na którym może mieć miejsce sensowny dialog między czytelnikami oraz między czytelnikami a autorami. Nie jest to zobowiązanie do konkretnego stopnia zaangażowania ze strony autorów, których udział w forum jest dobrowolny (i bezpłatny). Sugerujemy, aby zadawać autorom trudne pytania, co przyciągnie ich uwagę! Forum i archiwa zawierające wcześniejsze dyskusje są dostępne na witrynie wydawcy od chwili wydrukowania tej książki.
Matematyka na słowach (wektory TD-IDF)
Tematyka rozdziału
¡ Zliczanie słów i określanie częstości terminów w celu analizowania znaczenia
¡ Przewidywanie prawdopodobieństwa występowania słowa za pomocą prawa Zipfa
¡ Co to jest wektorowa reprezentacja słów i jak zacząć jej używać
¡ Znajdowanie właściwych dokumentów w korpusie za pomocą odwróconej częstości w dokumentach (inverse document frequencies, IDF)
¡ Przewidywanie podobieństwa par dokumentów za pomocą podobieństwa cosinusowego i Okapi MB25
3
Po zebraniu i policzeniu słów (tokenów) oraz pogrupowaniu ich na rdzenie i lematy nadszedł czas na zrobienie z nimi czegoś ciekawego. Wykrywanie słów jest użyteczne w prostych zadaniach, jak statystyka używania słów czy wyszukiwanie na podstawie słów kluczowych. Ale chcielibyście też wiedzieć, które słowa w określonym dokumencie
rozdział 3 Matematyka na słowach (wektory TD-IDF)
i w korpusie jako całości są ważne. Wtedy możecie użyć tej wartości „ważności” do zna lezienia właściwych dokumentów w korpusie na podstawie znaczenia słów kluczowych w każdym dokumencie.
To sprawi, że wykrywacz spamu będzie mniej podatny na potknięcie się na jednym przekleństwie lub bliskich spamu słowach w waszym emailu. I chcielibyście też zmie rzyć, na ile pozytywny i prospołeczny jest tweet, gdy mamy szeroki zakres słów z różnymi stopniami wyniku „pozytywności” i różnymi etykietami. Jeśli macie pojęcie o częstości, z jaką te słowa pojawiają się w dokumencie względem reszty dokumentów, możecie to wykorzystać do dalszego udoskonalenia „pozytywności” dokumentu. W tym rozdziale poznacie bardziej zróżnicowane, mniej binarne miary słów i ich użycia w dokumencie. To podejście od dziesięcioleci stało się filarem wydobywania cech z języka naturalnego dla komercyjnych wyszukiwarek i filtrów spamu. Kolejnym krokiem waszej przygody jest przekształcenie słów z rozdziału 2 w liczby rze czywiste zamiast liczb całkowitych reprezentujących liczniki słów lub binarne „wektory bitowe”, które wykrywają obecność lub nieobecność określonych słów. Mając reprezen tację słów w ciągłej przestrzeni, możecie działać na ich reprezentacji za pomocą znacz nie ciekawszej matematyki. Waszym celem jest znalezienie numerycznej reprezentacji słów, która w jakiś sposób uchwyci ważność lub zawartość informacyjną reprezentowa nych słów. Będziecie musieli poczekać do rozdziału 4, aby zobaczyć, jak przekształcić tę zawartość informacyjną w liczby reprezentujące znaczenie słów.
W tym rozdziale przyglądamy się trzem coraz mocniejszym sposobom reprezento wania słów i ich wagi w dokumencie. Są to:
¾ wektory BoW – wektory liczników częstości słów;
¾ wektory pojemników na n gramy – liczniki par słów (bigramów), trójek (trigramów) i tak dalej;
¾ wektory TF-IDF – wektory wartości liczbowych przypisywanych słowom w sposób, który lepiej reprezentuje ich znaczenie.
WAŻNE TF IDF to skrót od częstość słowa razy odwrotność częstości w dokumentach (term frequency times inverse document frequency). Częstości słów jest określona liczbą wystą pień każdego słowa w dokumencie, które poznaliście w poprzednich rozdziałach.
Odwrotna częstość w dokumentach oznacza, że dzielicie każdą z tych liczb słów przez liczbę dokumentów, w których słowo występuje.
Każdą z tych technik można zastosować oddzielnie lub jako część potoku NLP. Są to modele statystyczne, gdyż opierają się na częstości. W dalszej części książki poznacie różne sposoby głębszego zajrzenia w związki między słowami, w ich wzorce i nieliniowości. Ale te „płytkie” systemy NLP są mocne i użyteczne w wielu praktycznych zastosowa niach, jak filtrowanie spamu i analiza wydźwięku.
3.1.
Wektor BoW
W poprzednim rozdziale utworzyliście pierwszy model tekstu w przestrzeni wektorowej. Zastosowaliście kodowanie 1 z n dla każdego słowa, a następnie połączyliście wszystkie
te wektory za pomocą binarnego działania OR, aby utworzyć wektorową reprezentację tekstu. I ten binarny wektor BoW tworzy wielki indeks do wyszukiwania dokumentów, gdy pobierzemy go do struktury danych jak Pandas DataFrame. Potem przyjrzeliście się jeszcze bardziej użytecznej reprezentacji wektorowej, która zlicza liczbę wystąpień, czyli częstość, każdego słowa w danym tekście. Jako pierwsze przybliżenie zakładacie, że im więcej razy występuje dane słowo, tym więcej znacze nia musi ono wnosić do dokumentu. Dokument, który odwołuje się często do „wings” i „rudder” (skrzydła i ster) może być bardziej właściwy dla problemu związanego z odrzu towcami czy podróżami powietrznymi niż powiedzmy dokument, w którym często jest mowa o „cats” i „gravity” (kotach i grawitacji). Lub jeśli klasyfikujecie słowa wyraża jące pozytywne emocje – słowa jak „good”, „best”, „joy” i „fantastic” (dobry, najlepszy, radość, fantastyczny) – dokument zawierający więcej tych słów zapewne będzie wyrażał pozytywne nastawienie. Możecie sobie jednak wyobrazić, jak algorytm oparty na tych prostych zasadach może być mylący lub zagubiony.
Popatrzmy na przykład, w którym liczenie wystąpień słowa jest użyteczne:
>>> from nltk.tokenize import TreebankWordTokenizer
>>> sentence = """The faster Harry got to the store, the faster Harry, ... the faster, would get home."""
Mając swoją prostą listę, chcecie pobrać z dokumentu unikatowe słowa i ich liczniki. Słownik Pythona służy dobrze do tego celu, a ponieważ chcecie także liczyć słowa, może cie podobnie jak w poprzednich rozdziałach użyć Counter:
Jak w każdym dobrym słowniku Pythona kolejność kluczy została wymieszana. Nowa kolejność jest zoptymalizowana pod kątem pamięci, aktualizacji i znajdowania danych, a nie ze względu na wyświetlanie. Zawartość informacyjna w kolejności słów z oryginal nego zdania została odrzucona.
UWAGA Obiekt collections.Counter to nieuporządkowana kolekcja, nazywana także wielozbiorem. Zależnie od waszej platformy i wersji Pythona, może okazać się, że Counter jest wyświetlany w całkiem sensownej kolejności, jak kolejność leksykalna lub według tokenów pojawiających się w zdaniu. Ale w standardowym dict Pythona nie możecie polegać na kolejności tokenów (kluczy w Counter).
Dla krótkich dokumentów jak ten nieuporządkowany wektor BoW nadal zawiera wiele informacji o oryginalnym sensie zdania. A informacje w tym wektorze BoW wystarczają do wykonania takich rzeczy jak wykrywanie spamu, wyznaczenie wydźwięku (pozytyw nego nastawienia, szczęścia itp.), a nawet na wykrycie subtelnych intencji jak sarkazm. Może jest to wektor BoW, lecz jest pełen znaczenia i informacji. Wprowadźmy więc ranking tych słów – posortujmy w jakiejś kolejności, o której jest łatwiej myśleć. Obiekt Counter ma własnie do tego celu wygodną metodę, most_common: >>> bag_of_words.most_common(4) [('the', 4), (',', 3), ('faster', 3), ('harry', 2)] Konkretnie, liczba wystąpień słowa w danym dokumencie jest nazywana częstością słowa i często używa się skrótu TF (term frequency). W niektórych przykładach możecie zoba czyć licznik wystąpień słowa znormalizowany (podzielony) przez liczbę wszystkich słów w dokumencie1.
Domyślnie most_common wypisuje wszyskie tokeny, od najczęstszego do występującego najrzadziej, ale tu ograniczyliście listę do czterech najważniejszych.
Tak więc cztery główne pojęcia, czyli tokeny, to „The”, „,”, „harry” i „faster”. Ale słowo „the” oraz znak interpunkcji „,” nie niosą wiele informacji o zamyśle tego doku mentu. A te nieinformacyjne tokeny będą pojawiać się często podczas waszej szybkiej przygody. Więc na potrzeby tego przykładu zignorujecie je, razem z resztą stop listy stan dardowych angielskich słów i znaków przestankowych. Nie zawsze tak będzie, ale teraz pomaga w uproszczeniu przykładu. To pozostawia „harry” i „faste” wśród najczęstszych tokenów w waszym wektorze TF (BoW).
1 Jednak znormalizowana częstość jest naprawdę prawdopodobieństwem, więc zapewne nie powinna być nazywana częstością.
9.1.1. Propagacja wsteczna przez czas
No więc jak to całe ustrojstwo się uczy? Dzięki propagacji wstecznej – tak jak każda inna sieć neuronowa. Cofnijmy się na chwilę i spójrzmy na problem, który próbujecie rozwiązać za pomocą tej nowej złożoności. Zwykły RNN jest podatny na problem znikającego gradientu, ponieważ pochodna w danym kroku czasowym jest uzależniona od samych wag, więc cofając się w czasie i łącząc różne delty, po kilku iteracjach wagi (i współczynnik szybkości uczenia się) mogą zmniejszyć gradient aż do 0. Aktualizacja wag na końcu propagacji wstecznej (co byłoby równoznaczne z początkiem ciągu) jest albo minimalna, albo efektywnie wynosi 0. Podobny problem występuje, gdy wagi są dość duże: gradient eksploduje i rośnie nieproporcjonalnie do sieci.
LSTM unika tego problemu dzięki samemu stanowi pamięci. Neurony w każdej bramce są aktualizowane za pomocą pochodnych funkcji, do których wpuszczono ich wyjście, a mianowicie tych, które aktualizują stan pamięci przy przejściu do przodu. Tak więc w każdym kroku czasowym, ponieważ normalna reguła łańcuchowa jest stosowana wstecz do propagacji w przód, aktualizacje neuronów zależą tylko od stanu pamięci w tym kroku czasowym i w kroku poprzednim. W ten sposób błąd całej funkcji jest utrzymywany „bliżej” neuronów dla każdego kroku czasowego. Nazywa się to karuzelą błędu. w Praktyce
A więc jak to działa w praktyce? Dokładnie tak, jak proste RNN znane z poprzedniego rozdziału. Wszystko, co zmieniliście, to wewnętrzny sposób działania czarnej skrzynki, która jest warstwą rekurencyjną w sieci. Możecie więc po prostu wymienić warstwę SimpleRNN Kerasa na warstwę LSTM Kerasa, a wszystkie inne elementy klasyfikatora pozostaną takie same.
Wykorzystacie ten sam zbiór danych, przygotowany w ten sam sposób: tokenizujecie teksty i wektoryzujecie je przy użyciu Word2vec. Następnie ponownie uzupełniacie/ obcinacie ciągi do 400 tokenów, z których każdy używa funkcji, które zdefiniowaliście w poprzednich rozdziałach. Spójrzcie na następny listing.
Listing 9.2. Ładowanie i przygotowanie danych z IMDB
>>> with open("lstm_model1.json", "w") as json_file: ... json_file.write(model_structure)
>>> model.save_weights("lstm_weights1.h5")
Zapiszcie jego strukturę, byście nie musieli robić tej części ponownie.
Jest to ogromny skok, jeśli chodzi o dokładność walidacji w porównaniu z prostym RNN zaimplementowanym w rozdziale 8 przy użyciu tego samego zestawu danych. Możecie zacząć dostrzegać, jak duży zysk jesteście w stanie osiągnąć, wyposażając model w pamięć, gdy związki tokenów są tak ważne. Piękno tego algorytmu polega na tym, że uczy się on związków między tokenami, które widzi. Sieć jest teraz w stanie wymodelować te relacje, szczególnie w sposób, który motywowany jest wybranym przez was zadaniem i funkcją kosztu.
Jak blisko jesteście w tym przypadku poprawnej identyfikacji pozytywnego lub negatywnego wydźwięku? Jasne, jest to wąski podobszar o wiele poważniejszego problemu w przetwarzaniu języka naturalnego. Jak na przykład można by modelować humor, sarkazm lub niepokój? Czy można je modelować razem? To zdecydowanie obszar, w którym toczą się intensywne badania. Jednak prowadzenie prac nad każdym z tych zagadnień osobno, choć wymaga dużej ilości ręcznie etykietowanych danych (a każdego dnia jest ich więcej), jest z pewnością realną ścieżką, a umieszczanie tego rodzaju dyskretnych klasyfikatorów w waszym potoku jest pełnoprawnym sposobem postępowania w gęstej przestrzeni problemów.
9.1.2. Próba ognia
Ta część jest zabawna. Mając wyszkolony model, możecie zacząć wypróbowywać różne przykładowe frazy i sprawdzać skuteczność modelu. Spróbujcie go oszukać. Użyjcie radosnych słów w negatywnym kontekście. Spróbujcie fraz długich, krótkich, sprzecznych. Zerknijcie na listingi 9.6 i 9.7.
Listing 9.6. Ponowne załadowanie waszego modelu LSSTM
>>> from keras.models import model_from_json
>>> with open("lstm_model1.json", "r") as json_file:
... json_string = json_file.read()
>>> model = model_from_json(json_string)
>>> model.load_weights('lstm_weights1.h5')
posłowie do wydania polskiego
dr Łukasz Kobyliński, Ryszard Tuora
P.1. Wprowadzenie
Dotychczas przetwarzanie języka naturalnego było omawiane na przykładzie języka angielskiego. Ogromna większość przedstawionych koncepcji, problemów i sposobów ich rozwiązania ma zastosowanie również w przypadku przetwarzania innych języków. Istnieje jednak wiele wyzwań w NLP, które są specyficzne dla danego języka. Jest to naturalne: w oczywisty sposób nieco inaczej podeszlibyśmy do przetwarzania języków zapisywanych za pomocą alfabetu, a inaczej tych, których zapis wykonywany jest piktograficznie (pismem obrazkowym). Na szczęście w przypadku języka polskiego nie mamy do czynienia z aż tak wielkimi różnicami w stosunku do prezentowanych w książce podejść i przykładów dotyczących języka angielskiego. Te różnice, które są istotne dla automatycznego przetwarzania języka naturalnego, dotyczą zjawisk na kilku poziomach opisu języka, do których odniesiemy się w tym posłowiu, aby wskazać możliwe problemy i sposoby ich rozwiązywania.
Jedną z najistotniejszych dla zastosowania metod NLP różnic jest kwestia budowy słów w języku polskim. Język ten jest przedstawicielem grupy języków zachodniosłowiańskich, które charakteryzują się bogatą fleksją, a zatem słowa powstają z pewnej podstawy morfologicznej i końcówki fleksyjnej, co skutkuje dużym zróżnicowaniem form ortograficznych poszczególnych leksemów. Na przykład: rzeczownik brat odmienia się oczywiście przez przypadki i liczby i przyjmuje wówczas takie formy jak: brata, bratem, ale też bracia, braci, braćmi. Zachodzi zatem tzw. wymiana w temacie i formy odmienione nie są już łatwo porównywalne ortograficznie z formą podstawową. Ten poziom analizy językowej reprezentowany jest w przypadku NLP przez metody analizy i znakowania morfostyntaktycznego, a także stemmingu czy lematyzacji i metody te dosyć znacznie różnią się od metod, które można zastosować w przypadku języka angielskiego.
Na poziomie opisu morfologicznego słów mamy też do czynienia z problemem segmentacji słów. Dla języka polskiego istnieje wiele przypadków niejednoznaczności podziału ciągu znaków na poszczególne tokeny, które będą podlegać dalszemu przetwarzaniu. Niejednoznaczności te muszą być rozwiązywane na podstawie analizy kontekstu (często szerszego niż zdanie). Przykładem takiej niejednoznaczności jest ciąg znaków Coś w zdaniu Coś zrobił? Zdanie to ma dwie interpretacje zależne od sposobu przeprowadzenia segmentacji, co jest pokazane na rysunku P.1.
Rysunek P.1. Przykład niejednoznaczności segmentacyjnej dotyczącej ciągu znaków Coś w zdaniu Coś zrobił?
Źródło: na podstawie instrukcji Morfeusza:- http://download.sgjp.pl/morfeusz/Morfeusz2.pdf.
W pierwszej interpretacji słowo coś traktujemy jako całość, a więc rzeczownik, który nadaje zdaniu sens pytania o to, czy osoba, o którą pytamy, „coś zrobiła”, czy wykonała jakąś rzecz/czynność (por. Czy [on] coś zrobił?). W drugiej interpretacji słowo coś jest zbitkiem dwóch leksemów: leksemu co oraz leksemu być i wówczas zdanie nabiera znaczenia zapytania naszego rozmówcy o to, co ten właśnie rozmówca zrobił (por. Co zrobiłeś?)
Inną, istotną dla NLP różnicą między językiem polskim a językiem angielskim jest swobodny szyk zdań. W przypadku języka angielskiego szyk ten jest ustalony i realizowany według schematu SVO, a więc subject-verb-object (podmiot-orzeczenie-dopełnienie).
W języku polskim taki szyk również jest najczęstszy, natomiast nie ma przeciwskazań, aby zdania tworzyć w zupełnie innej kolejności elementów (por. John loves Mary oraz Jan kocha Marię, ale też Jan Marię kocha, czy Marię kocha Jan).
Łącznie wspomniane wyżej trudności w analizie języka polskiego składają się na wiele poziomów niejednoznaczności, które są głównym problemem w zastosowaniu jakichkolwiek metod automatycznej analizy i przetwarzania danych. Niejednoznaczności te muszą być rozwiązywane na każdym z poziomów z możliwie dużą dokładnością, ponieważ błędy z wcześniejszych etapów przetwarzania mają wpływ na dokładność tych etapów, które realizowane są w kolejnych krokach potoku przetwarzania.
Na koniec krótka uwaga techniczna. W przykładach poniżej używamy – podobnie jak autorzy książki – pakietu spaCy, który w łatwy sposób umożliwia realizowanie wielu zadań związanych z przetwarzaniem języka naturalnego. W chwili pisania tego tekstu istnieją co najmniej dwa modele języka polskiego do spaCy: model oficjalny, ogłoszony przez twórców spaCy latem 20201, oraz model przygotowany przez IPI PAN jesienią 1 https://spacy.io/models/pl.