diff --git a/AJN.ipynb b/AJN.ipynb new file mode 100644 index 0000000..8f87484 --- /dev/null +++ b/AJN.ipynb @@ -0,0 +1,303 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n", + "
\n", + "

Systemy Dialogowe

\n", + "

7. Parsing semantyczny z wykorzystaniem gramatyk [laboratoria]

\n", + "

Marek Kubis (2021)

\n", + "
\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 = chciałbym zarezerwować [] [];\n", + "\n", + " = {ilosc} (bilety | biletów);\n", + "\n", + " = dwa | trzy | cztery |1|2|3|4|5|6;\n", + "\n", + " = na [film] {tytul};\n", + "\n", + " = Batman | Uncharted | Pitbull;\n", + "\n", + " = na {dzien};\n", + "\n", + " = dzisiaj | jutro | poniedziałek | wtorek | środę | czwartek | piątek | sobotę | niedzielę;\n", + "\n", + " = na [godzinę] {godzina};\n", + "\n", + " = [];\n", + "\n", + " = dziewiątą | dziesiątą | jedenastą | dwunastą;\n", + "\n", + " = 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 +}