{ "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 (ipykernel)", "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.13" }, "subtitle": "7.Parsing semantyczny z wykorzystaniem gramatyk[laboratoria]", "title": "Systemy Dialogowe", "year": "2021" }, "nbformat": 4, "nbformat_minor": 4 }