Celem ćwiczenia jest zapoznanie się z zagadnieniami przetwarzania języka naturalnego i tworzenia bota konwersacyjnego. Narzędziem, które posłuży do wykonania ćwiczenia jest biblioteka NLTK języka Python, zaś podstawą do stworzenia własnego bota będzie EAK - eksperymentalny agent konwersacyjny autorstwa mgr inż. Bartłomieja Forysia.
Etap 1. Instalacja NLTK oraz podstawy języka Python
Zainstaluj Pythona w wersji 2.7.x - http://www.python.org/download/releases/2.7.6/
Zainstaluj NLTK - http://nltk.org/install.html
Ściągnij i zainstaluj dodatkowe dane NLTK - http://nltk.org/data.html
W celu zapoznania się z językiem Python oraz biblioteką NLTK przeczytaj pierwszy rozdział książki: Natural Language Processing with Python Birda, Kleina i Lopera - http://nltk.org/book/. Podrozdziały 1.5, 1.7 i 1.8 możesz pominąć.
Ćwiczenia opisane w książce można wykonywać na co najmniej trzy sposoby:
- pisać całe skrypty i następnie uruchamiać je za pomocą polecenia python mojskrypt.py,
- uruchomić interpreter Pythona (polecenie python bez parametrów) i pisać skrypty bezpośrednio w nim,
- uruchomić Python's Integrated DeveLompent Enviroment (IDLE) i pisać skrypty w interaktywnej konsoli.
Wybierając ostatnie rozwiązanie warto wiedzieć, że w celu uzyskania dostępu do historii komend należy użyć kombinacji klawiszy lewy alt + p oraz, że część komend nie działa w IDLE poprawnie (np. wyświetlanie wykresów) i spowoduje zawieszenie się konsoli.
Etap 2. Podstawowe zagadnienia przetwarzania języka naturalnego
W celu zapoznania się z podstawowymi zagadnieniami dziedziny przetwarzania języka naturalnego (NLP) zapoznaj się z pracą magisterską Statystyczne metody rozumienia i syntezy wypowiedzi języka naturalnego autorstwa mgr inż. Bartłomieja Forysia (http://sequoia.ict.pwr.wroc.pl/~witold/ai/EAK.pdf). Szczególnie uważnie przeczytaj podrozdział 2.4 o analizie gramatycznej wypowiedzi oraz rozdział 4 prezentujący przykłady zastosowań biblioteki NLTK do przetwarzania języka naturalnego (oznaczanie części mowy, segmentacji tekstu i analizie gramatycznej wypowiedzi).
Po poznaniu podstaw zapoznaj się z kolejnymi rozdziałami książki Natural Language Processing with Python (po przeczytaniu wskazanych fragmentów każdego rozdziału warto przeczytać również jego podsumowanie):
Wstęp do rozdziału 5, podrozdziały 5.1 i 5.2 - zawierają one podstawowe informacje o oznaczaniu części mowy, kolejne podrozdziały można pominąć - prezentują jak korzystać ze słowników języka Python oraz działanie poszczególnych narzędzi do oznaczania części mowy.
Wstęp do rozdziału 8, podrozdziały 8.1, 8.2 i 8.3 - zawierają one informacje dotyczące analizy struktury zdania za pomocą gramatyki. Warto również, chociaż pobieżnie (bez analizy przedstawionego kodu), zapoznać się z rozdziałem 8.4 by poznać metody analizy struktury zdania (podejścia top-down i bottom-up).
Wstęp do rozdziału 9, podrozdział 9.1, sekcja Subcategorization podrozdziału 9.3 - zawierają one informacje dotyczące gramatyki opartej na atrybutach.
Wstęp do rozdziału 10, podrozdziały 10.1, 10.2, 10.3 oraz podrozdział 10.4 do sekcji Transitive Verbs włącznie - zawierają one informacje dotyczące analizy znaczenia zdań. Ze szczególną uwagą i zrozumieniem należy przeczytać fragmenty o zapisie logiki pierwszego rzędu i rachunku lambda.
Jako uzupełnienie treści z książki warto przeczytać dokument A Brief Incomplete Introduction to NLTK http://www.cs.utsa.edu/~bylander/cs5233/nltk-intro.pdf.
Etap 3. Zapoznanie się z programem EAK
Jeśli nie zrobiłeś tego wcześniej przeczytaj rozdziały 5. i 6. pracy magisterskiej Statystyczne metody rozumienia i syntezy wypowiedzi języka naturalnego - opisują one działanie stworzonego agenta konwersacyjnego, sposób interakcji z nim, a także podsumowują jego działanie.
Pracę z programem EAK rozpocznij od pobrania i rozpakowania paczki: http://sequoia.ict.pwr.wroc.pl/~witold/ai/EAK1.zip
Z punktu widzenia pracy z programem EAK.py, najważniejszym jego elementem jest lista pairs zawierająca trzyelementowe krotki definiujące pytania, na które odpowiedzieć będzie potrafił agent.
Pierwszy element każdej krotki to wyrażenie regularne odpowiadające pytaniu, które ma rozpoznać agent. Lista analizowana jest od początku do końca, więc jeśli danemu pytaniu odpowiada więcej niż jedno wyrażenie regularne to wyrażenie bardziej szczegółowe powinno znaleźć się na liście przed wyrażaniem ogólniejszym. Z tego powodu ostatnim elementem listy jest wyrażenie r'(.*)', które odpowiada dowolnemu pytaniu. Litera r pojawiają się przed wyrażeniami oznacza 'raw text', co oznacza, że znaki specjalne interpretowane są jako normalne znaki. Drugi element krotek ma dwie dozwolone postacie. Dla pytań, na które oczekujemy odpowiedzi tak lub nie, jest to pytanie przekształcone do postaci zdania twierdzącego, którego prawdziwość zostanie poddana procesowi wnioskowania (\%1, \%2, ... - to fragmenty zdania, które w pytaniu zadanym przez użytkownika zostały dopasowane do wzorca, np. (.*)). Dla pytań szczegółowych, jest to formuła logiczna, zawierająca implikację, w której poprzednikiem implikacji jest warunek odpowiadający pytaniu szczegółowemu, zaś następnikiem predykat unarny ANSWER. Formuły poprzedzone są spacją i literą Q. Trzeci element krotek to początek odpowiedzi, którą wyświetla program. Koniec odpowiedzi stanowi tak lub nie (dla pytań tak/nie) lub lista odpowiedzi spełniających zadany warunek (dla pytań szczegółowych). Tworząc własnego agenta konwersacyjnego zmodyfikować należy listę pairs, tak aby odpowiadała pytaniom jakie pojawić się w mogą w czasie rozmowy z agentem na zdefiniowany temat.
Gramatyka, która zostanie wykorzystana do przetwarzania tekstu zapisana jest w pliku gramatyka.fcfg. Znajdują się w niej reguły rozkładu zdań, które należy przeanalizować i nie należy usuwać podczas tworzenia własnego agenta. Pod komentarzem #gramatyka1 znajduje się zbiór reguł pozwalających na zinterpretowania wiedzy zawartej w pliku MyText1.txt oraz odpowiadanie na pytania zdefiniowane w liście pairs w pliku EAK.py z paczki EAK1. Reguły definiują podmioty będące nazwami własnymi (Tom_Tomaski, Mary_Maryski, Sam_Samowski), orzeczenie 'is' oraz dopełnienia (man, student_WRUT, friend_of_Tom). Warto zwrócić uwagę na strukturę reguł - po prawej stronie strzałki (->) znajdują się możliwe formy zapisu danej części zdania/mowy, co oznacza, że myśląc o podmiocie Tom_Tomaski, możemy napisać Tom, Tom Tomaski, Tommy lub Thomas. Kluczowy dla interpretacji zdania jest atrybut SEM, który oznacza znaczenie danego słowa/wyrażenia zapisane w formie logiki pierwszego rzędu i rachunku lambda.
Wynik konwersacji z agentem został zapisany w pliku Wynik1.txt (po znaku # znajdują się komentarze do odpowiedzi agenta). Warto zauważyć, że pytania szczegółowe zostają bezpośrednio przekształcone przez reguły zapisane w liście pairs do formuł logicznych, więc chcąc zapytać o Tom_Tomaski nie możemy już nazwać go Tom, Thomas lub Tommy.
Podczas interakcji z agentem wyświetlane są dodatkowe informacje, dotyczą interpretacji zdań w języku naturalnym. Aby wyłączyć wyświetlanie wczytanych z pliku wejściowego formuł zakomentuj polecenie print tree.node['SEM'] w funkcji main. Aby wyłączyć wyświetlanie logicznej interpretacji zadanego pytania zakomentuj polecenia print g w funkcji converse, zaś aby wyłączyć wyświetlanie dowodu zakomentuj polecenie print tp.proof() w tej samej funkcji.
Po zapoznaniu się z agentem konwersacyjnym dostarczonym w paczce EAK1 warto zapoznać się z zawartością paczek: http://sequoia.ict.pwr.wroc.pl/~witold/ai/EAK2.zip i http://sequoia.ict.pwr.wroc.pl/~witold/ai/EAK3.zip.
Agent zawarty w paczce EAK2 rozbudowany został o kolejne pytania - pozwalają one na wnioskowanie z predykatami play oraz have. Oprócz nowych krotek na liście pairs odpowiadających zarówno pytaniom tak/nie jak i szczegółowym, rozbudowany został plik z gramatyką. Jego istotnym elementem są reguły NI definiujące części zdania, które mają być pomijane. Pozwala to na zadanie dłuższych pytań/podawanie dłuższych zdań z informacjami, jednocześnie odfiltrowując z nich kluczową treść.
Agent zawarty w paczce EAK3 został rozbudowany o możliwość rozpoznawania kolejnych informacji i pytań, tak aby pełniej wykorzystać mechanizm dowodzenia. W pliku MyText3.txt znajdują się informacje o tym, że Tom jest piłkarzem oraz że każdy piłkarz jest sportowcem. Dzięki prawidłowej interpretacji słów every i all, możemy uzyskać informację na temat tego czy Tom jest sportowcem (agent poda odpowiedź twierdzącą) pomimo tego, że informacja ta nie była wprost zawarta w bazie wiedzy. Dodano również nową regułę rozkładu zdania (dotychczasowa nie uwzględniała braku przedimka nieokreślonego przed rzeczownikiem w liczbie mnogiej) pozwalające inaczej niż dotychczas sparsować zdanie z czasownikiem posiłkowym. Warto zwrócić uwagę na inny niż dotychczas zapis semantyki słów pojawiających się w zdaniu (\P.P(slowo) oraz \x.slowo(x)). Wyjaśnienie różnicy między tymi dwoma zapisami znajduje się w książce Natural Language Processing with Python w sekcji poświęconej rachunkowi lambda.
W tej wersji agenta zwrócono również uwagę na problem rozpoznania poszczególnych części niektórych pytań, np. Is Thomas strong?. Za pomocą wyrażenia regularnego trudno jest opisać jednoznacznie format tego pytania by oddzielić od siebie podmiot od dopełnienia. We wcześniejszych przykładach używaliśmy do tego przedimki, np. w zdaniu Is Thomas a sportsman? podmiotem był wyrazy między Is a a zaś dopełnieniem wyrazy znajdują się za przedimkiem a. Problem ten można rozwiązać zadając na przykład pytanie w formie Is it true, that Thomas is strong? lub pytania w mowie zależnej.
Paczka http://sequoia.ict.pwr.wroc.pl/~witold/ai/EAK_calosc.zip zawiera agenta konwersacyjnego opisanego w pracy magisterskiej Statystyczne metody rozumienia i syntezy wypowiedzi języka naturalnego. Za poznaj się z jego działaniem podczas rozmów na temat wybranych filmów.
Etap 4. Zadanie do wykonania
Wersja prostsza - maksymalnie na ocenę 4.0
Wykorzystując wiedzę zdobytą poprzez wykonanie etapów 1-3 rozbuduj listę pairs oraz plik gramtyka.fcfg w celu stworzenia własnego agenta konwersacyjnego. Agent ma być zdolny do odpowiadania na pytania w określonym, wąskim temacie, np. wybrany okres w sztuce, twórczość artysty, wiedza geograficzna, wiedza medyczna, szczegóły dotyczące wydarzenia historycznego, Twój plan dnia (asystent znający nasze plany), itd., itp. Zadbaj aby agent mógł w pełni wykorzystać mechanizm dowodzenia twierdzeń (odpowiadać na pytania, na które odpowiedzi nie są wprost zawarte w bazie wiedzy). Postaraj się stworzyć zdania,w których pojawią się kwantyfikatory (zarówno ogólny jak i szczegółowy) oraz przeczenia. Wynikiem zadania powinny być zmodyfikowane pliki EAK.py oraz gramatyka.fcfg, baza wiedzy, na podstawie której rozmawiać będzie agent oraz zapis rozmowy pokazujący jego możliwości oraz ograniczenia (czyli sytuacje kiedy nie rozpozna pytania, odpowie niezgodnie z oczekiwaniami).
Wersja pełna
Opisane powyżej zadanie do wykonania, rozbuduj o taką modyfikację programu EAK.py, aby agent rozpoznawał zdania twierdzące od pytań. Formuły logiczne uzyskane po sparsowaniu zdania twierdzącego powinny być dodawane do bazy wiedzy odczytanej z pliku. Na pytania agent powinien odpowiadać tak jak dotychczas.
Uwaga do realizacji zadania:
W pliku tekstowym zawierającym bazę wiedzy, po kropce w ostatnim zdaniu nie może pojawić się spacja ani enter. Jeżeli edytor automatycznie dodaje je podczas zapisywania pliku, ostatnie zdanie należy zapisać bez kropki.