304 lines
8.8 KiB
Plaintext
304 lines
8.8 KiB
Plaintext
|
{
|
||
|
"cells": [
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
|
||
|
"<div class=\"alert alert-block alert-info\">\n",
|
||
|
"<h1> Systemy Dialogowe </h1>\n",
|
||
|
"<h2> 7. <i>Parsing semantyczny z wykorzystaniem gramatyk</i> [laboratoria]</h2> \n",
|
||
|
"<h3> Marek Kubis (2021)</h3>\n",
|
||
|
"</div>\n",
|
||
|
"\n",
|
||
|
"![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Parsing semantyczny z wykorzystaniem gramatyk\n",
|
||
|
"=============================================\n",
|
||
|
"\n",
|
||
|
"Wartości slotów możemy wydobywać z wypowiedzi użytkownika korzystając z takich technik, jak:\n",
|
||
|
"\n",
|
||
|
" - wyszukiwanie słów kluczowych w tekście,\n",
|
||
|
"\n",
|
||
|
" - dopasowywanie wzorców zbudowanych przy użyciu wyrażeń regularnych,\n",
|
||
|
"\n",
|
||
|
" - parsery regułowe (temat dzisiejszych zajęć),\n",
|
||
|
"\n",
|
||
|
" - uczenie maszynowe (temat kolejnych zajęć)."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Przykłady parserów regułowych\n",
|
||
|
"-----------------------------\n",
|
||
|
"\n",
|
||
|
" - [Phoenix](http://wiki.speech.cs.cmu.edu/olympus/index.php/Phoenix_Server) — parser gramatyk\n",
|
||
|
" bezkontekstowych whodzący w skład systemu dialogowego [Olympus](http://wiki.speech.cs.cmu.edu/olympus/index.php/Olympus)\n",
|
||
|
"\n",
|
||
|
" - Parsery [DCG](https://www.swi-prolog.org/pldoc/man?section=DCG) (Definite Clause Grammars) języka [Prolog](https://www.swi-prolog.org/)\n",
|
||
|
"\n",
|
||
|
" - [JSpeech Grammar Format](https://www.w3.org/TR/jsgf/) (JSGF)\n",
|
||
|
"\n",
|
||
|
"Przykład\n",
|
||
|
"--------\n",
|
||
|
"Zapiszmy w JSGF gramatykę semantyczną dla aktu dialogowego reprezentującego zamiar rezerwacji\n",
|
||
|
"stolika w restauracji."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 51,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"name": "stdout",
|
||
|
"output_type": "stream",
|
||
|
"text": [
|
||
|
"Overwriting book.jsgf\n"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"%%writefile book.jsgf\n",
|
||
|
"#JSGF V1.0 UTF-8 pl;\n",
|
||
|
"\n",
|
||
|
"grammar book;\n",
|
||
|
"\n",
|
||
|
"public <rezerwuj> = chciałbym zarezerwować <ilosc_biletow> <tytul_filmu> [<dzien_rezerwacji>] [<godzina_rezerwacji>];\n",
|
||
|
"\n",
|
||
|
"<ilosc_biletow> = <liczba> {ilosc} (bilety | biletów);\n",
|
||
|
"\n",
|
||
|
"<liczba> = dwa | trzy | cztery |1|2|3|4|5|6;\n",
|
||
|
"\n",
|
||
|
"<tytul_filmu> = na [film] <tytul> {tytul};\n",
|
||
|
"\n",
|
||
|
"<tytul> = Batman | Uncharted | Pitbull;\n",
|
||
|
"\n",
|
||
|
"<dzien_rezerwacji> = na <dzien> {dzien};\n",
|
||
|
"\n",
|
||
|
"<dzien> = dzisiaj | jutro | poniedziałek | wtorek | środę | czwartek | piątek | sobotę | niedzielę;\n",
|
||
|
"\n",
|
||
|
"<godzina_rezerwacji> = na [godzinę] <godzina_z_minutami> {godzina};\n",
|
||
|
"\n",
|
||
|
"<godzina_z_minutami> = <godzina> [<minuty>];\n",
|
||
|
"\n",
|
||
|
"<godzina> = dziewiątą | dziesiątą | jedenastą | dwunastą;\n",
|
||
|
"\n",
|
||
|
"<minuty> = pietnaście | trzydzieści;\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Parser akceptujący powyższą gramatykę utworzymy korzystając z biblioteki [pyjsgf](https://github.com/Danesprite/pyjsgf)."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 52,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/plain": [
|
||
|
"Grammar(version=1.0, charset=UTF-8, language=pl, name=book)"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 52,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"import jsgf\n",
|
||
|
"\n",
|
||
|
"book_grammar = jsgf.parse_grammar_file('book.jsgf')\n",
|
||
|
"book_grammar"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Wykorzystajmy gramatykę `book.jsgf` do analizy następującej wypowiedzi"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 53,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/plain": [
|
||
|
"[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'))))]"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 53,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"utterance = 'chciałbym zarezerwować 1 biletów na film Pitbull'\n",
|
||
|
"matched = book_grammar.find_matching_rules(utterance)\n",
|
||
|
"matched"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Reprezentację znaczenia można wydobyć ze sparsowanej wypowiedzi na wiele sposobów. My do\n",
|
||
|
"wydobywania slotów wykorzystamy mechanizm tagów JSGF a za nazwę aktu dialogowego przyjmiemy nazwę\n",
|
||
|
"gramatyki. Wzorując się na [DSTC2](https://github.com/matthen/dstc) wynikową ramę zapiszemy korzystając ze słownika o polach `act` i `slots`."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 54,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/plain": [
|
||
|
"{'act': 'book',\n",
|
||
|
" 'slots': [('ilosc', '1'),\n",
|
||
|
" ('tytul', 'Pitbull'),\n",
|
||
|
" ('dzien', None),\n",
|
||
|
" ('godzina', None)]}"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 54,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"def get_dialog_act(rule):\n",
|
||
|
" slots = []\n",
|
||
|
" get_slots(rule.expansion, slots)\n",
|
||
|
" return {'act': rule.grammar.name, 'slots': slots}\n",
|
||
|
"\n",
|
||
|
"def get_slots(expansion, slots):\n",
|
||
|
" if expansion.tag != '':\n",
|
||
|
" slots.append((expansion.tag, expansion.current_match))\n",
|
||
|
" return\n",
|
||
|
"\n",
|
||
|
" for child in expansion.children:\n",
|
||
|
" get_slots(child, slots)\n",
|
||
|
"\n",
|
||
|
" if not expansion.children and isinstance(expansion, jsgf.NamedRuleRef):\n",
|
||
|
" get_slots(expansion.referenced_rule.expansion, slots)\n",
|
||
|
"\n",
|
||
|
"get_dialog_act(matched[0])"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Łącząc powyższe funkcje możemy zbudować prosty moduł NLU."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 41,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/plain": [
|
||
|
"{'act': 'null', 'slots': []}"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 41,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"def nlu(utterance):\n",
|
||
|
" matched = book_grammar.find_matching_rules(utterance)\n",
|
||
|
"\n",
|
||
|
" if matched:\n",
|
||
|
" return get_dialog_act(matched[0])\n",
|
||
|
" else:\n",
|
||
|
" return {'act': 'null', 'slots': []}\n",
|
||
|
"\n",
|
||
|
"nlu('chciałbym zarezerwować dwa bilety na film Pitbull')"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Problemy\n",
|
||
|
"--------\n",
|
||
|
"\n",
|
||
|
" - Co z normalizacją wyrażeń liczbowych takich, jak godziny, daty czy numery telefonów?\n",
|
||
|
"\n",
|
||
|
" - Co w przypadku gdy więcej niż jedna reguła zostanie dopasowana?"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Zadanie\n",
|
||
|
"-------\n",
|
||
|
"Zaimplementować analizator języka naturalnego (NLU) na potrzeby realizowanego agenta dialogowego.\n",
|
||
|
"\n",
|
||
|
"Moduł powinien być zbudowany z wykorzystaniem parsingu regułowego i/lub technik uczenia maszynowego.\n",
|
||
|
"\n",
|
||
|
"Przygotować skrypt `evaluate.py` wyznaczający *dokładność* (ang. accuracy) analizatora względem zgromadzonego korpusu eksperymentalnego,\n",
|
||
|
"tj. stosunek liczby wypowiedzi użytkownika, w których akty dialogowe zostały rozpoznane prawidłowo do liczby wszystkich wypowiedzi użytkownika w korpusie.\n",
|
||
|
"\n",
|
||
|
"Analizator języka naturalnego umieścić w gałęzi `master` repozytorium projektowego. Skrypt `evaluate.py` umieścić w katalogu głównym tej gałęzi.\n",
|
||
|
"\n",
|
||
|
"Termin: 4.05.2022, godz. 23:59."
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"metadata": {
|
||
|
"author": "Marek Kubis",
|
||
|
"email": "mkubis@amu.edu.pl",
|
||
|
"jupytext": {
|
||
|
"cell_metadata_filter": "-all",
|
||
|
"main_language": "python",
|
||
|
"notebook_metadata_filter": "-all"
|
||
|
},
|
||
|
"kernelspec": {
|
||
|
"display_name": "Python 3",
|
||
|
"language": "python",
|
||
|
"name": "python3"
|
||
|
},
|
||
|
"lang": "pl",
|
||
|
"language_info": {
|
||
|
"codemirror_mode": {
|
||
|
"name": "ipython",
|
||
|
"version": 3
|
||
|
},
|
||
|
"file_extension": ".py",
|
||
|
"mimetype": "text/x-python",
|
||
|
"name": "python",
|
||
|
"nbconvert_exporter": "python",
|
||
|
"pygments_lexer": "ipython3",
|
||
|
"version": "3.7.3"
|
||
|
},
|
||
|
"subtitle": "7.Parsing semantyczny z wykorzystaniem gramatyk[laboratoria]",
|
||
|
"title": "Systemy Dialogowe",
|
||
|
"year": "2021"
|
||
|
},
|
||
|
"nbformat": 4,
|
||
|
"nbformat_minor": 4
|
||
|
}
|