Skocz do zawartości
kampo

Wstęp do przetwarzania języka naturalnego – klasyfikacja tekstu

Pomocna odpowiedź

Napisano (edytowany)

Witajcie, w artykule zajmiemy się klasyfikacją tekstu z wykorzystaniem sieci neuronowej. W kontekście robotyki, klasyfikacji możemy użyć w sterowaniu robotem za pomocą języka naturalnego.  Przykład można zobaczyć w wątku AgeBot. Przetwarzanie języka naturalnego (NLP) jest obszernym tematem, dlatego nie będziemy wdawać się zbytnio w szczegóły, ale przedstawię ogólną koncepcję i narzędzia przydatne do przetwarzania tekstu - da Wam punkt startowy w tej ciekawej dziedzinie 🙂 

Aby utrzymać artykuł we w miarę któtkiej formie zawierającej samo „mięso” założę, że Python jest Wam znany. Będziemy przetwarzać zdania w języku angielskim, który jest jednym z łatwiejszych języków w NLP. Język polski jest problematyczny (chociaż do niego też są narzędzia), więcej można dowiedzieć się z tego filmu.

Niniejszy artykuł objaśni bardziej proces normalizacji tekstu, da Wam informacje czego dalej szukać oraz pokaże jak klasyfikacja tekstu z grubsza działa. Konkretną implementację udostępniłem na GitHubie (link), którą możecie traktować jako bazę, aby zrobić podobne sterowanie w Waszych robotach 🙂 Polecam jednak przestudiować podlinkowany przykład kodu, aby dokładniej zrozumieć, co tam się dzieje lub rozwiać wątpliwości po przeczytaniu poniższych akapitów.

 

Zacznijmy od początku

Wspomniałem o sieci neuronowej, ale co to właściwie jest i jak ona działa? Polecam ten film. Wiedza jak działa sieć neuronowa nie jest jednak niezbędna, aby korzystać z powyższego kodu 🙂 

Jeśli korzystacie w swoich robotach z Raspberry PI, spokojnie powinniście bez problemu wykonywać poniższe czynności oraz uruchomić przykładowy kod na tejże platformie. Zainstalujmy potrzebne zależności:

pip3 install tensorflow nltk tflearn numpy

Tensorflow jest biblioteką, dzięki której możemy budować modele uczenia maszynowego. Tflearn jest nakładką, która ułatwia korzystanie z Tensorflow. Z Numpy korzystać będzie Tensorflow. Nltk natomiast jest biblioteką, która zawiera szereg przydatnych funkcji, jeśli zajmujemy się NLP.

Po zainstalowaniu, przygotujmy bibliotekę nltk do użytku za pomocą konsoli Pythona (po tym kroku można uruchomić skrypt z GitHuba):

import nltk
nltk.download(‘punkt’)

 

Pora na mięso

Jeśli mamy sterować robotem, to przyjmijmy sobie jedno zdanie na którym objaśnię kolejne etapy - niech to będzie „move forward please”. W pierwszym kroku następuje tzw. tokenizacja – podzielenie zdania na mniejsze części, które nazywamy tokenami. W przypadku przyjętego zdania, dostaniemy:

[‘move’, forward’, please’]

Używamy do tego funkcji „word_tokenize” z biblioteki „nltk”. Samo zdanie zostało podzielone na słowa, jednak wynik przy trudniejszych zdaniach będzie wyglądał nieco inaczej. Spróbujmy „robot didn’t move!”.

[‘robot’, did’, nt”, moved’, ‘!’]

Pamiętajmy jednak, że języki mają różne reguły, więc rozbicie zdania za pomocą „spacji” niekoniecznie będzie poprawnym sposobem 🙂 W powyższym „n’t” możemy zastąpić na „not”, gdyż te dwa słowa oznaczają to samo. Jeśli tego nie zrobimy, oba będą traktowane jako dwa osobne słowa, co może zakłócić trafność klasyfikacji. 

Kolejnym krokiem jest stemming. Co to takiego? Jest to redukcja konkretnych słów do ich podstawowych form. Co dzięki stemmingowi osiągamy? Jedną intencję można wyrazić na kilka sposobów, używając różnych odmian danych słów, jednak te zdania nadal oznaczają jedno. Istnieje wiele algorytmów, możecie pobawić się nimi tutaj. My użyjemy algorytmu Lancaster, który jest dosyć agresywny. Przykładowo zdanie:

Programmer programmed a program which programs new programs

zostanie zredukowane do formy

program program a program which program new program

Ostatnim krokiem jest normalizacja danych w taki sposób, aby proces był powtarzalny. Tworzymy więc sobie słownik zawierający unikalne słowa, w którym umieszczamy tokeny po stemmingu posortowane wg. alfabetu. Dane treningowe dla modelu, jako że sieć neuronowa pracuje na liczbach, musimy przekształcić... na liczby 🙂 . Zakładając, że nasz słownik już po tokenizacji i stemmingu wygląda następująco:

[‘forward’, mov’, pleas’]

Tworzymy pierwszy wiersz danych trenujących korzystając z przykładów zdań. W naszym przypadku jest jedno zdanie, ale słowo „please” jest właściwie opcjonalne. Bez „please” po prostu będziemy mniej mili 😉 Tworzymy nową tablicę i iterujemy po słowniku. Jeśli napotkamy w nim słowo, które występuje w zdaniu, wstawiamy do nowo utworzonej tablicy 1, w przeciwnym wypadku 0. Ilość elementów w jednym wierszu danych trenujących musi być równa ilości słów w słowniku oraz ich kolejność musi być identyczna, stąd taki zabieg. Uzyskujemy następujące dane treningowe:

Dla zdania „move forward please”: [1, 1, 1]
Dla zdania „move forward”: [1, 1, 0]

Analogicznie postępujemy z danymi wyjściowymi, czyli naszymi klasami. Tworzymy tablicę dostępnych, unikalnych oraz posortowanych alfabetycznie klas. Przyjmijmy, że nasze zdanie będzie sklasyfikowane jako „move” oraz do przykładów dodamy zdanie „hello there” oznaczone klasą „greeting”:

[‘greeting’, move’]

Wyjściem będzie:

Dla zdania „move forward please”: [0, 1]
Dla zdania „move forward”: [0, 1] (to jest ta sama klasa zdania)
Dla zdania „hello there”: [1, 0]

Skupmy się jednak dalej na naszym bazowym zdaniu „move forward please”. Dane trenujące, które uzyskamy w całym tym procesie, czyli:

X = [[1, 1, 1], [1, 1, 0]]
Y = [[0, 1], [0, 1]]

używamy, aby wytrenować sieć neuronową. Po wytrenowaniu, klasyfikując konkretne zdania, proces powtarzamy – sprowadzamy zdanie do liczb i klasyfikujemy.

Gdy mamy już wytrenowany model (sieć), używamy go w celu klasyfikacji nowych (lub tych z przykładów) zdań. Ostatecznie pisząc do robota „move forward please” wiemy, że autorowi chodzi o „move”, ponieważ wyjście sieci neuronowej to prawdopodobieństwo z jaką algorytm jest "pewien" danej klasy. Suma tych liczb, przez użycie funkcji aktywacyjnej "softmax" będzie równać się jeden, niezależnie od ilości klas. Zatem programujemy programujemy robota zależnie od naszych potrzeb 🙂 

W tym artykule to już wszystko. Polecam jeszcze raz, aby zapoznać się z kodem na GitHubie. Jeśli coś było niejasne, chętnie odpowiem na Wasze pytania.

PS: Celowo pominąłem część przykładów z kodem, ponieważ zależnie od tego jakiej biblioteki użyjecie, nazwy funkcji mogą się różnić.

Edytowano przez kampo
  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites

Wszystko fajnie, opisałeś tworzenie modelu dla języka angielskiego (i ogólnie dla języków pozycyjnych). Dla języka polskiego (i ogólnie dla języków fleksyjnych) zastosowanie stemmera usunęłoby praktycznie całą warstwę znaczeniową, pozostawiając "zupę" niezwiązanych ze sobą wyrazów. O ile w prostej klasyfikacji dłuższych tekstów przy założeniu niewielkiej ilości dobrze określonych gatunków i wzięcia jako cel wyłącznie ustalenia przynależności do danego gatunku algorytm pewnie by sobie poradził - o tyle przy klasyfikacji pojedynczych zdań (gdy nie wiadomo, co jest podmiotem, a czasem nawet orzeczeniem zdania) jest to kompletnie nieprzydatne. Czyli inaczej: algorytm będzie w stanie sklasyfikować książki w bibliotece, ale nie będzie umiał zanalizować większości kilkuwyrazowych poleceń.

Pomijam już fakt, że algorytmiczne stemmery dla języka polskiego nie istnieją (a przynajmniej takie, które nadają się do czegoś więcej niż wyszukiwarka w wordpressie), a ich rolę grają rozwiązania słownikowe (np. ispell i pochodne) - dla algorytmu jest to to samo, tym niemniej warto o tym wspomnieć.

Aha, tak poza tym "hello there" nie jest zdaniem, ale to szczegół 🙂

 

  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites

@ethanak rozumiem krytykę, ale nadal dla @kampo należą się podziękowania za to, że zdecydował się napisać artykuł. Oby każdy tak chętnie dzielił się swoimi doświadczeniami. Może dla języka polskiego nie sprawdzi się to zbyt dobrze, ale jak ktoś będzie szukał rozwiązania dla języka angielskiego to start będzie miał dobry 🙂

Udostępnij ten post


Link to post
Share on other sites

Ależ ja nie nic złego chyba nie napisałem 🙂 Sam czekam na to co będzie dalej (a mam nadzieję że będzie, bo to przecież "wstęp") - a jeśli coś będę mógł ze swoich doświadczeń dodać (dla języka polskiego) to mam nadzieję że mnie nikt nie wyklnie...

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites
15 godzin temu, ethanak napisał:

Dla języka polskiego (i ogólnie dla języków fleksyjnych) zastosowanie stemmera usunęłoby praktycznie całą warstwę znaczeniową, pozostawiając "zupę" niezwiązanych ze sobą wyrazów.

Zgadza się, wspomniałem o tym już na początku artykułu, że do języka polskiego - w tym też innych słowiańskich czy fleksyjnych jak napisałeś - należy podejść nieco inaczej.

 

15 godzin temu, ethanak napisał:

Aha, tak poza tym "hello there" nie jest zdaniem, ale to szczegół 🙂

Generalnie pamiętajmy, że jest sporo ludzi, który nie mieli do czynienia z NLP w ogóle. Być może przesadnie używałem słowa "zdanie" i doświadczona osoba w tym obszarze może wskazać wiele uwag, ale chciałem artykuł utrzymać w jak najprostszej formie. Artykuł przedstawia pewne podejście i zawiera kawałek nowej wiedzy, którą trzeba przyswoić, więc aby nie komplikować za bardzo - uprościłem niektóre rzeczy. Jest to też trochę ten przypadek "skończ gadać i pokaż kod" (przynajmniej dla mnie 🙂)

Zakładam, że jeśli kogoś NLP zaintryguje i zacznie drążyć na własną rękę, to prędzej czy później dojdzie do takich wniosków odnośnie przedstawionego tutaj procesu zastosowanego do języka polskiego przykładowo 🙂 

14 godzin temu, ethanak napisał:

Ależ ja nie nic złego chyba nie napisałem 🙂 [...] a jeśli coś będę mógł ze swoich doświadczeń dodać (dla języka polskiego) to mam nadzieję że mnie nikt nie wyklnie...

Nie traktuję tego jako coś złego, dla mnie wszystkie uwagi i konstruktywna krytyka są mile widziane. Dobrze też wiedzieć, że masz z tym doświadczenie 😉 Inna sprawa, że cały czas uczę się przekazywać wiedzę w taki sposób, aby było to zrozumiałe. Także dziękuję za uwagi 🙂 

14 godzin temu, Treker napisał:

Może dla języka polskiego nie sprawdzi się to zbyt dobrze, ale jak ktoś będzie szukał rozwiązania dla języka angielskiego to start będzie miał dobry 🙂

Dokładnie taki był cel 😉 

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Napisz odpowiedź...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...