8.4 KiB
Parsing semantyczny z wykorzystaniem gramatyk
Wartości slotów możemy wydobywać z wypowiedzi użytkownika korzystając z takich technik, jak:
wyszukiwanie słów kluczowych w tekście,
dopasowywanie wzorców zbudowanych przy użyciu wyrażeń regularnych,
parsery regułowe (temat dzisiejszych zajęć),
uczenie maszynowe (temat kolejnych zajęć).
Przykłady parserów regułowych
Phoenix — parser gramatyk bezkontekstowych whodzący w skład systemu dialogowego Olympus
JSpeech Grammar Format (JSGF)
Przykład
Zapiszmy w JSGF gramatykę semantyczną dla aktu dialogowego reprezentującego zamiar rezerwacji stolika w restauracji.
%%writefile book.jsgf
#JSGF V1.0 UTF-8 pl;
grammar book;
public <rezerwuj> = chciałbym zarezerwować stolik <dzien_rezerwacji> <godzina_rezerwacji> <liczba_osob> ;
<dzien_rezerwacji> = na <dzien> {day};
<dzien> = dzisiaj | jutro | poniedziałek | wtorek | środę | czwartek | piątek | sobotę | niedzielę;
<godzina_rezerwacji> = na [godzinę] <godzina_z_minutami> {hour};
<godzina_z_minutami> = <godzina> [<minuty>];
<godzina> = dziewiątą | dziesiątą | jedenastą | dwunastą;
<minuty> = pietnaście | trzydzieści;
<liczba_osob> = (na | dla) <liczba> {size} osób;
<liczba> = dwie | dwóch | trzy | trzech | cztery | czterech | pięć | pieciu;
Writing book.jsgf
Parser akceptujący powyższą gramatykę utworzymy korzystając z biblioteki pyjsgf.
import jsgf
book_grammar = jsgf.parse_grammar_file('book.jsgf')
book_grammar
Grammar(version=1.0, charset=UTF-8, language=pl, name=book)
Wykorzystajmy gramatykę book.jsgf
do analizy następującej wypowiedzi
utterance = 'chcialbym zarezerwowac stolik na jutro na godzine dwunasta trzydziesci na piec osob'
matched = book_grammar.find_matching_rules(utterance)
matched
[]
Reprezentację znaczenia można wydobyć ze sparsowanej wypowiedzi na wiele sposobów. My do
wydobywania slotów wykorzystamy mechanizm tagów JSGF a za nazwę aktu dialogowego przyjmiemy nazwę
gramatyki. Wzorując się na DSTC2 wynikową ramę zapiszemy korzystając ze słownika o polach act
i slots
.
def get_dialog_act(rule):
slots = []
get_slots(rule.expansion, slots)
return {'act': rule.grammar.name, 'slots': slots}
def get_slots(expansion, slots):
if expansion.tag != '':
slots.append((expansion.tag, expansion.current_match))
return
for child in expansion.children:
get_slots(child, slots)
if not expansion.children and isinstance(expansion, jsgf.NamedRuleRef):
get_slots(expansion.referenced_rule.expansion, slots)
get_dialog_act(matched[0])
[1;31m---------------------------------------------------------------------------[0m [1;31mIndexError[0m Traceback (most recent call last) Cell [1;32mIn[16], line 17[0m [0;32m 14[0m [39mif[39;00m [39mnot[39;00m expansion[39m.[39mchildren [39mand[39;00m [39misinstance[39m(expansion, jsgf[39m.[39mNamedRuleRef): [0;32m 15[0m get_slots(expansion[39m.[39mreferenced_rule[39m.[39mexpansion, slots) [1;32m---> 17[0m get_dialog_act(matched[[39m0[39;49m]) [1;31mIndexError[0m: list index out of range
Łącząc powyższe funkcje możemy zbudować prosty moduł NLU.
def nlu(utterance):
matched = book_grammar.find_matching_rules(utterance)
if matched:
return get_dialog_act(matched[0])
else:
return {'act': 'null', 'slots': []}
nlu('chciałbym zarezerwować stolik na jutro na godzinę dziesiątą dla trzech osób')
Problemy
Co z normalizacją wyrażeń liczbowych takich, jak godziny, daty czy numery telefonów?
Co w przypadku gdy więcej niż jedna reguła zostanie dopasowana?
Zadanie
Zaimplementować analizator języka naturalnego (NLU) na potrzeby realizowanego agenta dialogowego.
Moduł powinien być zbudowany z wykorzystaniem parsingu regułowego i/lub technik uczenia maszynowego.
Przygotować skrypt evaluate.py
wyznaczający _dokładność (ang. accuracy) analizatora względem zgromadzonego korpusu eksperymentalnego,
tj. stosunek liczby wypowiedzi użytkownika, w których akty dialogowe zostały rozpoznane prawidłowo do liczby wszystkich wypowiedzi użytkownika w korpusie.
Analizator języka naturalnego umieścić w gałęzi master
repozytorium projektowego. Skrypt evaluate.py
umieścić w katalogu głównym tej gałęzi.