8.8 KiB
Systemy Dialogowe
7. Parsing semantyczny z wykorzystaniem gramatyk [laboratoria]
Marek Kubis (2021)
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ć <ilosc_biletow> <tytul_filmu> [<dzien_rezerwacji>] [<godzina_rezerwacji>];
<ilosc_biletow> = <liczba> {ilosc} (bilety | biletów);
<liczba> = dwa | trzy | cztery |1|2|3|4|5|6;
<tytul_filmu> = na [film] <tytul> {tytul};
<tytul> = Batman | Uncharted | Pitbull;
<dzien_rezerwacji> = na <dzien> {dzien};
<dzien> = dzisiaj | jutro | poniedziałek | wtorek | środę | czwartek | piątek | sobotę | niedzielę;
<godzina_rezerwacji> = na [godzinę] <godzina_z_minutami> {godzina};
<godzina_z_minutami> = <godzina> [<minuty>];
<godzina> = dziewiątą | dziesiątą | jedenastą | dwunastą;
<minuty> = pietnaście | trzydzieści;
Overwriting 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 = 'chciałbym zarezerwować 1 biletów na film Pitbull'
matched = book_grammar.find_matching_rules(utterance)
matched
[Rule(name='rezerwuj', visible=True, expansion=Sequence(Literal('chciałbym zarezerwować'), NamedRuleRef('ilosc_biletow'), NamedRuleRef('tytul_filmu'), OptionalGrouping(NamedRuleRef('dzien_rezerwacji')), OptionalGrouping(NamedRuleRef('godzina_rezerwacji'))))]
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])
{'act': 'book', 'slots': [('ilosc', '1'), ('tytul', 'Pitbull'), ('dzien', None), ('godzina', None)]}
Łą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ć dwa bilety na film Pitbull')
{'act': 'null', 'slots': []}
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.
Termin: 4.05.2022, godz. 23:59.