From 187d2b95967efc1c112c92e74be5c6280629ccac Mon Sep 17 00:00:00 2001 From: ignatov Date: Fri, 2 Aug 2019 11:04:27 +0300 Subject: [PATCH 01/39] feat: added socket to feed model fix: changed port parameter in deep.py --- deeppavlov/deep.py | 7 +- deeppavlov/utils/settings/socket_config.json | 5 ++ deeppavlov/utils/socket/__init__.py | 0 deeppavlov/utils/socket/socket.py | 86 ++++++++++++++++++++ 4 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 deeppavlov/utils/settings/socket_config.json create mode 100644 deeppavlov/utils/socket/__init__.py create mode 100644 deeppavlov/utils/socket/socket.py diff --git a/deeppavlov/deep.py b/deeppavlov/deep.py index 4dd73302ea..1bbda851c4 100644 --- a/deeppavlov/deep.py +++ b/deeppavlov/deep.py @@ -27,6 +27,7 @@ from deeppavlov.utils.ms_bot_framework.server import run_ms_bf_default_agent from deeppavlov.utils.pip_wrapper import install_from_config from deeppavlov.utils.server.server import start_model_server +from deeppavlov.utils.socket.socket import start_model_socket from deeppavlov.utils.telegram.telegram_ui import interact_model_by_telegram log = getLogger(__name__) @@ -35,7 +36,7 @@ parser.add_argument("mode", help="select a mode, train or interact", type=str, choices={'train', 'evaluate', 'interact', 'predict', 'interactbot', 'interactmsbot', - 'alexa', 'riseapi', 'download', 'install', 'crossval'}) + 'alexa', 'riseapi', 'risesocket', 'download', 'install', 'crossval'}) parser.add_argument("config_path", help="path to a pipeline json config", type=str) parser.add_argument("-e", "--start-epoch-num", dest="start_epoch_num", default=None, @@ -60,7 +61,7 @@ parser.add_argument("--key", default=None, help="ssl key", type=str) parser.add_argument("--cert", default=None, help="ssl certificate", type=str) -parser.add_argument("-p", "--port", default=None, help="api port", type=str) +parser.add_argument("-p", "--port", default=None, help="api port", type=int) parser.add_argument("--api-mode", help="rest api mode: 'basic' with batches or 'alice' for Yandex.Dialogs format", type=str, default='basic', choices={'basic', 'alice'}) @@ -120,6 +121,8 @@ def main(): start_alice_server(pipeline_config_path, https, ssl_key, ssl_cert, port=args.port) else: start_model_server(pipeline_config_path, https, ssl_key, ssl_cert, port=args.port) + elif args.mode == 'risesocket': + start_model_socket(pipeline_config_path, port=args.port) elif args.mode == 'predict': predict_on_stream(pipeline_config_path, args.batch_size, args.file_path) elif args.mode == 'install': diff --git a/deeppavlov/utils/settings/socket_config.json b/deeppavlov/utils/settings/socket_config.json new file mode 100644 index 0000000000..1ec65fca22 --- /dev/null +++ b/deeppavlov/utils/settings/socket_config.json @@ -0,0 +1,5 @@ +{ + "host": "0.0.0.0", + "port": 5000, + "model_args_names": ["context"] +} \ No newline at end of file diff --git a/deeppavlov/utils/socket/__init__.py b/deeppavlov/utils/socket/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py new file mode 100644 index 0000000000..9f05d42ad5 --- /dev/null +++ b/deeppavlov/utils/socket/socket.py @@ -0,0 +1,86 @@ +import asyncio +import json +import socket +from logging import getLogger +from pathlib import Path +from typing import Optional, List + +from deeppavlov.core.agent.dialog_logger import DialogLogger +from deeppavlov.core.commands.infer import build_model +from deeppavlov.core.common.chainer import Chainer +from deeppavlov.core.common.file import read_json +from deeppavlov.core.common.paths import get_settings_path + +SOCKET_CONFIG_FILENAME = 'socket_config.json' + +log = getLogger(__name__) +loop = asyncio.get_event_loop() +dialog_logger = DialogLogger(agent_name='dp_api') + + +async def handle_connection(conn: socket.socket, addr, model: Chainer, params_names: List[str]): + conn.setblocking(False) + incoming_data = b'' + recv_data = conn.recv(1024) + incoming_data += recv_data + try: + data = json.loads(incoming_data) + except ValueError: + log.error('request type is not json') + conn.sendall(b'[]') + return + dialog_logger.log_in(data) + model_args = [] + for param_name in params_names: + param_value = data.get(param_name) + if param_value is None or (isinstance(param_value, list) and len(param_value) > 0): + model_args.append(param_value) + else: + log.error(f"nonempty array expected but got '{param_name}'={repr(param_value)}") + conn.sendall(b'[]') + return + lengths = {len(i) for i in model_args if i is not None} + + if not lengths: + log.error('got empty request') + conn.sendall(b'[]') + return + elif len(lengths) > 1: + log.error('got several different batch sizes') + conn.sendall(b'[]') + return + batch_size = list(lengths)[0] + model_args = [arg or [None] * batch_size for arg in model_args] + + # in case when some parameters were not described in model_args + model_args += [[None] * batch_size for _ in range(len(model.in_x) - len(model_args))] + + prediction = await loop.run_in_executor(None, model, *model_args) + if len(model.out_params) == 1: + prediction = [prediction] + prediction = list(zip(*prediction)) + result = json.dumps(prediction) + dialog_logger.log_out(result) + conn.sendall(result.encode('utf-8')) + + +async def process_connections(server: socket.socket, model: Chainer, params_names: List[str]) -> None: + while True: + conn, addr = await loop.run_in_executor(None, server.accept) + loop.create_task(handle_connection(conn, addr, model, params_names)) + + +def start_model_socket(model_config: Path, port: Optional[int] = None) -> None: + socket_config_path = get_settings_path() / SOCKET_CONFIG_FILENAME + socket_params = read_json(socket_config_path) + model_args_names = socket_params['model_args_names'] + + host = socket_params['host'] + port = port or socket_params['port'] + + model = build_model(model_config) + + server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server.bind((host, port)) + server.listen() + loop.run_until_complete(process_connections(server, model, model_args_names)) \ No newline at end of file From 57e57f9483b85cd9a1e9c0a2701349fdc5e3794b Mon Sep 17 00:00:00 2001 From: ignatov Date: Fri, 2 Aug 2019 14:27:52 +0300 Subject: [PATCH 02/39] feat: added socket interface test, small fixes --- deeppavlov/utils/settings/socket_config.json | 5 ++- deeppavlov/utils/socket/socket.py | 21 +++++---- tests/test_quick_start.py | 45 ++++++++++++++++++-- 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/deeppavlov/utils/settings/socket_config.json b/deeppavlov/utils/settings/socket_config.json index 1ec65fca22..c0ae8a7e9c 100644 --- a/deeppavlov/utils/settings/socket_config.json +++ b/deeppavlov/utils/settings/socket_config.json @@ -1,5 +1,6 @@ { "host": "0.0.0.0", - "port": 5000, - "model_args_names": ["context"] + "port": 5001, + "model_args_names": ["context"], + "bufsize": 1024 } \ No newline at end of file diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index 9f05d42ad5..785c6fd8a9 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -18,10 +18,10 @@ dialog_logger = DialogLogger(agent_name='dp_api') -async def handle_connection(conn: socket.socket, addr, model: Chainer, params_names: List[str]): +async def handle_connection(conn: socket.socket, addr, model: Chainer, params_names: List[str], bufsize: int): conn.setblocking(False) incoming_data = b'' - recv_data = conn.recv(1024) + recv_data = conn.recv(bufsize) incoming_data += recv_data try: data = json.loads(incoming_data) @@ -64,23 +64,28 @@ async def handle_connection(conn: socket.socket, addr, model: Chainer, params_na conn.sendall(result.encode('utf-8')) -async def process_connections(server: socket.socket, model: Chainer, params_names: List[str]) -> None: +async def process_connections(server: socket.socket, model: Chainer, params_names: List[str], bufsize: int) -> None: while True: conn, addr = await loop.run_in_executor(None, server.accept) - loop.create_task(handle_connection(conn, addr, model, params_names)) + loop.create_task(handle_connection(conn, addr, model, params_names, bufsize)) - -def start_model_socket(model_config: Path, port: Optional[int] = None) -> None: +def get_socket_params(): socket_config_path = get_settings_path() / SOCKET_CONFIG_FILENAME socket_params = read_json(socket_config_path) - model_args_names = socket_params['model_args_names'] + return socket_params +def start_model_socket(model_config: Path, port: Optional[int] = None) -> None: + socket_params = get_socket_params() + + model_args_names = socket_params['model_args_names'] host = socket_params['host'] port = port or socket_params['port'] + bufsize = socket_params['bufsize'] model = build_model(model_config) server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind((host, port)) server.listen() - loop.run_until_complete(process_connections(server, model, model_args_names)) \ No newline at end of file + log.info(f'socket http://{host}:{port} has successfully launched') + loop.run_until_complete(process_connections(server, model, model_args_names, bufsize)) \ No newline at end of file diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index 9c36880035..67a4724ea4 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -5,10 +5,11 @@ import pickle import shutil import signal +import socket import sys from concurrent.futures import ProcessPoolExecutor from pathlib import Path -from typing import Union +from typing import Optional, Union from urllib.parse import urljoin import pexpect @@ -23,6 +24,7 @@ from deeppavlov.core.data.utils import get_all_elems_from_json from deeppavlov.download import deep_download from deeppavlov.utils.server.server import get_server_params, SERVER_CONFIG_FILENAME +from deeppavlov.utils.socket.socket import get_socket_params tests_dir = Path(__file__).parent test_configs_path = tests_dir / "deeppavlov" / "configs" @@ -30,7 +32,7 @@ test_src_dir = tests_dir / "test_configs" download_path = tests_dir / "download" -cache_dir: Path = None +cache_dir: Optional[Path] = None if not os.getenv('DP_PYTEST_NO_CACHE'): cache_dir = tests_dir / 'download_cache' @@ -99,7 +101,7 @@ ("classifiers/rusentiment_elmo_twitter_cnn.json", "classifiers", ('IP',)): [ONE_ARGUMENT_INFER_CHECK], ("classifiers/rusentiment_bigru_superconv.json", "classifiers", ('IP',)): [ONE_ARGUMENT_INFER_CHECK], ("classifiers/yahoo_convers_vs_info.json", "classifiers", ('IP',)): [ONE_ARGUMENT_INFER_CHECK], - ("classifiers/ru_obscenity_classifier.json", "classifiers", ('IP')): + ("classifiers/ru_obscenity_classifier.json", "classifiers", ('IP',)): [ ("Ну и сука же она", 'True'), ("я два года жду эту игру", 'False') @@ -414,6 +416,34 @@ def interact_api(config_path): # if p.wait() != 0: # raise RuntimeError('Error in shutting down API server: \n{}'.format(logfile.getvalue().decode())) + @staticmethod + def interact_socket(config_path): + logfile = io.BytesIO(b'') + socket_params = get_socket_params() + host = socket_params['host'] + port = api_port or socket_params['port'] + socket_url = f'http://{host}:{port}' + args = [sys.executable, "-m", "deeppavlov", "risesocket", str(config_path)] + if api_port: + args += ['-p', str(api_port)] + p = pexpect.popen_spawn.PopenSpawn(' '.join(args), + timeout=None, logfile=logfile) + try: + p.expect(socket_url) + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.connect((host, port)) + di = {"context": ["This is DeepPavlov API python test."]} + di = json.dumps(di) + s.sendall(di.encode('utf-8')) + data = s.recv(1024) + print(data) + assert 1 == 1 + except pexpect.exceptions.EOF: + raise RuntimeError('Got unexpected EOF: \n{}'.format(logfile.getvalue().decode())) + finally: + p.kill(signal.SIGTERM) + p.wait() + def test_interacting_pretrained_model(self, model, conf_file, model_dir, mode): if 'IP' in mode: config_file_path = str(test_configs_path.joinpath(conf_file)) @@ -433,6 +463,15 @@ def test_interacting_pretrained_model_api(self, model, conf_file, model_dir, mod else: pytest.skip("Unsupported mode: {}".format(mode)) + def test_interacting_pretrained_model_socket(self, model, conf_file, model_dir, mode): + if 'IP' in mode and conf_file == "ner/ner_ontonotes.json": + config_file_path = str(test_configs_path.joinpath(conf_file)) + install_config(config_file_path) + deep_download(config_file_path) + self.interact_socket(test_configs_path / conf_file) + else: + pytest.skip(f"Unsupported mode: {mode}") + def test_serialization(self, model, conf_file, model_dir, mode): if 'SR' not in mode: return pytest.skip("Unsupported mode: {}".format(mode)) From 143f9fb83bfe3afef48ddaa70a5005dfc74234a4 Mon Sep 17 00:00:00 2001 From: ignatov Date: Fri, 2 Aug 2019 20:01:09 +0300 Subject: [PATCH 03/39] fix: correct asynchronous requests, small refactor --- deeppavlov/utils/socket/socket.py | 43 +++++++++++++++++++------------ tests/test_quick_start.py | 3 ++- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index 785c6fd8a9..e0122ec6a8 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -19,15 +19,14 @@ async def handle_connection(conn: socket.socket, addr, model: Chainer, params_names: List[str], bufsize: int): + log.info(f'handling connection from {addr}') conn.setblocking(False) - incoming_data = b'' - recv_data = conn.recv(bufsize) - incoming_data += recv_data + recv_data = await loop.sock_recv(conn, bufsize) try: - data = json.loads(incoming_data) + data = json.loads(recv_data) except ValueError: log.error('request type is not json') - conn.sendall(b'[]') + await loop.sock_sendall(conn, b'[]') return dialog_logger.log_in(data) model_args = [] @@ -37,17 +36,17 @@ async def handle_connection(conn: socket.socket, addr, model: Chainer, params_na model_args.append(param_value) else: log.error(f"nonempty array expected but got '{param_name}'={repr(param_value)}") - conn.sendall(b'[]') + await loop.sock_sendall(conn, b'[]') return lengths = {len(i) for i in model_args if i is not None} if not lengths: log.error('got empty request') - conn.sendall(b'[]') + await loop.sock_sendall(conn, b'[]') return elif len(lengths) > 1: log.error('got several different batch sizes') - conn.sendall(b'[]') + await loop.sock_sendall(conn, b'[]') return batch_size = list(lengths)[0] model_args = [arg or [None] * batch_size for arg in model_args] @@ -59,21 +58,23 @@ async def handle_connection(conn: socket.socket, addr, model: Chainer, params_na if len(model.out_params) == 1: prediction = [prediction] prediction = list(zip(*prediction)) - result = json.dumps(prediction) + result = json.dumps({'status': 'OK', 'payload': prediction}) dialog_logger.log_out(result) - conn.sendall(result.encode('utf-8')) + await loop.sock_sendall(conn, result.encode('utf-8')) -async def process_connections(server: socket.socket, model: Chainer, params_names: List[str], bufsize: int) -> None: +async def server(sock: socket.socket, model: Chainer, params_names: List[str], bufsize: int) -> None: while True: - conn, addr = await loop.run_in_executor(None, server.accept) + conn, addr = await loop.sock_accept(sock) loop.create_task(handle_connection(conn, addr, model, params_names, bufsize)) -def get_socket_params(): + +def get_socket_params() -> dict: socket_config_path = get_settings_path() / SOCKET_CONFIG_FILENAME socket_params = read_json(socket_config_path) return socket_params + def start_model_socket(model_config: Path, port: Optional[int] = None) -> None: socket_params = get_socket_params() @@ -84,8 +85,16 @@ def start_model_socket(model_config: Path, port: Optional[int] = None) -> None: model = build_model(model_config) - server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - server.bind((host, port)) - server.listen() + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.setblocking(False) + s.bind((host, port)) + s.listen() log.info(f'socket http://{host}:{port} has successfully launched') - loop.run_until_complete(process_connections(server, model, model_args_names, bufsize)) \ No newline at end of file + try: + loop.run_until_complete(server(s, model, model_args_names, bufsize)) + except: + pass + finally: + loop.close() + s.close() diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index 67a4724ea4..39e4b31895 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -436,7 +436,8 @@ def interact_socket(config_path): di = json.dumps(di) s.sendall(di.encode('utf-8')) data = s.recv(1024) - print(data) + resp = json.loads(data) + assert resp['status'] == 'OK', f"Socket returned {resp['status']} with {config_path}" assert 1 == 1 except pexpect.exceptions.EOF: raise RuntimeError('Got unexpected EOF: \n{}'.format(logfile.getvalue().decode())) From 48373446ecf9ef563b02c360be347da02df09ce9 Mon Sep 17 00:00:00 2001 From: ignatov Date: Mon, 5 Aug 2019 13:51:42 +0300 Subject: [PATCH 04/39] fix: correct receiving data at server, errors refactor --- deeppavlov/utils/socket/socket.py | 40 +++++++++++++++++++++---------- tests/test_quick_start.py | 10 ++++---- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index e0122ec6a8..25ac7fde26 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -19,14 +19,31 @@ async def handle_connection(conn: socket.socket, addr, model: Chainer, params_names: List[str], bufsize: int): + async def response(status, payload): + resp_dict = {'status': status, 'payload': payload} + resp_str = json.dumps(resp_dict) + return resp_str.encode('utf-8') + + async def wrap_error(conn, error): + log.error(error) + await loop.sock_sendall(conn, await response(error, '')) + log.info(f'handling connection from {addr}') conn.setblocking(False) - recv_data = await loop.sock_recv(conn, bufsize) + recv_data = b'' + try: + while True: + chunk = await loop.run_in_executor(None, conn.recv, bufsize) + if chunk: + recv_data += chunk + else: + break + except BlockingIOError: + pass try: data = json.loads(recv_data) except ValueError: - log.error('request type is not json') - await loop.sock_sendall(conn, b'[]') + await wrap_error(conn, 'request type is not json') return dialog_logger.log_in(data) model_args = [] @@ -35,18 +52,15 @@ async def handle_connection(conn: socket.socket, addr, model: Chainer, params_na if param_value is None or (isinstance(param_value, list) and len(param_value) > 0): model_args.append(param_value) else: - log.error(f"nonempty array expected but got '{param_name}'={repr(param_value)}") - await loop.sock_sendall(conn, b'[]') + await wrap_error(conn, f"nonempty array expected but got '{param_name}'={repr(param_value)}") return lengths = {len(i) for i in model_args if i is not None} if not lengths: - log.error('got empty request') - await loop.sock_sendall(conn, b'[]') + await wrap_error(conn, 'got empty request') return elif len(lengths) > 1: - log.error('got several different batch sizes') - await loop.sock_sendall(conn, b'[]') + await wrap_error(conn, 'got several different batch sizes') return batch_size = list(lengths)[0] model_args = [arg or [None] * batch_size for arg in model_args] @@ -58,9 +72,9 @@ async def handle_connection(conn: socket.socket, addr, model: Chainer, params_na if len(model.out_params) == 1: prediction = [prediction] prediction = list(zip(*prediction)) - result = json.dumps({'status': 'OK', 'payload': prediction}) + result = await response('OK', prediction) dialog_logger.log_out(result) - await loop.sock_sendall(conn, result.encode('utf-8')) + await loop.sock_sendall(conn, result) async def server(sock: socket.socket, model: Chainer, params_names: List[str], bufsize: int) -> None: @@ -93,8 +107,8 @@ def start_model_socket(model_config: Path, port: Optional[int] = None) -> None: log.info(f'socket http://{host}:{port} has successfully launched') try: loop.run_until_complete(server(s, model, model_args_names, bufsize)) - except: - pass + except Exception as e: + log.error(f'got exception {e} while running server') finally: loop.close() s.close() diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index 39e4b31895..ce4442e2a0 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -417,7 +417,7 @@ def interact_api(config_path): # raise RuntimeError('Error in shutting down API server: \n{}'.format(logfile.getvalue().decode())) @staticmethod - def interact_socket(config_path): + def interact_socket(text, config_path): logfile = io.BytesIO(b'') socket_params = get_socket_params() host = socket_params['host'] @@ -432,13 +432,12 @@ def interact_socket(config_path): p.expect(socket_url) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((host, port)) - di = {"context": ["This is DeepPavlov API python test."]} + di = {"context": [text]} di = json.dumps(di) s.sendall(di.encode('utf-8')) data = s.recv(1024) resp = json.loads(data) - assert resp['status'] == 'OK', f"Socket returned {resp['status']} with {config_path}" - assert 1 == 1 + return resp except pexpect.exceptions.EOF: raise RuntimeError('Got unexpected EOF: \n{}'.format(logfile.getvalue().decode())) finally: @@ -469,7 +468,8 @@ def test_interacting_pretrained_model_socket(self, model, conf_file, model_dir, config_file_path = str(test_configs_path.joinpath(conf_file)) install_config(config_file_path) deep_download(config_file_path) - self.interact_socket(test_configs_path / conf_file) + resp = self.interact_socket("This is DeepPavlov API python test.", test_configs_path / conf_file) + assert resp['status'] == 'OK', f"Socket returned {resp['status']}" else: pytest.skip(f"Unsupported mode: {mode}") From efc72f953fc56111c02300f766ae37e2620f650d Mon Sep 17 00:00:00 2001 From: ignatov Date: Mon, 5 Aug 2019 14:54:45 +0300 Subject: [PATCH 05/39] refactor: socket server put into class --- deeppavlov/deep.py | 4 +- deeppavlov/utils/socket/socket.py | 185 ++++++++++++++++-------------- 2 files changed, 99 insertions(+), 90 deletions(-) diff --git a/deeppavlov/deep.py b/deeppavlov/deep.py index 1bbda851c4..c3f8d92135 100644 --- a/deeppavlov/deep.py +++ b/deeppavlov/deep.py @@ -27,7 +27,7 @@ from deeppavlov.utils.ms_bot_framework.server import run_ms_bf_default_agent from deeppavlov.utils.pip_wrapper import install_from_config from deeppavlov.utils.server.server import start_model_server -from deeppavlov.utils.socket.socket import start_model_socket +from deeppavlov.utils.socket.socket import start_socket_server from deeppavlov.utils.telegram.telegram_ui import interact_model_by_telegram log = getLogger(__name__) @@ -122,7 +122,7 @@ def main(): else: start_model_server(pipeline_config_path, https, ssl_key, ssl_cert, port=args.port) elif args.mode == 'risesocket': - start_model_socket(pipeline_config_path, port=args.port) + start_socket_server(pipeline_config_path, port=args.port) elif args.mode == 'predict': predict_on_stream(pipeline_config_path, args.batch_size, args.file_path) elif args.mode == 'install': diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index 25ac7fde26..9ad9d3a849 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -3,7 +3,7 @@ import socket from logging import getLogger from pathlib import Path -from typing import Optional, List +from typing import Dict, Optional, Tuple from deeppavlov.core.agent.dialog_logger import DialogLogger from deeppavlov.core.commands.infer import build_model @@ -13,102 +13,111 @@ SOCKET_CONFIG_FILENAME = 'socket_config.json' -log = getLogger(__name__) -loop = asyncio.get_event_loop() -dialog_logger = DialogLogger(agent_name='dp_api') +class SocketServer: + _host: str + _loop: asyncio.AbstractEventLoop + _model: Chainer + _params: Dict + _port: int + _socket: socket.socket + + def __init__(self, model_config: Path, port: Optional[int] = None): + self._params = get_socket_params() + self._dialog_logger = DialogLogger(agent_name='dp_api') + self._host = self._params['host'] + self._log = getLogger(__name__) + self._loop = asyncio.get_event_loop() + self._model = build_model(model_config) + self._port = port or self._params['port'] + self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self._socket.setblocking(False) + + def start(self) -> None: + self._socket.bind((self._host, self._port)) + self._socket.listen() + self._log.info(f'launching socket at http://{self._host}:{self._port}') + try: + self._loop.run_until_complete(self._server()) + except Exception as e: + self._log.error(f'got exception {e} while running server') + finally: + self._loop.close() + self._socket.close() + + async def _server(self) -> None: + while True: + conn, addr = await self._loop.sock_accept(self._socket) + self._loop.create_task(self._handle_connection(conn, addr)) + + async def _handle_connection(self, conn: socket.socket, addr: Tuple) -> None: + self._log.info(f'handling connection from {addr}') + conn.setblocking(False) + recv_data = b'' + try: + while True: + chunk = await self._loop.run_in_executor(None, conn.recv, self._params['bufsize']) + if chunk: + recv_data += chunk + else: + break + except BlockingIOError: + pass + try: + data = json.loads(recv_data) + except ValueError: + await self._wrap_error(conn, 'request type is not json') + return + self._dialog_logger.log_in(data) + model_args = [] + for param_name in self._params['model_args_names']: + param_value = data.get(param_name) + if param_value is None or (isinstance(param_value, list) and len(param_value) > 0): + model_args.append(param_value) + else: + await self._wrap_error(conn, f"nonempty array expected but got '{param_name}'={repr(param_value)}") + return + lengths = {len(i) for i in model_args if i is not None} -async def handle_connection(conn: socket.socket, addr, model: Chainer, params_names: List[str], bufsize: int): - async def response(status, payload): + if not lengths: + await self._wrap_error(conn, 'got empty request') + return + elif len(lengths) > 1: + await self._wrap_error(conn, 'got several different batch sizes') + return + batch_size = list(lengths)[0] + model_args = [arg or [None] * batch_size for arg in model_args] + + # in case when some parameters were not described in model_args + model_args += [[None] * batch_size for _ in range(len(self._model.in_x) - len(model_args))] + + prediction = await self._loop.run_in_executor(None, self._model, *model_args) + if len(self._model.out_params) == 1: + prediction = [prediction] + prediction = list(zip(*prediction)) + result = await self._response('OK', prediction) + self._dialog_logger.log_out(result) + await self._loop.sock_sendall(conn, result) + + async def _wrap_error(self, conn: socket.socket, error: str) -> None: + self._log.error(error) + await self._loop.sock_sendall(conn, await self._response(error, '')) + + @staticmethod + async def _response(status: str, payload) -> bytes: resp_dict = {'status': status, 'payload': payload} resp_str = json.dumps(resp_dict) return resp_str.encode('utf-8') - async def wrap_error(conn, error): - log.error(error) - await loop.sock_sendall(conn, await response(error, '')) - - log.info(f'handling connection from {addr}') - conn.setblocking(False) - recv_data = b'' - try: - while True: - chunk = await loop.run_in_executor(None, conn.recv, bufsize) - if chunk: - recv_data += chunk - else: - break - except BlockingIOError: - pass - try: - data = json.loads(recv_data) - except ValueError: - await wrap_error(conn, 'request type is not json') - return - dialog_logger.log_in(data) - model_args = [] - for param_name in params_names: - param_value = data.get(param_name) - if param_value is None or (isinstance(param_value, list) and len(param_value) > 0): - model_args.append(param_value) - else: - await wrap_error(conn, f"nonempty array expected but got '{param_name}'={repr(param_value)}") - return - lengths = {len(i) for i in model_args if i is not None} - - if not lengths: - await wrap_error(conn, 'got empty request') - return - elif len(lengths) > 1: - await wrap_error(conn, 'got several different batch sizes') - return - batch_size = list(lengths)[0] - model_args = [arg or [None] * batch_size for arg in model_args] - - # in case when some parameters were not described in model_args - model_args += [[None] * batch_size for _ in range(len(model.in_x) - len(model_args))] - - prediction = await loop.run_in_executor(None, model, *model_args) - if len(model.out_params) == 1: - prediction = [prediction] - prediction = list(zip(*prediction)) - result = await response('OK', prediction) - dialog_logger.log_out(result) - await loop.sock_sendall(conn, result) - - -async def server(sock: socket.socket, model: Chainer, params_names: List[str], bufsize: int) -> None: - while True: - conn, addr = await loop.sock_accept(sock) - loop.create_task(handle_connection(conn, addr, model, params_names, bufsize)) - -def get_socket_params() -> dict: +def get_socket_params() -> Dict: socket_config_path = get_settings_path() / SOCKET_CONFIG_FILENAME socket_params = read_json(socket_config_path) return socket_params -def start_model_socket(model_config: Path, port: Optional[int] = None) -> None: - socket_params = get_socket_params() - - model_args_names = socket_params['model_args_names'] - host = socket_params['host'] - port = port or socket_params['port'] - bufsize = socket_params['bufsize'] - - model = build_model(model_config) - - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - s.setblocking(False) - s.bind((host, port)) - s.listen() - log.info(f'socket http://{host}:{port} has successfully launched') - try: - loop.run_until_complete(server(s, model, model_args_names, bufsize)) - except Exception as e: - log.error(f'got exception {e} while running server') - finally: - loop.close() - s.close() +def start_socket_server(model_config: Path, port: Optional[int] = None) -> None: + server = SocketServer(model_config, port) + server.start() From abbc05e502b6123fb93bc12fcd93a064da0f289f Mon Sep 17 00:00:00 2001 From: ignatov Date: Mon, 5 Aug 2019 16:21:45 +0300 Subject: [PATCH 06/39] refactor: added docstrings, changed socket param function also test refactor --- deeppavlov/utils/socket/socket.py | 43 +++++++++++++++++++++++++----- tests/test_quick_start.py | 44 ++++++++++++++++++------------- 2 files changed, 62 insertions(+), 25 deletions(-) diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index 9ad9d3a849..70ac559996 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -1,3 +1,17 @@ +# Copyright 2017 Neural Networks and Deep Learning lab, MIPT +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import asyncio import json import socket @@ -10,11 +24,26 @@ from deeppavlov.core.common.chainer import Chainer from deeppavlov.core.common.file import read_json from deeppavlov.core.common.paths import get_settings_path +from deeppavlov.utils.server.server import get_server_params, SERVER_CONFIG_FILENAME SOCKET_CONFIG_FILENAME = 'socket_config.json' +def get_socket_params(socket_config_path: Path, model_config: Path) -> Dict: + server_config_path = get_settings_path() / SERVER_CONFIG_FILENAME + server_params = get_server_params(server_config_path, model_config) + socket_params = read_json(socket_config_path) + socket_params['model_args_names'] = server_params['model_args_names'] + return socket_params + + class SocketServer: + """ + Class launches socket server. The data received by the socket is processed in the deeppavlov model. Sends model + response back as dictionary with two keys: + response['status']: str - 'OK' if data processed successfully, else - error message. + response['payload']: str - model response dumped with json.dumps. Empty if an error occured. + """ _host: str _loop: asyncio.AbstractEventLoop _model: Chainer @@ -23,7 +52,8 @@ class SocketServer: _socket: socket.socket def __init__(self, model_config: Path, port: Optional[int] = None): - self._params = get_socket_params() + socket_config_path = get_settings_path() / SOCKET_CONFIG_FILENAME + self._params = get_socket_params(socket_config_path, model_config) self._dialog_logger = DialogLogger(agent_name='dp_api') self._host = self._params['host'] self._log = getLogger(__name__) @@ -107,17 +137,16 @@ async def _wrap_error(self, conn: socket.socket, error: str) -> None: @staticmethod async def _response(status: str, payload) -> bytes: + """ + :param status: response status. 'OK' if no error occurred + :param payload: Deeppavlov model result + :return bytes: {'status': status, 'payload': payload} dumped as bytes array + """ resp_dict = {'status': status, 'payload': payload} resp_str = json.dumps(resp_dict) return resp_str.encode('utf-8') -def get_socket_params() -> Dict: - socket_config_path = get_settings_path() / SOCKET_CONFIG_FILENAME - socket_params = read_json(socket_config_path) - return socket_params - - def start_socket_server(model_config: Path, port: Optional[int] = None) -> None: server = SocketServer(model_config, port) server.start() diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index ce4442e2a0..e75f2804a0 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -24,7 +24,7 @@ from deeppavlov.core.data.utils import get_all_elems_from_json from deeppavlov.download import deep_download from deeppavlov.utils.server.server import get_server_params, SERVER_CONFIG_FILENAME -from deeppavlov.utils.socket.socket import get_socket_params +from deeppavlov.utils.socket.socket import get_socket_params, SOCKET_CONFIG_FILENAME tests_dir = Path(__file__).parent test_configs_path = tests_dir / "deeppavlov" / "configs" @@ -392,7 +392,7 @@ def interact_api(config_path): post_payload = {} for arg_name in model_args_names: - arg_value = str(' '.join(['qwerty'] * 10)) + arg_value = ' '.join(['qwerty'] * 10) post_payload[arg_name] = [arg_value] logfile = io.BytesIO(b'') @@ -417,12 +417,23 @@ def interact_api(config_path): # raise RuntimeError('Error in shutting down API server: \n{}'.format(logfile.getvalue().decode())) @staticmethod - def interact_socket(text, config_path): - logfile = io.BytesIO(b'') - socket_params = get_socket_params() + def interact_socket(config_path): + socket_conf_file = get_settings_path() / SOCKET_CONFIG_FILENAME + + socket_params = get_socket_params(socket_conf_file, config_path) + model_args_names = socket_params['model_args_names'] + host = socket_params['host'] port = api_port or socket_params['port'] socket_url = f'http://{host}:{port}' + + socket_payload = {} + for arg_name in model_args_names: + arg_value = ' '.join(['qwerty'] * 10) + socket_payload[arg_name] = [arg_value] + dumped_socket_payload = json.dumps(socket_payload) + + logfile = io.BytesIO(b'') args = [sys.executable, "-m", "deeppavlov", "risesocket", str(config_path)] if api_port: args += ['-p', str(api_port)] @@ -432,14 +443,15 @@ def interact_socket(text, config_path): p.expect(socket_url) with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((host, port)) - di = {"context": [text]} - di = json.dumps(di) - s.sendall(di.encode('utf-8')) + s.sendall(dumped_socket_payload.encode('utf-8')) data = s.recv(1024) resp = json.loads(data) - return resp + print(resp) + assert resp['status'] == 'OK', f"socket request returned status: {resp['status']} with {config_path}" + except pexpect.exceptions.EOF: raise RuntimeError('Got unexpected EOF: \n{}'.format(logfile.getvalue().decode())) + finally: p.kill(signal.SIGTERM) p.wait() @@ -457,19 +469,15 @@ def test_interacting_pretrained_model(self, model, conf_file, model_dir, mode): def test_interacting_pretrained_model_api(self, model, conf_file, model_dir, mode): if 'IP' in mode: self.interact_api(test_configs_path / conf_file) - - if 'TI' not in mode: - shutil.rmtree(str(download_path), ignore_errors=True) else: pytest.skip("Unsupported mode: {}".format(mode)) def test_interacting_pretrained_model_socket(self, model, conf_file, model_dir, mode): - if 'IP' in mode and conf_file == "ner/ner_ontonotes.json": - config_file_path = str(test_configs_path.joinpath(conf_file)) - install_config(config_file_path) - deep_download(config_file_path) - resp = self.interact_socket("This is DeepPavlov API python test.", test_configs_path / conf_file) - assert resp['status'] == 'OK', f"Socket returned {resp['status']}" + if 'IP' in mode: + self.interact_socket(test_configs_path / conf_file) + + if 'TI' not in mode: + shutil.rmtree(str(download_path), ignore_errors=True) else: pytest.skip(f"Unsupported mode: {mode}") From 934ee3323e9a5b23649d16f2682c9717a825a03a Mon Sep 17 00:00:00 2001 From: ignatov Date: Mon, 5 Aug 2019 16:24:38 +0300 Subject: [PATCH 07/39] refactor: in SocketServer docstring --- deeppavlov/utils/socket/socket.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index 70ac559996..04ac425cca 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -39,8 +39,8 @@ def get_socket_params(socket_config_path: Path, model_config: Path) -> Dict: class SocketServer: """ - Class launches socket server. The data received by the socket is processed in the deeppavlov model. Sends model - response back as dictionary with two keys: + Class with socket server. The data received by the socket is processed in the deeppavlov model. Sends model + response back as dictionary with two keys - 'status' and 'payload': response['status']: str - 'OK' if data processed successfully, else - error message. response['payload']: str - model response dumped with json.dumps. Empty if an error occured. """ From e9b36b7936bdcf313f1ffaea0a19022ea8bffd23 Mon Sep 17 00:00:00 2001 From: ignatov Date: Mon, 5 Aug 2019 16:54:17 +0300 Subject: [PATCH 08/39] refactor: socket params now independent from server params --- deeppavlov/utils/settings/socket_config.json | 19 +++++++++++++++---- deeppavlov/utils/socket/socket.py | 17 ++++++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/deeppavlov/utils/settings/socket_config.json b/deeppavlov/utils/settings/socket_config.json index c0ae8a7e9c..68637d14be 100644 --- a/deeppavlov/utils/settings/socket_config.json +++ b/deeppavlov/utils/settings/socket_config.json @@ -1,6 +1,17 @@ { - "host": "0.0.0.0", - "port": 5001, - "model_args_names": ["context"], - "bufsize": 1024 + "common_defaults":{ + "host": "0.0.0.0", + "port": 5001, + "socket_type": "TCP", + "model_args_names": ["context"], + "bufsize": 1024 + }, + "model_defaults": { + "EcommerceSkill": { + "model_args_names": ["query", "history", "state"] + }, + "SquadModel": { + "model_args_names": ["context", "question"] + } + } } \ No newline at end of file diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index 04ac425cca..706242995e 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -21,19 +21,26 @@ from deeppavlov.core.agent.dialog_logger import DialogLogger from deeppavlov.core.commands.infer import build_model +from deeppavlov.core.commands.utils import parse_config from deeppavlov.core.common.chainer import Chainer from deeppavlov.core.common.file import read_json from deeppavlov.core.common.paths import get_settings_path -from deeppavlov.utils.server.server import get_server_params, SERVER_CONFIG_FILENAME +from deeppavlov.core.data.utils import check_nested_dict_keys SOCKET_CONFIG_FILENAME = 'socket_config.json' def get_socket_params(socket_config_path: Path, model_config: Path) -> Dict: - server_config_path = get_settings_path() / SERVER_CONFIG_FILENAME - server_params = get_server_params(server_config_path, model_config) - socket_params = read_json(socket_config_path) - socket_params['model_args_names'] = server_params['model_args_names'] + socket_config = read_json(socket_config_path) + model_config = parse_config(model_config) + + socket_params = socket_config['common_defaults'] + + if check_nested_dict_keys(model_config, ['metadata', 'labels', 'server_utils']): + model_tag = model_config['metadata']['labels']['server_utils'] + if model_tag in socket_config['model_defaults']: + model_defaults = socket_config['model_defaults'][model_tag] + socket_params.update(model_defaults) return socket_params From 8c4125f8f00ccdf8c03597ba7571df5703149e17 Mon Sep 17 00:00:00 2001 From: ignatov Date: Mon, 5 Aug 2019 17:47:06 +0300 Subject: [PATCH 09/39] feat: starting to add UNIX socket --- deeppavlov/deep.py | 4 ++- deeppavlov/utils/settings/socket_config.json | 1 + deeppavlov/utils/socket/socket.py | 26 ++++++++++++-------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/deeppavlov/deep.py b/deeppavlov/deep.py index c3f8d92135..6cbf0b5aed 100644 --- a/deeppavlov/deep.py +++ b/deeppavlov/deep.py @@ -62,6 +62,8 @@ parser.add_argument("--cert", default=None, help="ssl certificate", type=str) parser.add_argument("-p", "--port", default=None, help="api port", type=int) +parser.add_argument("--socket-type", default=None, type=str, choices={"TCP", "UNIX"}) +parser.add_argument("--socket-file", default="/tmp/deeppavlov_socket.s", type=str) parser.add_argument("--api-mode", help="rest api mode: 'basic' with batches or 'alice' for Yandex.Dialogs format", type=str, default='basic', choices={'basic', 'alice'}) @@ -122,7 +124,7 @@ def main(): else: start_model_server(pipeline_config_path, https, ssl_key, ssl_cert, port=args.port) elif args.mode == 'risesocket': - start_socket_server(pipeline_config_path, port=args.port) + start_socket_server(pipeline_config_path, args.socket_type, port=args.port, file=args.socket_file) elif args.mode == 'predict': predict_on_stream(pipeline_config_path, args.batch_size, args.file_path) elif args.mode == 'install': diff --git a/deeppavlov/utils/settings/socket_config.json b/deeppavlov/utils/settings/socket_config.json index 68637d14be..28a7764b94 100644 --- a/deeppavlov/utils/settings/socket_config.json +++ b/deeppavlov/utils/settings/socket_config.json @@ -2,6 +2,7 @@ "common_defaults":{ "host": "0.0.0.0", "port": 5001, + "unix_socket_file": "/tmp/deeppavlov_socket.s", "socket_type": "TCP", "model_args_names": ["context"], "bufsize": 1024 diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index 706242995e..05124eeff8 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -14,10 +14,11 @@ import asyncio import json +import os import socket from logging import getLogger from pathlib import Path -from typing import Dict, Optional, Tuple +from typing import Dict, Optional, Tuple, Union from deeppavlov.core.agent.dialog_logger import DialogLogger from deeppavlov.core.commands.infer import build_model @@ -51,31 +52,36 @@ class SocketServer: response['status']: str - 'OK' if data processed successfully, else - error message. response['payload']: str - model response dumped with json.dumps. Empty if an error occured. """ - _host: str + _bind_address: Union[Tuple, str] + _launch_msg: str _loop: asyncio.AbstractEventLoop _model: Chainer _params: Dict - _port: int _socket: socket.socket + _socket_type: str - def __init__(self, model_config: Path, port: Optional[int] = None): + def __init__(self, model_config: Path, socket_type: str, port: Optional[int] = None, socket_file: Optional[str] = None): socket_config_path = get_settings_path() / SOCKET_CONFIG_FILENAME self._params = get_socket_params(socket_config_path, model_config) + self._socket_type = socket_type or self._params['socket_type'] + if self._socket_type == 'TCP': + host = self._params['host'] + port = port or self._params['port'] + self._launch_msg = f'launching socket at http://{host}:{port}' + self._bind_address = (host, port) self._dialog_logger = DialogLogger(agent_name='dp_api') - self._host = self._params['host'] self._log = getLogger(__name__) self._loop = asyncio.get_event_loop() self._model = build_model(model_config) - self._port = port or self._params['port'] self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._socket.setblocking(False) def start(self) -> None: - self._socket.bind((self._host, self._port)) + self._socket.bind(self._bind_address) self._socket.listen() - self._log.info(f'launching socket at http://{self._host}:{self._port}') + self._log.info(self._launch_msg) try: self._loop.run_until_complete(self._server()) except Exception as e: @@ -154,6 +160,6 @@ async def _response(status: str, payload) -> bytes: return resp_str.encode('utf-8') -def start_socket_server(model_config: Path, port: Optional[int] = None) -> None: - server = SocketServer(model_config, port) +def start_socket_server(model_config: Path, socket_type: str, port: Optional[int], file: Optional[str]) -> None: + server = SocketServer(model_config, socket_type, port, file) server.start() From 53d677c771645bac4b4215541f54ea20326914ba Mon Sep 17 00:00:00 2001 From: ignatov Date: Mon, 5 Aug 2019 18:26:07 +0300 Subject: [PATCH 10/39] feat: added UNIX socket Added tests on both TCP and UNIX sockets --- deeppavlov/deep.py | 2 +- deeppavlov/utils/settings/socket_config.json | 3 +- deeppavlov/utils/socket/socket.py | 13 +++++++-- tests/test_quick_start.py | 30 +++++++++++++------- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/deeppavlov/deep.py b/deeppavlov/deep.py index 6cbf0b5aed..81c554935f 100644 --- a/deeppavlov/deep.py +++ b/deeppavlov/deep.py @@ -62,7 +62,7 @@ parser.add_argument("--cert", default=None, help="ssl certificate", type=str) parser.add_argument("-p", "--port", default=None, help="api port", type=int) -parser.add_argument("--socket-type", default=None, type=str, choices={"TCP", "UNIX"}) +parser.add_argument("--socket-type", default='TCP', type=str, choices={"TCP", "UNIX"}) parser.add_argument("--socket-file", default="/tmp/deeppavlov_socket.s", type=str) parser.add_argument("--api-mode", help="rest api mode: 'basic' with batches or 'alice' for Yandex.Dialogs format", diff --git a/deeppavlov/utils/settings/socket_config.json b/deeppavlov/utils/settings/socket_config.json index 28a7764b94..170b25ecff 100644 --- a/deeppavlov/utils/settings/socket_config.json +++ b/deeppavlov/utils/settings/socket_config.json @@ -5,7 +5,8 @@ "unix_socket_file": "/tmp/deeppavlov_socket.s", "socket_type": "TCP", "model_args_names": ["context"], - "bufsize": 1024 + "bufsize": 1024, + "binding_message": "binding socket to" }, "model_defaults": { "EcommerceSkill": { diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index 05124eeff8..a12019ed26 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -64,16 +64,25 @@ def __init__(self, model_config: Path, socket_type: str, port: Optional[int] = N socket_config_path = get_settings_path() / SOCKET_CONFIG_FILENAME self._params = get_socket_params(socket_config_path, model_config) self._socket_type = socket_type or self._params['socket_type'] + if self._socket_type == 'TCP': host = self._params['host'] port = port or self._params['port'] - self._launch_msg = f'launching socket at http://{host}:{port}' + self._address_family = socket.AF_INET + self._launch_msg = f'{self._params["binding_message"]} http://{host}:{port}' self._bind_address = (host, port) + elif self._socket_type == 'UNIX': + self._address_family = socket.AF_UNIX + self._bind_address = socket_file or self._params['unix_socket_file'] + if os.path.exists(self._bind_address): + os.remove(self._bind_address) + self._launch_msg = f'{self._params["binding_message"]} {self._bind_address}' + self._dialog_logger = DialogLogger(agent_name='dp_api') self._log = getLogger(__name__) self._loop = asyncio.get_event_loop() self._model = build_model(model_config) - self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._socket = socket.socket(self._address_family, socket.SOCK_STREAM) self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._socket.setblocking(False) diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index e75f2804a0..67fbe9bb74 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -417,7 +417,7 @@ def interact_api(config_path): # raise RuntimeError('Error in shutting down API server: \n{}'.format(logfile.getvalue().decode())) @staticmethod - def interact_socket(config_path): + def interact_socket(config_path, socket_type): socket_conf_file = get_settings_path() / SOCKET_CONFIG_FILENAME socket_params = get_socket_params(socket_conf_file, config_path) @@ -425,7 +425,6 @@ def interact_socket(config_path): host = socket_params['host'] port = api_port or socket_params['port'] - socket_url = f'http://{host}:{port}' socket_payload = {} for arg_name in model_args_names: @@ -434,19 +433,24 @@ def interact_socket(config_path): dumped_socket_payload = json.dumps(socket_payload) logfile = io.BytesIO(b'') - args = [sys.executable, "-m", "deeppavlov", "risesocket", str(config_path)] - if api_port: - args += ['-p', str(api_port)] + args = [sys.executable, "-m", "deeppavlov", "risesocket", str(config_path), '--socket-type', socket_type] + if socket_type == 'TCP': + if api_port: + args += ['-p', str(api_port)] + address_family = socket.AF_INET + connect_arg = (host, port) + else: + address_family = socket.AF_UNIX + connect_arg = socket_params['unix_socket_file'] p = pexpect.popen_spawn.PopenSpawn(' '.join(args), timeout=None, logfile=logfile) try: - p.expect(socket_url) - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.connect((host, port)) + p.expect(socket_params['binding_message']) + with socket.socket(address_family, socket.SOCK_STREAM) as s: + s.connect(connect_arg) s.sendall(dumped_socket_payload.encode('utf-8')) data = s.recv(1024) resp = json.loads(data) - print(resp) assert resp['status'] == 'OK', f"socket request returned status: {resp['status']} with {config_path}" except pexpect.exceptions.EOF: @@ -473,8 +477,12 @@ def test_interacting_pretrained_model_api(self, model, conf_file, model_dir, mod pytest.skip("Unsupported mode: {}".format(mode)) def test_interacting_pretrained_model_socket(self, model, conf_file, model_dir, mode): - if 'IP' in mode: - self.interact_socket(test_configs_path / conf_file) + if 'IP' in mode and conf_file == "ner/ner_ontonotes.json": + config_file_path = str(test_configs_path.joinpath(conf_file)) + install_config(config_file_path) + deep_download(config_file_path) + for socket_type in ['TCP', 'UNIX']: + self.interact_socket(test_configs_path / conf_file, socket_type) if 'TI' not in mode: shutil.rmtree(str(download_path), ignore_errors=True) From 91f9029c66f2dbfd80094f46433973147a1f0c62 Mon Sep 17 00:00:00 2001 From: ignatov Date: Mon, 5 Aug 2019 18:27:06 +0300 Subject: [PATCH 11/39] fix: removed restriction that tests sockets only on NER --- tests/test_quick_start.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index 67fbe9bb74..a37ff96fdc 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -477,10 +477,7 @@ def test_interacting_pretrained_model_api(self, model, conf_file, model_dir, mod pytest.skip("Unsupported mode: {}".format(mode)) def test_interacting_pretrained_model_socket(self, model, conf_file, model_dir, mode): - if 'IP' in mode and conf_file == "ner/ner_ontonotes.json": - config_file_path = str(test_configs_path.joinpath(conf_file)) - install_config(config_file_path) - deep_download(config_file_path) + if 'IP' in mode: for socket_type in ['TCP', 'UNIX']: self.interact_socket(test_configs_path / conf_file, socket_type) From 85607b2ed69ed039e97747c555511ab65596cb31 Mon Sep 17 00:00:00 2001 From: ignatov Date: Tue, 6 Aug 2019 11:56:51 +0300 Subject: [PATCH 12/39] fix: fixed response receive in socket test --- tests/test_quick_start.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index a37ff96fdc..5112b26f36 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -449,7 +449,17 @@ def interact_socket(config_path, socket_type): with socket.socket(address_family, socket.SOCK_STREAM) as s: s.connect(connect_arg) s.sendall(dumped_socket_payload.encode('utf-8')) - data = s.recv(1024) + data = b'' + try: + while True: + buf = s.recv(1024) + s.setblocking(False) + if buf: + data += buf + else: + break + except BlockingIOError: + pass resp = json.loads(data) assert resp['status'] == 'OK', f"socket request returned status: {resp['status']} with {config_path}" From eb04f23b9ec3f504c60326d10dfe074f616a9405 Mon Sep 17 00:00:00 2001 From: ignatov Date: Wed, 7 Aug 2019 11:30:03 +0300 Subject: [PATCH 13/39] fix: api_port type to int --- tests/test_quick_start.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index 5112b26f36..14349c206b 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -36,7 +36,7 @@ if not os.getenv('DP_PYTEST_NO_CACHE'): cache_dir = tests_dir / 'download_cache' -api_port = os.getenv('DP_PYTEST_API_PORT') +api_port = int(os.getenv('DP_PYTEST_API_PORT')) TEST_MODES = ['IP', # test_interacting_pretrained_model 'TI', # test_consecutive_training_and_interacting From 1b65895736d8a1d1d896dec43c698d0754785858 Mon Sep 17 00:00:00 2001 From: ignatov Date: Wed, 7 Aug 2019 14:05:48 +0300 Subject: [PATCH 14/39] refactor: more pretty code --- deeppavlov/core/data/utils.py | 5 ++--- deeppavlov/utils/socket/socket.py | 3 ++- tests/test_quick_start.py | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/deeppavlov/core/data/utils.py b/deeppavlov/core/data/utils.py index 10e5ef3592..bb2f2cf79a 100644 --- a/deeppavlov/core/data/utils.py +++ b/deeppavlov/core/data/utils.py @@ -413,10 +413,9 @@ def jsonify_data(data): result[key] = jsonify_data(data[key]) elif isinstance(data, np.ndarray): result = data.tolist() - elif isinstance(data, (np.int_, np.intc, np.intp, np.int8, np.int16, np.int32, - np.int64, np.uint8, np.uint16, np.uint32, np.uint64)): + elif isinstance(data, np.integer): result = int(data) - elif isinstance(data, (np.float_, np.float16, np.float32, np.float64)): + elif isinstance(data, np.floating): result = float(data) else: result = data diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index a12019ed26..ce46815966 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -60,7 +60,8 @@ class SocketServer: _socket: socket.socket _socket_type: str - def __init__(self, model_config: Path, socket_type: str, port: Optional[int] = None, socket_file: Optional[str] = None): + def __init__(self, model_config: Path, socket_type: str, port: Optional[int] = None, + socket_file: Optional[str] = None): socket_config_path = get_settings_path() / SOCKET_CONFIG_FILENAME self._params = get_socket_params(socket_config_path, model_config) self._socket_type = socket_type or self._params['socket_type'] diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index 14349c206b..65af5cd365 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -435,8 +435,7 @@ def interact_socket(config_path, socket_type): logfile = io.BytesIO(b'') args = [sys.executable, "-m", "deeppavlov", "risesocket", str(config_path), '--socket-type', socket_type] if socket_type == 'TCP': - if api_port: - args += ['-p', str(api_port)] + args += ['-p', str(port)] address_family = socket.AF_INET connect_arg = (host, port) else: From 25f69b0d65db6a7c7beca409eeceb92709b190d8 Mon Sep 17 00:00:00 2001 From: ignatov Date: Wed, 7 Aug 2019 14:06:28 +0300 Subject: [PATCH 15/39] fix: correct api_port handling --- tests/test_quick_start.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index 65af5cd365..c1503ba469 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -36,7 +36,9 @@ if not os.getenv('DP_PYTEST_NO_CACHE'): cache_dir = tests_dir / 'download_cache' -api_port = int(os.getenv('DP_PYTEST_API_PORT')) +api_port = os.getenv('DP_PYTEST_API_PORT') +if api_port is not None: + api_port = int(api_port) TEST_MODES = ['IP', # test_interacting_pretrained_model 'TI', # test_consecutive_training_and_interacting From c14af0df6e8cf2c58c0434d9bafb362aec08528d Mon Sep 17 00:00:00 2001 From: ignatov Date: Wed, 7 Aug 2019 14:07:11 +0300 Subject: [PATCH 16/39] fix: correct socket test if model return numpy date Earlier test failed --- deeppavlov/utils/socket/socket.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index ce46815966..49354ca35e 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -26,7 +26,7 @@ from deeppavlov.core.common.chainer import Chainer from deeppavlov.core.common.file import read_json from deeppavlov.core.common.paths import get_settings_path -from deeppavlov.core.data.utils import check_nested_dict_keys +from deeppavlov.core.data.utils import check_nested_dict_keys, jsonify_data SOCKET_CONFIG_FILENAME = 'socket_config.json' @@ -50,7 +50,7 @@ class SocketServer: Class with socket server. The data received by the socket is processed in the deeppavlov model. Sends model response back as dictionary with two keys - 'status' and 'payload': response['status']: str - 'OK' if data processed successfully, else - error message. - response['payload']: str - model response dumped with json.dumps. Empty if an error occured. + response['payload']: str - model response dumped to bytes. Empty if an error occured. """ _bind_address: Union[Tuple, str] _launch_msg: str @@ -165,7 +165,7 @@ async def _response(status: str, payload) -> bytes: :param payload: Deeppavlov model result :return bytes: {'status': status, 'payload': payload} dumped as bytes array """ - resp_dict = {'status': status, 'payload': payload} + resp_dict = jsonify_data({'status': status, 'payload': payload}) resp_str = json.dumps(resp_dict) return resp_str.encode('utf-8') From 7d7c9cfcb200722f256f67337a6a6a827e7b4540 Mon Sep 17 00:00:00 2001 From: ignatov Date: Thu, 8 Aug 2019 14:34:29 +0300 Subject: [PATCH 17/39] refactor: socket.py * Changed docstrings according to Google style * Fixes in typing * os module functions substituted by pathlib.Path --- deeppavlov/deep.py | 2 +- deeppavlov/utils/socket/socket.py | 70 ++++++++++++++++++++++--------- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/deeppavlov/deep.py b/deeppavlov/deep.py index 81c554935f..3439935343 100644 --- a/deeppavlov/deep.py +++ b/deeppavlov/deep.py @@ -124,7 +124,7 @@ def main(): else: start_model_server(pipeline_config_path, https, ssl_key, ssl_cert, port=args.port) elif args.mode == 'risesocket': - start_socket_server(pipeline_config_path, args.socket_type, port=args.port, file=args.socket_file) + start_socket_server(pipeline_config_path, args.socket_type, port=args.port, socket_file=args.socket_file) elif args.mode == 'predict': predict_on_stream(pipeline_config_path, args.batch_size, args.file_path) elif args.mode == 'install': diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index 49354ca35e..6eb761b7af 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -14,11 +14,10 @@ import asyncio import json -import os import socket from logging import getLogger from pathlib import Path -from typing import Dict, Optional, Tuple, Union +from typing import Dict, List, Optional, Tuple, Union from deeppavlov.core.agent.dialog_logger import DialogLogger from deeppavlov.core.commands.infer import build_model @@ -46,13 +45,22 @@ def get_socket_params(socket_config_path: Path, model_config: Path) -> Dict: class SocketServer: + """Creates socket server that sends the received data to the Deeppavlov model and returns model response. + + The server receives dictionary serialized to JSON formatted bytes array and sends it to the model. The dictionary + keys should match model arguments names, the values should be lists or tuples of inferenced values. + + Example: + {“context”:[“Elon Musk launched his cherry Tesla roadster to the Mars orbit”]} + + Socket server returns dictionary {'status': status, 'payload': payload} serialized to a JSON formatted byte array, + where: + status (str): 'OK' if the model successfully processed the data, else - error message. + payload: (Optional[List[Tuple]]): The model result if no error has occurred, otherwise None + """ - Class with socket server. The data received by the socket is processed in the deeppavlov model. Sends model - response back as dictionary with two keys - 'status' and 'payload': - response['status']: str - 'OK' if data processed successfully, else - error message. - response['payload']: str - model response dumped to bytes. Empty if an error occured. - """ - _bind_address: Union[Tuple, str] + _address_family: socket.AddressFamily + _bind_address: Union[Tuple[str, int], str] _launch_msg: str _loop: asyncio.AbstractEventLoop _model: Chainer @@ -61,7 +69,18 @@ class SocketServer: _socket_type: str def __init__(self, model_config: Path, socket_type: str, port: Optional[int] = None, - socket_file: Optional[str] = None): + socket_file: Optional[Union[str, Path]] = None) -> None: + """Initialize socket server. + + Args: + model_config: Path to the config file. + socket_type: Socket family. "TCP" for the AF_INET socket, "UNIX" for the AF_UNIX. + port: Port number for the AF_INET address family. If parameter is not defined, the port number from the + model_config is used. + socket_file: Path to the file to which server of the AF_UNIX address family connects. If parameter + is not defined, the path from the model_config is used. + + """ socket_config_path = get_settings_path() / SOCKET_CONFIG_FILENAME self._params = get_socket_params(socket_config_path, model_config) self._socket_type = socket_type or self._params['socket_type'] @@ -74,10 +93,14 @@ def __init__(self, model_config: Path, socket_type: str, port: Optional[int] = N self._bind_address = (host, port) elif self._socket_type == 'UNIX': self._address_family = socket.AF_UNIX - self._bind_address = socket_file or self._params['unix_socket_file'] - if os.path.exists(self._bind_address): - os.remove(self._bind_address) + bind_address = socket_file or self._params['unix_socket_file'] + bind_address = Path(bind_address).resolve() + if bind_address.exists(): + bind_address.unlink() + self._bind_address = str(bind_address) self._launch_msg = f'{self._params["binding_message"]} {self._bind_address}' + else: + raise ValueError(f'socket type "{self._socket_type}" is not supported') self._dialog_logger = DialogLogger(agent_name='dp_api') self._log = getLogger(__name__) @@ -89,6 +112,7 @@ def __init__(self, model_config: Path, socket_type: str, port: Optional[int] = N self._socket.setblocking(False) def start(self) -> None: + """Binds the socket to the address and enables the server to accept connections""" self._socket.bind(self._bind_address) self._socket.listen() self._log.info(self._launch_msg) @@ -156,20 +180,26 @@ async def _handle_connection(self, conn: socket.socket, addr: Tuple) -> None: async def _wrap_error(self, conn: socket.socket, error: str) -> None: self._log.error(error) - await self._loop.sock_sendall(conn, await self._response(error, '')) + await self._loop.sock_sendall(conn, await self._response(error, None)) @staticmethod - async def _response(status: str, payload) -> bytes: - """ - :param status: response status. 'OK' if no error occurred - :param payload: Deeppavlov model result - :return bytes: {'status': status, 'payload': payload} dumped as bytes array + async def _response(status: str, payload: Optional[List[Tuple]]) -> bytes: + """Puts arguments into dict and serialize it to JSON formatted byte array. + + Args: + status: Response status. 'OK' if no error has occurred, otherwise error message. + payload: Deeppavlov model result if no error has occurred, otherwise None. + + Returns: + dict({'status': status, 'payload': payload}) serialized to a JSON formatted byte array. + """ resp_dict = jsonify_data({'status': status, 'payload': payload}) resp_str = json.dumps(resp_dict) return resp_str.encode('utf-8') -def start_socket_server(model_config: Path, socket_type: str, port: Optional[int], file: Optional[str]) -> None: - server = SocketServer(model_config, socket_type, port, file) +def start_socket_server(model_config: Path, socket_type: str, port: Optional[int], + socket_file: Optional[Union[str, Path]]) -> None: + server = SocketServer(model_config, socket_type, port, socket_file) server.start() From e20b0884da281559c31d1e95cde62b1be04c4390 Mon Sep 17 00:00:00 2001 From: ignatov Date: Thu, 8 Aug 2019 19:09:45 +0300 Subject: [PATCH 18/39] docs: added resesocket mode to the quickstart and integration sections --- docs/index.rst | 1 + docs/integrations/socket_api.rst | 122 +++++++++++++++++++++++++++++++ docs/intro/quick_start.rst | 2 + 3 files changed, 125 insertions(+) create mode 100644 docs/integrations/socket_api.rst diff --git a/docs/index.rst b/docs/index.rst index 8fc6ba862b..d077f9b02a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -29,6 +29,7 @@ Welcome to DeepPavlov's documentation! :caption: Integrations REST API + Socket API Telegram integration Yandex Alice integration Amazon Alexa integration diff --git a/docs/integrations/socket_api.rst b/docs/integrations/socket_api.rst new file mode 100644 index 0000000000..6161dc8013 --- /dev/null +++ b/docs/integrations/socket_api.rst @@ -0,0 +1,122 @@ +Socket API +========== + +Each DeepPavlov model can be made available as a socket server. The general +method is: + +.. code:: bash + + python -m deeppavlov risesocket [-d] [--socket-type ] [-p ] \ + [--socket-file ] + + +* ``-d``: downloads model specific data before starting the service. +* ``--socket-type ``: sets socket address family to ``AF_INET`` + if ```` is ``TCP`` or to ``AF_UNIX`` if ```` + is ``UNIX``. Overrides default settings from + ``deeppavlov/utils/settings/socket_config.json``. +* ``-p ``: sets the port to ```` if socket address family is + ``AF_INET``. Overrides default settings from + ``deeppavlov/utils/settings/socket_config.json``. +* ``--socket-file ``: sets the file for socket binding to + ```` if socket address family is ``AF_UNIX``. Overrides + default settings from ``deeppavlov/utils/settings/socket_config.json``. + +The command will print the binding address: host and port for ``AF_INET`` +socket family and path to the UNIX socket file for ``AF_UNIX`` socket family. +Default service properties (socket address family, host, port, path to the UNIX +socket file, socket buffer size, binding message) can be modified via changing +``deeppavlov/utils/settings/socket_config.json`` file. + +Advanced configuration +~~~~~~~~~~~~~~~~~~~~~~ + +By modifying ``deeppavlov/utils/settings/socket_config.json`` you can change +socket address family, host, port, path to the UNIX socket file and other +properties of the API service. + +Properties from ``common_defaults`` section are used by default unless they are +overridden by model-specific properties, provided in ``model_defaults`` section +of the ``socket_config.json``. Model-specific properties are bound to the model +by ``server_utils`` label in ``metadata/labels`` section of the model config. +Value of ``server_utils`` label from model config should match with properties +key from ``model_defaults`` section of ``socket_config.json``. + +For example, ``metadata/labels/server_utils`` tag from +``deeppavlov/configs/squad/squad.json`` references to the *SquadModel* section +of ``socket_config.json``. Therefore, ``model_args_names`` (see details below) +parameter in ``common_defaults`` will be overridden with the same parameter +from ``model_defaults/SquadModel``. + +Model argument names are provided as list in ``model_args_names`` parameter, +where arguments order corresponds to model API. When inferencing model via +socket API, serialized JSON payload keys should match model arguments names from +``model_args_names``. Default argument name for one argument models is +*"context"*. Here are server request examples for some of the library models: + ++-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ +| Model | POST request JSON payload example | ++=========================================+=================================================================================================================================================+ +| **One argument models** | ++-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ +| NER model | {"context":["Elon Musk launched his cherry Tesla roadster to the Mars orbit"]} | ++-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ +| Intent classification model | {"context":["I would like to go to a restaurant with Asian cuisine this evening"]} | ++-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ +| Automatic spelling correction model | {"context":["errror"]} | ++-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ +| Ranking model | {"context":["What is the average cost of life insurance services?"]} | ++-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ +| Goal-oriented bot | {"context":["Hello, can you help me to find and book a restaurant this evening?"]} | ++-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ +| **Multiple arguments models** | ++-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ +| Question Answering model | | {"context":["After 1765, growing philosophical and political differences strained the relationship between Great Britain and its colonies."], | +| | |  "question":["What strained the relationship between Great Britain and its colonies?"]} | ++-----------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------+ + +Socket client example (Python) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Socket client for :doc:`SQuAD ` model with a batch of +two elements: + +.. code-block:: python + + # squad-client.py + + import json + import socket + + socket_payload = { + "context": [ + "All work and no play makes Jack a dull boy", + "I used to be an adventurer like you, then I took an arrow in the knee." + ], + "question": [ + "What makes Jack a dull boy?", + "Who I used to be?" + ] + } + dumped_socket_payload = json.dumps(socket_payload) + + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.connect(('0.0.0.0', 5000)) + s.sendall(dumped_socket_payload.encode('utf-8')) + serialized_payload = s.recv(1024) + json_payload = json.loads(serialized_payload) + + print(json_payload) + +To start socket server with ``squad_bert`` model run: + +.. code:: bash + + python -m deeppavlov risesocket -d squad_bert --socket-type TCP -p 5000 + + +To start socket client on another terminal run: + +.. code:: bash + + python squad-client.py diff --git a/docs/intro/quick_start.rst b/docs/intro/quick_start.rst index c2fb7195a3..db70fdc193 100644 --- a/docs/intro/quick_start.rst +++ b/docs/intro/quick_start.rst @@ -67,6 +67,8 @@ There are even more actions you can perform with configs: * ``interact`` to interact via CLI, * ``riseapi`` to run a REST API server (see :doc:`docs `), + * ``risesocket`` to run a socket API server (see :doc:`docs + `), * ``interactbot`` to run as a Telegram bot (see :doc:`docs `), * ``interactmsbot`` to run a Miscrosoft Bot Framework server (see From 652c2454e6bd3422e437cd6b69f11e3887825ed7 Mon Sep 17 00:00:00 2001 From: ignatov Date: Mon, 12 Aug 2019 14:57:03 +0300 Subject: [PATCH 19/39] fix: removed UNIX sockets from test, small refactor --- deeppavlov/utils/socket/socket.py | 4 ++-- tests/test_quick_start.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index 6eb761b7af..0f8aab16c9 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -45,7 +45,7 @@ def get_socket_params(socket_config_path: Path, model_config: Path) -> Dict: class SocketServer: - """Creates socket server that sends the received data to the Deeppavlov model and returns model response. + """Creates socket server that sends the received data to the DeepPavlov model and returns model response. The server receives dictionary serialized to JSON formatted bytes array and sends it to the model. The dictionary keys should match model arguments names, the values should be lists or tuples of inferenced values. @@ -188,7 +188,7 @@ async def _response(status: str, payload: Optional[List[Tuple]]) -> bytes: Args: status: Response status. 'OK' if no error has occurred, otherwise error message. - payload: Deeppavlov model result if no error has occurred, otherwise None. + payload: DeepPavlov model result if no error has occurred, otherwise None. Returns: dict({'status': status, 'payload': payload}) serialized to a JSON formatted byte array. diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index c1503ba469..9cd3b81364 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -462,7 +462,8 @@ def interact_socket(config_path, socket_type): except BlockingIOError: pass resp = json.loads(data) - assert resp['status'] == 'OK', f"socket request returned status: {resp['status']} with {config_path}" + assert resp['status'] == 'OK', f"{socket_type} socket request returned status: {resp['status']}"\ + " with {config_path}" except pexpect.exceptions.EOF: raise RuntimeError('Got unexpected EOF: \n{}'.format(logfile.getvalue().decode())) @@ -489,7 +490,7 @@ def test_interacting_pretrained_model_api(self, model, conf_file, model_dir, mod def test_interacting_pretrained_model_socket(self, model, conf_file, model_dir, mode): if 'IP' in mode: - for socket_type in ['TCP', 'UNIX']: + for socket_type in ['TCP']: self.interact_socket(test_configs_path / conf_file, socket_type) if 'TI' not in mode: From 6462470af1399d7a062fd5b676892aecf673a7fc Mon Sep 17 00:00:00 2001 From: ignatov Date: Mon, 12 Aug 2019 15:02:54 +0300 Subject: [PATCH 20/39] refactor: changed call of interact_socket function in tests --- tests/test_quick_start.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index 9cd3b81364..ed9e6c38c0 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -490,8 +490,7 @@ def test_interacting_pretrained_model_api(self, model, conf_file, model_dir, mod def test_interacting_pretrained_model_socket(self, model, conf_file, model_dir, mode): if 'IP' in mode: - for socket_type in ['TCP']: - self.interact_socket(test_configs_path / conf_file, socket_type) + self.interact_socket(test_configs_path / conf_file, 'TCP') if 'TI' not in mode: shutil.rmtree(str(download_path), ignore_errors=True) From 92c3349bab3d81cfff43f9d5b3fafbee9e669385 Mon Sep 17 00:00:00 2001 From: Aleksei Lymar Date: Thu, 15 Aug 2019 16:51:18 +0300 Subject: [PATCH 21/39] docs: remove info on NTI and Sberbank in README --- README.md | 2 +- docs/_static/ipavlov_footer.png | Bin 371557 -> 38537 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d539e52d3a..684192a5f2 100644 --- a/README.md +++ b/README.md @@ -246,7 +246,7 @@ DeepPavlov is Apache 2.0 - licensed. ## The Team -DeepPavlov is built and maintained by [Neural Networks and Deep Learning Lab](https://mipt.ru/english/research/labs/neural-networks-and-deep-learning-lab) at [MIPT](https://mipt.ru/english/) within [iPavlov](http://ipavlov.ai/) project (part of [National Technology Initiative](https://asi.ru/eng/nti/)) and in partnership with [Sberbank](http://www.sberbank.com/). +DeepPavlov is built and maintained by [Neural Networks and Deep Learning Lab](https://mipt.ru/english/research/labs/neural-networks-and-deep-learning-lab) at [MIPT](https://mipt.ru/english/) within [iPavlov](http://ipavlov.ai/) project.

diff --git a/docs/_static/ipavlov_footer.png b/docs/_static/ipavlov_footer.png index fb7d2a1a16f8a2a32c4889ca712b77b9e1b8cb9e..691442d87ff5eec4e7b4bd85c9d08f3818d7fb6d 100644 GIT binary patch literal 38537 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 C*p~eO literal 371557 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�@a3{2wQTN8;ns>3mjlEuqZWQS@Kxygif{ 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℞mDFqAM1qWG*Z6wis_<_J~ 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

Cz;ba5wP+Qm90JZ@2b?4tXaA$0E*RTil9F*a2 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%0A_=|xVo)2C% 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 From 3aea9be2db0c7fc021da422dee0a1a17380de838 Mon Sep 17 00:00:00 2001 From: Aleksei Lymar Date: Mon, 19 Aug 2019 11:27:56 +0300 Subject: [PATCH 22/39] docs: add a footer with social links to documentation pages (#957) * docs: add a footer with contact info to documentation pages * docs: add social media links and reword documentation footer * docs: add a hack to move copyright lower --- docs/_static/social/Medium_Monogram.svg | 13 ++++ .../Twitter_Social_Icon_Circle_Color.svg | 20 ++++++ docs/_static/social/f_logo_RGB-Blue_58.png | Bin 0 -> 2465 bytes .../social/youtube_social_circle_red.png | Bin 0 -> 2835 bytes docs/_templates/footer.html | 64 ++++++++++++++++++ 5 files changed, 97 insertions(+) create mode 100644 docs/_static/social/Medium_Monogram.svg create mode 100755 docs/_static/social/Twitter_Social_Icon_Circle_Color.svg create mode 100755 docs/_static/social/f_logo_RGB-Blue_58.png create mode 100755 docs/_static/social/youtube_social_circle_red.png create mode 100644 docs/_templates/footer.html diff --git a/docs/_static/social/Medium_Monogram.svg b/docs/_static/social/Medium_Monogram.svg new file mode 100644 index 0000000000..c8b251ddec --- /dev/null +++ b/docs/_static/social/Medium_Monogram.svg @@ -0,0 +1,13 @@ + + + + Monogram + Created with Sketch. + + + + + + + + \ No newline at end of file diff --git a/docs/_static/social/Twitter_Social_Icon_Circle_Color.svg b/docs/_static/social/Twitter_Social_Icon_Circle_Color.svg new file mode 100755 index 0000000000..6b421ee917 --- /dev/null +++ b/docs/_static/social/Twitter_Social_Icon_Circle_Color.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/docs/_static/social/f_logo_RGB-Blue_58.png b/docs/_static/social/f_logo_RGB-Blue_58.png new file mode 100755 index 0000000000000000000000000000000000000000..743ec2d28b193e1ee5005f38646ac3651e52e519 GIT binary patch literal 2465 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 bQ&0x&SFftO>eump + {% if (theme_prev_next_buttons_location == 'bottom' or theme_prev_next_buttons_location == 'both') and (next or prev) %} +

+ {% endif %} + +
+ +
+ {%- block extrafooter %} +

Problem? Ask a Question or try our Demo

+

+ twitter + facebook + youtube + medium +

+ {% endblock %} +

+ {%- if show_copyright %} + {%- if hasdoc('copyright') %} + {% set path = pathto('copyright') %} + {% set copyright = copyright|e %} + © {% trans %}Copyright{% endtrans %} {{ copyright }} + {%- else %} + {% set copyright = copyright|e %} + © {% trans %}Copyright{% endtrans %} {{ copyright }} + {%- endif %} + {%- endif %} + + {%- if build_id and build_url %} + + {# Translators: Build is a noun, not a verb #} + {% trans %}Build{% endtrans %} + {{ build_id }}. + + {%- elif commit %} + + {% trans %}Revision{% endtrans %} {{ commit }}. + + {%- elif last_updated %} + + {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %} + + {%- endif %} + +

+
+ + {%- if show_sphinx %} + {% set sphinx_web = 'Sphinx' %} + {% set readthedocs_web = 'Read the Docs' %} + {% trans sphinx_web=sphinx_web, readthedocs_web=readthedocs_web %}Built with {{ sphinx_web }} using a{% endtrans %} {% trans %}theme{% endtrans %} {% trans %}provided by {{ readthedocs_web }}{% endtrans %}. + {%- endif %} + + From dfd2db94efb1c58ee503ee4824b89a4f0e07bc86 Mon Sep 17 00:00:00 2001 From: Anton Kiselev Date: Mon, 19 Aug 2019 11:59:55 +0300 Subject: [PATCH 23/39] Fixing formatting in documentation for rule-based skills DSL (#953) * docs: redundant `\n` removed from docs * docs: typo fixed --- docs/features/skills/dsl_skill.rst | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/features/skills/dsl_skill.rst b/docs/features/skills/dsl_skill.rst index c705b92c33..575558cfc6 100644 --- a/docs/features/skills/dsl_skill.rst +++ b/docs/features/skills/dsl_skill.rst @@ -1,14 +1,11 @@ DSL Skill ====================== -An :doc:`DSL implementation`. DSL helps to easily create user-defined - skills for dialog systems. +A :doc:`DSL implementation`. DSL helps to easily create user-defined skills for dialog systems. -For the case when DSL skill matched utterance and found response it outputs response with confidence -value. +For the case when DSL skill matched utterance and found response it outputs response with confidence value. -For the case when no match occurred DSL skill returns the argument `on_invalid_command` ("Простите, я вас не понял" by delault) - as utterance and sets confidence to `null_confidence` attribute (0 by default). +For the case when no match occurred DSL skill returns the argument `on_invalid_command` ("Простите, я вас не понял" by delault) as utterance and sets confidence to `null_confidence` attribute (0 by default). `on_invalid_command` and `null_confidence` can be changed in model config From b351f75cff95e72242b8935635bb611e95ab9a73 Mon Sep 17 00:00:00 2001 From: Aleksei Lymar Date: Wed, 21 Aug 2019 18:10:13 +0300 Subject: [PATCH 24/39] docs: `Register your model` instead of `Registry your model` --- docs/devguides/contribution_guide.rst | 2 +- docs/index.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/devguides/contribution_guide.rst b/docs/devguides/contribution_guide.rst index 010ddac1a1..8ea975255e 100644 --- a/docs/devguides/contribution_guide.rst +++ b/docs/devguides/contribution_guide.rst @@ -26,7 +26,7 @@ How to contribute: Accompany code with **clear comments** to let other people understand the flow of your mind. - If you create new models, refer to the :doc:`Registry your model + If you create new models, refer to the :doc:`Register your model ` section to add it to the DeepPavlov registry of models. diff --git a/docs/index.rst b/docs/index.rst index 912eedf2dd..65ee8696f0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -75,7 +75,7 @@ Welcome to DeepPavlov's documentation! :caption: Developer Guides Contribution guide - Registry your model + Register your model .. toctree:: From de05318615f8a691e2087020f85f2f825c8a4162 Mon Sep 17 00:00:00 2001 From: Sergey Mironov Date: Fri, 23 Aug 2019 13:14:45 +0300 Subject: [PATCH 25/39] update .gitignore Ignore *vim rules such as used by LocalRC plugin for per-project customisations. --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 05dff405d1..9d3b5937be 100644 --- a/.gitignore +++ b/.gitignore @@ -109,6 +109,10 @@ ENV/ #vscode IDE .vscode +# Vim +*.vim +*.vimrc + #GIT .git/ From abd12dc365d37db3886a5c3f2bf5eeaa273568fd Mon Sep 17 00:00:00 2001 From: Dilyara Baymurzina Date: Mon, 26 Aug 2019 13:39:29 +0300 Subject: [PATCH 26/39] feat: max_proba returns one value instead of a list of one value (#973) * chore: one class is not covered to list anymore * chore: one class is not covered to list anymore * fix: change sets_accuracy to accuracy for all one-class configs * fix: change sets_accuracy to accuracy for all one-class configs from tests * fix: typing for proba2labels --- .../configs/classifiers/insults_kaggle.json | 2 +- .../classifiers/insults_kaggle_bert.json | 2 +- .../classifiers/insults_kaggle_conv_bert.json | 2 +- .../classifiers/intents_sample_csv.json | 2 +- .../classifiers/intents_sample_json.json | 2 +- .../configs/classifiers/intents_snips.json | 2 +- .../classifiers/intents_snips_big.json | 2 +- .../configs/classifiers/rusentiment_bert.json | 2 +- .../rusentiment_bigru_superconv.json | 2 +- .../configs/classifiers/rusentiment_cnn.json | 2 +- .../rusentiment_elmo_twitter_cnn.json | 2 +- .../classifiers/sentiment_twitter.json | 2 +- .../sentiment_twitter_preproc.json | 2 +- .../configs/classifiers/topic_ag_news.json | 2 +- .../classifiers/yahoo_convers_vs_info.json | 2 +- .../yahoo_convers_vs_info_bert.json | 2 +- .../evolution/evolve_intents_snips.json | 2 +- .../evolution/evolve_rusentiment_cnn.json | 2 +- .../snips_intents_iterator.py | 2 +- .../basic_classification_reader.py | 20 +++++++++++++++---- .../classifiers/keras_classification_model.py | 4 ++-- deeppavlov/models/classifiers/proba2labels.py | 4 ++-- .../classifiers/intents_snips_bigru.json | 2 +- .../classifiers/intents_snips_bilstm.json | 2 +- .../intents_snips_bilstm_bilstm.json | 2 +- .../classifiers/intents_snips_bilstm_cnn.json | 2 +- .../intents_snips_bilstm_proj_layer.json | 2 +- ...tents_snips_bilstm_self_add_attention.json | 2 +- ...ents_snips_bilstm_self_mult_attention.json | 2 +- .../classifiers/intents_snips_cnn_bilstm.json | 2 +- 30 files changed, 47 insertions(+), 35 deletions(-) diff --git a/deeppavlov/configs/classifiers/insults_kaggle.json b/deeppavlov/configs/classifiers/insults_kaggle.json index a2d95b4f9c..a3ca0f7238 100644 --- a/deeppavlov/configs/classifiers/insults_kaggle.json +++ b/deeppavlov/configs/classifiers/insults_kaggle.json @@ -112,7 +112,7 @@ "epochs": 1000, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/deeppavlov/configs/classifiers/insults_kaggle_bert.json b/deeppavlov/configs/classifiers/insults_kaggle_bert.json index 4755ac9f10..83974a46a1 100644 --- a/deeppavlov/configs/classifiers/insults_kaggle_bert.json +++ b/deeppavlov/configs/classifiers/insults_kaggle_bert.json @@ -97,7 +97,7 @@ "y_pred_probas" ] }, - "sets_accuracy", + "accuracy", "f1_macro" ], "validation_patience": 5, diff --git a/deeppavlov/configs/classifiers/insults_kaggle_conv_bert.json b/deeppavlov/configs/classifiers/insults_kaggle_conv_bert.json index a19bfa114e..0884166985 100644 --- a/deeppavlov/configs/classifiers/insults_kaggle_conv_bert.json +++ b/deeppavlov/configs/classifiers/insults_kaggle_conv_bert.json @@ -113,7 +113,7 @@ "y_pred_probas" ] }, - "sets_accuracy", + "accuracy", "f1_macro" ], "validation_patience": 5, diff --git a/deeppavlov/configs/classifiers/intents_sample_csv.json b/deeppavlov/configs/classifiers/intents_sample_csv.json index 9b15809ae4..b3eeee623e 100644 --- a/deeppavlov/configs/classifiers/intents_sample_csv.json +++ b/deeppavlov/configs/classifiers/intents_sample_csv.json @@ -118,7 +118,7 @@ "epochs": 100, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/deeppavlov/configs/classifiers/intents_sample_json.json b/deeppavlov/configs/classifiers/intents_sample_json.json index e8d8034591..23f2bdd8e9 100644 --- a/deeppavlov/configs/classifiers/intents_sample_json.json +++ b/deeppavlov/configs/classifiers/intents_sample_json.json @@ -113,7 +113,7 @@ "epochs": 100, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/deeppavlov/configs/classifiers/intents_snips.json b/deeppavlov/configs/classifiers/intents_snips.json index b64349b16f..de684dd21e 100644 --- a/deeppavlov/configs/classifiers/intents_snips.json +++ b/deeppavlov/configs/classifiers/intents_snips.json @@ -103,7 +103,7 @@ "epochs": 1000, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/deeppavlov/configs/classifiers/intents_snips_big.json b/deeppavlov/configs/classifiers/intents_snips_big.json index 64e4363572..e113c9f86c 100644 --- a/deeppavlov/configs/classifiers/intents_snips_big.json +++ b/deeppavlov/configs/classifiers/intents_snips_big.json @@ -103,7 +103,7 @@ "epochs": 1000, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/deeppavlov/configs/classifiers/rusentiment_bert.json b/deeppavlov/configs/classifiers/rusentiment_bert.json index 927178635d..4de0d36918 100644 --- a/deeppavlov/configs/classifiers/rusentiment_bert.json +++ b/deeppavlov/configs/classifiers/rusentiment_bert.json @@ -104,7 +104,7 @@ "metrics": [ "f1_weighted", "f1_macro", - "sets_accuracy", + "accuracy", { "name": "roc_auc", "inputs": [ diff --git a/deeppavlov/configs/classifiers/rusentiment_bigru_superconv.json b/deeppavlov/configs/classifiers/rusentiment_bigru_superconv.json index 2a765a4dce..4a7fbf490a 100644 --- a/deeppavlov/configs/classifiers/rusentiment_bigru_superconv.json +++ b/deeppavlov/configs/classifiers/rusentiment_bigru_superconv.json @@ -130,7 +130,7 @@ "metrics": [ "f1_weighted", "f1_macro", - "sets_accuracy", + "accuracy", { "name": "roc_auc", "inputs": ["y_onehot", "y_pred_probas"] diff --git a/deeppavlov/configs/classifiers/rusentiment_cnn.json b/deeppavlov/configs/classifiers/rusentiment_cnn.json index 90d18503bf..3b4f9e9c75 100644 --- a/deeppavlov/configs/classifiers/rusentiment_cnn.json +++ b/deeppavlov/configs/classifiers/rusentiment_cnn.json @@ -127,7 +127,7 @@ "batch_size": 64, "metrics": [ "f1_weighted", - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/deeppavlov/configs/classifiers/rusentiment_elmo_twitter_cnn.json b/deeppavlov/configs/classifiers/rusentiment_elmo_twitter_cnn.json index 1b1b9b2c61..038f4104bb 100644 --- a/deeppavlov/configs/classifiers/rusentiment_elmo_twitter_cnn.json +++ b/deeppavlov/configs/classifiers/rusentiment_elmo_twitter_cnn.json @@ -135,7 +135,7 @@ "metrics": [ "f1_weighted", "f1_macro", - "sets_accuracy", + "accuracy", { "name": "roc_auc", "inputs": ["y_onehot", "y_pred_probas"] diff --git a/deeppavlov/configs/classifiers/sentiment_twitter.json b/deeppavlov/configs/classifiers/sentiment_twitter.json index 7a6f5d295a..4d8e3ce4b1 100644 --- a/deeppavlov/configs/classifiers/sentiment_twitter.json +++ b/deeppavlov/configs/classifiers/sentiment_twitter.json @@ -103,7 +103,7 @@ "epochs": 100, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/deeppavlov/configs/classifiers/sentiment_twitter_preproc.json b/deeppavlov/configs/classifiers/sentiment_twitter_preproc.json index 1b9abffcba..cf127367c7 100644 --- a/deeppavlov/configs/classifiers/sentiment_twitter_preproc.json +++ b/deeppavlov/configs/classifiers/sentiment_twitter_preproc.json @@ -113,7 +113,7 @@ "epochs": 100, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/deeppavlov/configs/classifiers/topic_ag_news.json b/deeppavlov/configs/classifiers/topic_ag_news.json index 047e242d9b..8def9bcace 100644 --- a/deeppavlov/configs/classifiers/topic_ag_news.json +++ b/deeppavlov/configs/classifiers/topic_ag_news.json @@ -111,7 +111,7 @@ "epochs": 100, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/deeppavlov/configs/classifiers/yahoo_convers_vs_info.json b/deeppavlov/configs/classifiers/yahoo_convers_vs_info.json index 877dd64792..04c5a54d9a 100644 --- a/deeppavlov/configs/classifiers/yahoo_convers_vs_info.json +++ b/deeppavlov/configs/classifiers/yahoo_convers_vs_info.json @@ -121,7 +121,7 @@ ] }, { - "name": "sets_accuracy", + "name": "accuracy", "inputs": [ "y", "y_pred_labels" diff --git a/deeppavlov/configs/classifiers/yahoo_convers_vs_info_bert.json b/deeppavlov/configs/classifiers/yahoo_convers_vs_info_bert.json index c0136a0c7c..a33a240b9f 100644 --- a/deeppavlov/configs/classifiers/yahoo_convers_vs_info_bert.json +++ b/deeppavlov/configs/classifiers/yahoo_convers_vs_info_bert.json @@ -114,7 +114,7 @@ ] }, { - "name": "sets_accuracy", + "name": "accuracy", "inputs": [ "y", "y_pred_labels" diff --git a/deeppavlov/configs/evolution/evolve_intents_snips.json b/deeppavlov/configs/evolution/evolve_intents_snips.json index 29ccf85b9f..ca37789fbd 100644 --- a/deeppavlov/configs/evolution/evolve_intents_snips.json +++ b/deeppavlov/configs/evolution/evolve_intents_snips.json @@ -168,7 +168,7 @@ "discrete": true }, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/deeppavlov/configs/evolution/evolve_rusentiment_cnn.json b/deeppavlov/configs/evolution/evolve_rusentiment_cnn.json index d674c6874b..6ff2b47e19 100644 --- a/deeppavlov/configs/evolution/evolve_rusentiment_cnn.json +++ b/deeppavlov/configs/evolution/evolve_rusentiment_cnn.json @@ -167,7 +167,7 @@ "discrete": true }, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/deeppavlov/dataset_iterators/snips_intents_iterator.py b/deeppavlov/dataset_iterators/snips_intents_iterator.py index 4f90455336..306329e762 100644 --- a/deeppavlov/dataset_iterators/snips_intents_iterator.py +++ b/deeppavlov/dataset_iterators/snips_intents_iterator.py @@ -28,5 +28,5 @@ def preprocess(self, data, *args, **kwargs): for query in data: text = ''.join(part['text'] for part in query['data']) intent = query['intent'] - result.append((text, [intent])) + result.append((text, intent)) return result diff --git a/deeppavlov/dataset_readers/basic_classification_reader.py b/deeppavlov/dataset_readers/basic_classification_reader.py index 4438f84cd1..8b33963dd5 100644 --- a/deeppavlov/dataset_readers/basic_classification_reader.py +++ b/deeppavlov/dataset_readers/basic_classification_reader.py @@ -34,7 +34,7 @@ class BasicClassificationDatasetReader(DatasetReader): @overrides def read(self, data_path: str, url: str = None, - format: str = "csv", class_sep: str = ",", + format: str = "csv", class_sep: str = None, *args, **kwargs) -> dict: """ Read dataset from data_path directory. @@ -47,7 +47,7 @@ def read(self, data_path: str, url: str = None, url: download data files if data_path not exists or empty format: extension of files. Set of Values: ``"csv", "json"`` class_sep: string separator of labels in column with labels - sep (str): delimeter for ``"csv"`` files. Default: ``","`` + sep (str): delimeter for ``"csv"`` files. Default: None -> only one class per sample header (int): row number to use as the column names names (array): list of column names to use orient (str): indication of expected JSON string format @@ -88,9 +88,21 @@ def read(self, data_path: str, url: str = None, x = kwargs.get("x", "text") y = kwargs.get('y', 'labels') if isinstance(x, list): - data[data_type] = [([row[x_] for x_ in x], str(row[y]).split(class_sep)) for _, row in df.iterrows()] + if class_sep is None: + # each sample is a tuple ("text", "label") + data[data_type] = [([row[x_] for x_ in x], str(row[y])) + for _, row in df.iterrows()] + else: + # each sample is a tuple ("text", ["label", "label", ...]) + data[data_type] = [([row[x_] for x_ in x], str(row[y]).split(class_sep)) + for _, row in df.iterrows()] else: - data[data_type] = [(row[x], str(row[y]).split(class_sep)) for _, row in df.iterrows()] + if class_sep is None: + # each sample is a tuple ("text", "label") + data[data_type] = [(row[x], str(row[y])) for _, row in df.iterrows()] + else: + # each sample is a tuple ("text", ["label", "label", ...]) + data[data_type] = [(row[x], str(row[y]).split(class_sep)) for _, row in df.iterrows()] else: log.warning("Cannot find {} file".format(file)) diff --git a/deeppavlov/models/classifiers/keras_classification_model.py b/deeppavlov/models/classifiers/keras_classification_model.py index f2b0c6a2a9..bcde5df3d3 100644 --- a/deeppavlov/models/classifiers/keras_classification_model.py +++ b/deeppavlov/models/classifiers/keras_classification_model.py @@ -190,7 +190,7 @@ def train_on_batch(self, texts: List[List[np.ndarray]], labels: list) -> Union[f """ features = self.check_input(texts) - metrics_values = self.model.train_on_batch(features, np.squeeze(np.array(labels))) + metrics_values = self.model.train_on_batch(features, np.array(labels)) return metrics_values def infer_on_batch(self, texts: List[List[np.ndarray]], labels: list = None) -> \ @@ -209,7 +209,7 @@ def infer_on_batch(self, texts: List[List[np.ndarray]], labels: list = None) -> features = self.check_input(texts) if labels: - metrics_values = self.model.test_on_batch(features, np.squeeze(np.array(labels))) + metrics_values = self.model.test_on_batch(features, np.array(labels)) return metrics_values else: predictions = self.model.predict(features) diff --git a/deeppavlov/models/classifiers/proba2labels.py b/deeppavlov/models/classifiers/proba2labels.py index 5cb2dfe659..164495cb25 100644 --- a/deeppavlov/models/classifiers/proba2labels.py +++ b/deeppavlov/models/classifiers/proba2labels.py @@ -54,7 +54,7 @@ def __init__(self, self.top_n = top_n def __call__(self, data: Union[np.ndarray, List[List[float]], List[List[int]]], - *args, **kwargs) -> Union[List[List[str]], List[str]]: + *args, **kwargs) -> Union[List[List[int]], List[int]]: """ Process probabilities to labels @@ -70,7 +70,7 @@ def __call__(self, data: Union[np.ndarray, List[List[float]], List[List[int]]], return [list(np.where(np.array(d) > self.confident_threshold)[0]) for d in data] elif self.max_proba: - return [[np.argmax(d)] for d in data] + return [np.argmax(d) for d in data] elif self.top_n: return [np.argsort(d)[::-1][:self.top_n] for d in data] else: diff --git a/tests/test_configs/classifiers/intents_snips_bigru.json b/tests/test_configs/classifiers/intents_snips_bigru.json index 244d54b617..ff9e7ed430 100644 --- a/tests/test_configs/classifiers/intents_snips_bigru.json +++ b/tests/test_configs/classifiers/intents_snips_bigru.json @@ -99,7 +99,7 @@ "epochs": 1, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/tests/test_configs/classifiers/intents_snips_bilstm.json b/tests/test_configs/classifiers/intents_snips_bilstm.json index 5371d84b17..831be68378 100644 --- a/tests/test_configs/classifiers/intents_snips_bilstm.json +++ b/tests/test_configs/classifiers/intents_snips_bilstm.json @@ -99,7 +99,7 @@ "epochs": 1, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/tests/test_configs/classifiers/intents_snips_bilstm_bilstm.json b/tests/test_configs/classifiers/intents_snips_bilstm_bilstm.json index 7af8d58c42..ba4301ffba 100644 --- a/tests/test_configs/classifiers/intents_snips_bilstm_bilstm.json +++ b/tests/test_configs/classifiers/intents_snips_bilstm_bilstm.json @@ -100,7 +100,7 @@ "epochs": 1, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/tests/test_configs/classifiers/intents_snips_bilstm_cnn.json b/tests/test_configs/classifiers/intents_snips_bilstm_cnn.json index f146ad4779..e2ac142a43 100644 --- a/tests/test_configs/classifiers/intents_snips_bilstm_cnn.json +++ b/tests/test_configs/classifiers/intents_snips_bilstm_cnn.json @@ -106,7 +106,7 @@ "epochs": 1, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/tests/test_configs/classifiers/intents_snips_bilstm_proj_layer.json b/tests/test_configs/classifiers/intents_snips_bilstm_proj_layer.json index 18489bc2fd..0c557350ab 100644 --- a/tests/test_configs/classifiers/intents_snips_bilstm_proj_layer.json +++ b/tests/test_configs/classifiers/intents_snips_bilstm_proj_layer.json @@ -101,7 +101,7 @@ "epochs": 1, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/tests/test_configs/classifiers/intents_snips_bilstm_self_add_attention.json b/tests/test_configs/classifiers/intents_snips_bilstm_self_add_attention.json index 588020a7da..32311f4629 100644 --- a/tests/test_configs/classifiers/intents_snips_bilstm_self_add_attention.json +++ b/tests/test_configs/classifiers/intents_snips_bilstm_self_add_attention.json @@ -102,7 +102,7 @@ "epochs": 1, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/tests/test_configs/classifiers/intents_snips_bilstm_self_mult_attention.json b/tests/test_configs/classifiers/intents_snips_bilstm_self_mult_attention.json index 3ec8802f80..9d373c957c 100644 --- a/tests/test_configs/classifiers/intents_snips_bilstm_self_mult_attention.json +++ b/tests/test_configs/classifiers/intents_snips_bilstm_self_mult_attention.json @@ -102,7 +102,7 @@ "epochs": 1, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", diff --git a/tests/test_configs/classifiers/intents_snips_cnn_bilstm.json b/tests/test_configs/classifiers/intents_snips_cnn_bilstm.json index 2b62a146a0..30c6437277 100644 --- a/tests/test_configs/classifiers/intents_snips_cnn_bilstm.json +++ b/tests/test_configs/classifiers/intents_snips_cnn_bilstm.json @@ -106,7 +106,7 @@ "epochs": 1, "batch_size": 64, "metrics": [ - "sets_accuracy", + "accuracy", "f1_macro", { "name": "roc_auc", From 4362292d4b21125f65601daa88adc069d4f9c5bf Mon Sep 17 00:00:00 2001 From: yurakuratov Date: Mon, 2 Sep 2019 16:47:00 +0300 Subject: [PATCH 27/39] fix: update links to fixed bert models (#981) resolves #969 --- docs/features/models/bert.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/features/models/bert.rst b/docs/features/models/bert.rst index c8a847ee02..d798cd51f3 100644 --- a/docs/features/models/bert.rst +++ b/docs/features/models/bert.rst @@ -17,9 +17,9 @@ There are several pre-trained BERT models released by Google Research, more deta We have trained BERT-base model for other languages: -- RuBERT, Russian, cased, 12-layer, 768-hidden, 12-heads, 180M parameters: `[deeppavlov] `__ -- SlavicBERT, Slavic (bg, cs, pl, ru), cased, 12-layer, 768-hidden, 12-heads, 180M parameters: `[deeppavlov] `__ -- Conversational BERT, English, cased, 12-layer, 768-hidden, 12-heads, 110M parameters: `[deeppavlov] `__ +- RuBERT, Russian, cased, 12-layer, 768-hidden, 12-heads, 180M parameters: `[deeppavlov] `__ +- SlavicBERT, Slavic (bg, cs, pl, ru), cased, 12-layer, 768-hidden, 12-heads, 180M parameters: `[deeppavlov] `__ +- Conversational BERT, English, cased, 12-layer, 768-hidden, 12-heads, 110M parameters: `[deeppavlov] `__ RuBERT was trained on the Russian part of Wikipedia and news data. We used this training data to build vocabulary of Russian subtokens and took multilingual version of BERT-base as initialization for RuBERT [1]_. From cc63c3e04901004fc27f7004468ef40bd1949357 Mon Sep 17 00:00:00 2001 From: Aleksei Lymar Date: Tue, 3 Sep 2019 14:19:03 +0300 Subject: [PATCH 28/39] docs: add a questionnaire link in README.md (#980) * docs: remove tabulation in code examples * docs: add a link on the framework questionnaire. --- README.md | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 684192a5f2..baaee3234d 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ DeepPavlov is designed for * Docker Hub [*hub.docker.com/u/deeppavlov/*](https://hub.docker.com/u/deeppavlov/) * Docker Images Documentation [*docs:docker-images/*](http://docs.deeppavlov.ai/en/master/intro/installation.html#docker-images) +Please leave us [your feedback](https://forms.gle/i64fowQmiVhMMC7f9) on how we can improve the DeepPavlov framework. + **Models** [Named Entity Recognition](http://docs.deeppavlov.ai/en/master/features/models/ner.html) | [Slot filling](http://docs.deeppavlov.ai/en/master/features/models/slot_filling.html) @@ -85,8 +87,8 @@ List of models is available on [the doc page](http://docs.deeppavlov.ai/en/master/features/overview.html) in the `deeppavlov.configs` (Python): -```python - from deeppavlov import configs +```python +from deeppavlov import configs ``` When you're decided on the model (+ config file), there are two ways to train, @@ -98,8 +100,8 @@ evaluate and infer it: Before making choice of an interface, install model's package requirements (CLI): -```bash - python -m deeppavlov install +```bash +python -m deeppavlov install ``` * where `` is path to the chosen model's config file (e.g. @@ -111,8 +113,8 @@ Before making choice of an interface, install model's package requirements To get predictions from a model interactively through CLI, run -```bash - python -m deeppavlov interact [-d] +```bash +python -m deeppavlov interact [-d] ``` * `-d` downloads required data -- pretrained model files and embeddings @@ -121,7 +123,7 @@ To get predictions from a model interactively through CLI, run You can train it in the same simple way: ```bash - python -m deeppavlov train [-d] +python -m deeppavlov train [-d] ``` Dataset will be downloaded regardless of whether there was `-d` flag or not. @@ -132,8 +134,8 @@ The data format is specified in the corresponding model doc page. There are even more actions you can perform with configs: -```bash - python -m deeppavlov [-d] +```bash +python -m deeppavlov [-d] ``` * `` can be @@ -157,13 +159,13 @@ There are even more actions you can perform with configs: To get predictions from a model interactively through Python, run -```python - from deeppavlov import build_model +```python +from deeppavlov import build_model - model = build_model(, download=True) +model = build_model(, download=True) - # get predictions for 'input_text1', 'input_text2' - model(['input_text1', 'input_text2']) +# get predictions for 'input_text1', 'input_text2' +model(['input_text1', 'input_text2']) ``` * where `download=True` downloads required data from web -- pretrained model @@ -175,10 +177,10 @@ To get predictions from a model interactively through Python, run You can train it in the same simple way: -```python - from deeppavlov import train_model +```python +from deeppavlov import train_model - model = train_model(, download=True) +model = train_model(, download=True) ``` * `download=True` downloads pretrained model, therefore the pretrained @@ -194,9 +196,9 @@ The data format is specified in the corresponding model doc page. You can also calculate metrics on the dataset specified in your config file: ```python - from deeppavlov import evaluate_model +from deeppavlov import evaluate_model - model = evaluate_model(, download=True) +model = evaluate_model(, download=True) ``` There are also available integrations with various messengers, see From a59de9a3c1443a939f12bfa7a855a46e2c213a59 Mon Sep 17 00:00:00 2001 From: IgnatovFedor Date: Tue, 3 Sep 2019 15:09:31 +0300 Subject: [PATCH 29/39] feat: added detailed information to socket test logs (#986) resolves #985 --- deeppavlov/utils/socket/socket.py | 4 ++-- tests/test_quick_start.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deeppavlov/utils/socket/socket.py b/deeppavlov/utils/socket/socket.py index 0f8aab16c9..d67a93d90b 100644 --- a/deeppavlov/utils/socket/socket.py +++ b/deeppavlov/utils/socket/socket.py @@ -145,7 +145,7 @@ async def _handle_connection(self, conn: socket.socket, addr: Tuple) -> None: try: data = json.loads(recv_data) except ValueError: - await self._wrap_error(conn, 'request type is not json') + await self._wrap_error(conn, f'request "{recv_data}" type is not json') return self._dialog_logger.log_in(data) model_args = [] @@ -162,7 +162,7 @@ async def _handle_connection(self, conn: socket.socket, addr: Tuple) -> None: await self._wrap_error(conn, 'got empty request') return elif len(lengths) > 1: - await self._wrap_error(conn, 'got several different batch sizes') + await self._wrap_error(conn, f'got several different batch sizes: {lengths}') return batch_size = list(lengths)[0] model_args = [arg or [None] * batch_size for arg in model_args] diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index ed9e6c38c0..051630d989 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -463,7 +463,7 @@ def interact_socket(config_path, socket_type): pass resp = json.loads(data) assert resp['status'] == 'OK', f"{socket_type} socket request returned status: {resp['status']}"\ - " with {config_path}" + f" with {config_path}\n{logfile.getvalue().decode()}" except pexpect.exceptions.EOF: raise RuntimeError('Got unexpected EOF: \n{}'.format(logfile.getvalue().decode())) From 01f85f901df4a0b72cfe12204dc6e0e56ff811ec Mon Sep 17 00:00:00 2001 From: Alexander Dmitrievskiy Date: Fri, 6 Sep 2019 10:46:40 +0300 Subject: [PATCH 30/39] feat: add a Rasa skill wrapper (#916) * rasa skill wrapper * add requirements * remove comments * move aiml_skill.json config to configs.skills * update aiml_skill.rst for new config's path * add rasas skill's apiref documentation link * feat: require deepmipt/rasa for rasa-skill to skip tensorflow dependency * fix: add rasa to autodoc_mock_imports * fix: add rasa_skill to toktree * feat: require rasa version 1.2.5 for rasa skill * tests: fix aiml skill config path * docs: update Rasa skill documentation * chore: update version to 0.6.0 * style: prettify test_rasa_skill code * chore: update rasa version --- deeppavlov/__init__.py | 2 +- .../{aiml_skill => skills}/aiml_skill.json | 0 deeppavlov/configs/skills/rasa_skill.json | 43 +++ deeppavlov/core/common/registry.json | 1 + deeppavlov/requirements/rasa_skill.txt | 1 + deeppavlov/skills/rasa_skill/__init__.py | 0 deeppavlov/skills/rasa_skill/rasa_skill.py | 256 ++++++++++++++++++ docs/apiref/skills/rasa_skill.rst | 5 + docs/conf.py | 2 +- docs/features/skills/aiml_skill.rst | 2 +- docs/features/skills/rasa_skill.rst | 51 ++++ docs/index.rst | 1 + tests/test_aiml_skill.py | 2 +- tests/test_rasa_skill.py | 47 ++++ 14 files changed, 409 insertions(+), 4 deletions(-) rename deeppavlov/configs/{aiml_skill => skills}/aiml_skill.json (100%) create mode 100644 deeppavlov/configs/skills/rasa_skill.json create mode 100644 deeppavlov/requirements/rasa_skill.txt create mode 100644 deeppavlov/skills/rasa_skill/__init__.py create mode 100644 deeppavlov/skills/rasa_skill/rasa_skill.py create mode 100644 docs/apiref/skills/rasa_skill.rst create mode 100644 docs/features/skills/rasa_skill.rst create mode 100644 tests/test_rasa_skill.py diff --git a/deeppavlov/__init__.py b/deeppavlov/__init__.py index b5f7926eed..8d259ea039 100644 --- a/deeppavlov/__init__.py +++ b/deeppavlov/__init__.py @@ -37,7 +37,7 @@ def evaluate_model(config: [str, Path, dict], download: bool = False, recursive: except ImportError: 'Assuming that requirements are not yet installed' -__version__ = '0.5.1' +__version__ = '0.6.0' __author__ = 'Neural Networks and Deep Learning lab, MIPT' __description__ = 'An open source library for building end-to-end dialog systems and training chatbots.' __keywords__ = ['NLP', 'NER', 'SQUAD', 'Intents', 'Chatbot'] diff --git a/deeppavlov/configs/aiml_skill/aiml_skill.json b/deeppavlov/configs/skills/aiml_skill.json similarity index 100% rename from deeppavlov/configs/aiml_skill/aiml_skill.json rename to deeppavlov/configs/skills/aiml_skill.json diff --git a/deeppavlov/configs/skills/rasa_skill.json b/deeppavlov/configs/skills/rasa_skill.json new file mode 100644 index 0000000000..fae1521b0a --- /dev/null +++ b/deeppavlov/configs/skills/rasa_skill.json @@ -0,0 +1,43 @@ +{ + "chainer": { + "in": [ + "utterances" + ], + "out": [ + "responses_batch", + "confidences_batch" + ], + "pipe": [ + { + "class_name": "rasa_skill", + "path_to_models": "{PROJECT_ROOT}/models", + "in": [ + "utterances" + ], + "out": [ + "responses_batch", + "confidences_batch", + "output_states_batch" + ] + } + ] + }, + "metadata": { + "variables": { + "ROOT_PATH": "~/.deeppavlov", + "DOWNLOADS_PATH": "{ROOT_PATH}/downloads", + "MODELS_PATH": "{ROOT_PATH}/models", + "PROJECT_ROOT": "{DOWNLOADS_PATH}/rasa_tutorial_project" + }, + "requirements": [ + "{DEEPPAVLOV_PATH}/requirements/rasa_skill.txt", + "{DEEPPAVLOV_PATH}/requirements/tf.txt" + ], + "download": [ + { + "url": "http://files.deeppavlov.ai/rasa_skill/rasa_tutorial_project.tar.gz", + "subdir": "{DOWNLOADS_PATH}" + } + ] + } +} diff --git a/deeppavlov/core/common/registry.json b/deeppavlov/core/common/registry.json index 079010b520..1108aa3d24 100644 --- a/deeppavlov/core/common/registry.json +++ b/deeppavlov/core/common/registry.json @@ -105,6 +105,7 @@ "ru_sent_tokenizer": "deeppavlov.models.tokenizers.ru_sent_tokenizer:RuSentTokenizer", "ru_tokenizer": "deeppavlov.models.tokenizers.ru_tokenizer:RussianTokenizer", "russian_words_vocab": "deeppavlov.vocabs.typos:RussianWordsVocab", + "rasa_skill": "deeppavlov.skills.rasa_skill.rasa_skill:RASASkill", "sanitizer": "deeppavlov.models.preprocessors.sanitizer:Sanitizer", "sent_label_splitter": "deeppavlov.models.morpho_tagger.misc:SentLabelSplitter", "seq2seq_go_bot": "deeppavlov.models.seq2seq_go_bot.bot:Seq2SeqGoalOrientedBot", diff --git a/deeppavlov/requirements/rasa_skill.txt b/deeppavlov/requirements/rasa_skill.txt new file mode 100644 index 0000000000..bfb2598b2d --- /dev/null +++ b/deeppavlov/requirements/rasa_skill.txt @@ -0,0 +1 @@ +git+https://github.com/deepmipt/rasa.git@b0a80916e54ed9f4496c709a28f1093f7a5f2492#egg=rasa==1.2.7 diff --git a/deeppavlov/skills/rasa_skill/__init__.py b/deeppavlov/skills/rasa_skill/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/deeppavlov/skills/rasa_skill/rasa_skill.py b/deeppavlov/skills/rasa_skill/rasa_skill.py new file mode 100644 index 0000000000..d29350c881 --- /dev/null +++ b/deeppavlov/skills/rasa_skill/rasa_skill.py @@ -0,0 +1,256 @@ +import uuid +import asyncio +import logging +from pathlib import Path +from typing import Tuple, Optional, List +from functools import reduce + +from deeppavlov.core.common.registry import register +from deeppavlov.core.skill.skill import Skill + +from rasa.core.agent import Agent +from rasa.core.channels import UserMessage +from rasa.core.channels import CollectingOutputChannel +from rasa.model import get_model +from rasa.cli.utils import get_validated_path +from rasa.constants import DEFAULT_MODELS_PATH + +logger = logging.getLogger(__name__) + + +@register("rasa_skill") +class RASASkill(Skill): + """RASASkill lets you to wrap RASA Agent as a Skill within DeepPavlov environment. + + The component requires path to your RASA models (folder with timestamped tar.gz archieves) + as you use in command `rasa run -m models --enable-api --log-file out.log` + + """ + + def __init__(self, path_to_models: str, **kwargs) -> None: + """ + Constructs RASA Agent as a DeepPavlov skill: + read model folder, + initialize rasa.core.agent.Agent and wrap it's interfaces + + Args: + path_to_models: string path to folder with RASA models + + """ + # we need absolute path (expanded for user home and resolved if it relative path): + self.path_to_models = Path(path_to_models).expanduser().resolve() + + model = get_validated_path(self.path_to_models, "model", DEFAULT_MODELS_PATH) + + model_path = get_model(model) + if not model_path: + # can not laod model path + raise Exception("can not load model path: %s" % model) + + self._agent = Agent.load(model_path) + self.ioloop = asyncio.new_event_loop() + logger.info(f"path to RASA models is: `{self.path_to_models}`") + + def __call__(self, utterances_batch: List[str], + history_batch: Optional[List]=None, + states_batch: Optional[List]=None) -> Tuple[List[str], List[float], list]: + """Returns skill inference result. + + Returns batches of skill inference results, estimated confidence + levels and up to date states corresponding to incoming utterance + batch. + + Args: + utterances_batch: A batch of utterances of str type. + history_batch: A batch of list typed histories for each utterance. + states_batch: A batch of arbitrary typed states for + each utterance. + + + Returns: + response: A batch of arbitrary typed skill inference results. + confidence: A batch of float typed confidence levels for each of + skill inference result. + output_states_batch: A batch of arbitrary typed states for + each utterance. + + """ + user_ids, output_states_batch = self._handle_user_identification(utterances_batch, states_batch) + ################################################################################# + # RASA use asyncio for handling messages and handle_text is async function, + # so we need to instantiate event loop + # futures = [rasa_confident_response_decorator(self._agent, utt, sender_id=uid) for utt, uid in + futures = [self.rasa_confident_response_decorator(self._agent, utt, sender_id=uid) for utt, uid in + zip(utterances_batch, user_ids)] + + asyncio.set_event_loop(self.ioloop) + results = self.ioloop.run_until_complete(asyncio.gather(*futures)) + + responses_batch, confidences_batch = zip(*results) + return responses_batch, confidences_batch, output_states_batch + + async def rasa_confident_response_decorator(self, rasa_agent, text_message, sender_id): + """ + Args: + rasa_agent: rasa.core.agent.Agent instance + text_message: str with utterance from user + sender_id: id of the user + + Returns: None or tuple with str and float, where first element is a message and second is + confidence + """ + + resp = await self.rasa_handle_text_verbosely(rasa_agent, text_message, sender_id) + if resp: + responses, confidences, actions = resp + else: + logger.warning("Null response from RASA Skill") + return None + + # for adaptation to deep pavlov arch we need to merge multi-messages into single string: + texts = [each_resp['text'] for each_resp in responses if 'text' in each_resp] + merged_message = "\n".join(texts) + + merged_confidence = reduce(lambda a, b: a * b, confidences) + # TODO possibly it better to choose another function for calculation of final confidence + # current realisation of confidence propagation may cause confidence decay for long actions + # chains. If long chains is your case, try max(confidence) or confidence[0] + return merged_message, merged_confidence + + async def rasa_handle_text_verbosely(self, rasa_agent, text_message, sender_id): + """ + This function reimplements RASA's rasa.core.agent.Agent.handle_text method to allow to retrieve + message responses with confidence estimation altogether. + + It reconstructs with merge RASA's methods: + https://github.com/RasaHQ/rasa_core/blob/master/rasa/core/agent.py#L401 + https://github.com/RasaHQ/rasa_core/blob/master/rasa/core/agent.py#L308 + https://github.com/RasaHQ/rasa/blob/master/rasa/core/processor.py#L327 + + This required to allow RASA to output confidences with actions altogether + (Out of the box RASA does not support such use case). + + Args: + rasa_agent: rasa.core.agent.Agent instance + text_message: str with utterance from user + sender_id: id of the user + + Returns: None or + tuple where first element is a list of messages dicts, the second element is a list + of confidence scores for all actions (it is longer than messages list, because some actions + does not produce messages) + + """ + message = UserMessage(text_message, + output_channel=None, + sender_id=sender_id) + + processor = rasa_agent.create_processor() + tracker = processor._get_tracker(message.sender_id) + + confidences = [] + actions = [] + await processor._handle_message_with_tracker(message, tracker) + # save tracker state to continue conversation from this state + processor._save_tracker(tracker) + + # here we restore some of logic in RASA management. + # ###### Loop of IntraStep decisions ########################################################## + # await processor._predict_and_execute_next_action(msg, tracker): + # https://github.com/RasaHQ/rasa/blob/master/rasa/core/processor.py#L327-L362 + # keep taking actions decided by the policy until it chooses to 'listen' + should_predict_another_action = True + num_predicted_actions = 0 + + def is_action_limit_reached(): + return (num_predicted_actions == processor.max_number_of_predictions and + should_predict_another_action) + + # action loop. predicts actions until we hit action listen + while (should_predict_another_action and + processor._should_handle_message(tracker) and + num_predicted_actions < processor.max_number_of_predictions): + # this actually just calls the policy's method by the same name + action, policy, confidence = processor.predict_next_action(tracker) + + confidences.append(confidence) + actions.append(action) + + should_predict_another_action = await processor._run_action( + action, + tracker, + message.output_channel, + processor.nlg, + policy, confidence + ) + num_predicted_actions += 1 + + if is_action_limit_reached(): + # circuit breaker was tripped + logger.warning( + "Circuit breaker tripped. Stopped predicting " + "more actions for sender '{}'".format(tracker.sender_id)) + if processor.on_circuit_break: + # call a registered callback + processor.on_circuit_break(tracker, message.output_channel, processor.nlg) + + if isinstance(message.output_channel, CollectingOutputChannel): + + return message.output_channel.messages, confidences, actions + else: + return None + + def _generate_user_id(self) -> str: + """ + Here you put user id generative logic if you want to implement it in the skill. + + Although it is better to delegate user_id generation to Agent Layer + Returns: str + + """ + return uuid.uuid1().hex + + def _handle_user_identification(self, utterances_batch, states_batch): + """Method preprocesses states batch to guarantee that all users are identified (or + identifiers are generated for all users). + + Args: + utterances_batch: batch of utterances + states_batch: batch of states + + Returns: + + """ + # grasp user_ids from states batch. + # We expect that skill receives None or dict of state for each utterance. + # if state has user_id then skill uses it, otherwise it generates user_id and calls the + # user with this name in further. + + # In this implementation we use current datetime for generating uniqe ids + output_states_batch = [] + user_ids = [] + if states_batch is None: + # generate states batch matching batch of utterances: + states_batch = [None] * len(utterances_batch) + + for state in states_batch: + if not state: + user_id = self._generate_user_id() + new_state = {'user_id': user_id} + + elif 'user_id' not in state: + new_state = state + user_id = self._generate_user_id() + new_state['user_id'] = self._generate_user_id() + + else: + new_state = state + user_id = new_state['user_id'] + + user_ids.append(user_id) + output_states_batch.append(new_state) + return user_ids, output_states_batch + + def destroy(self): + self.ioloop.close() + super().destroy() diff --git a/docs/apiref/skills/rasa_skill.rst b/docs/apiref/skills/rasa_skill.rst new file mode 100644 index 0000000000..c4cef207fb --- /dev/null +++ b/docs/apiref/skills/rasa_skill.rst @@ -0,0 +1,5 @@ +deeppavlov.skills.rasa_skill +======================================== + +.. automodule:: deeppavlov.skills.rasa_skill.rasa_skill + :members: diff --git a/docs/conf.py b/docs/conf.py index eed018f2b7..eec32ec4e5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -191,7 +191,7 @@ # -- Extension configuration ------------------------------------------------- autodoc_mock_imports = ['tensorflow', 'tensorflow_hub', 'fastText', 'nltk', 'gensim', 'kenlm', 'spacy', 'lxml', - 'sortedcontainers', 'russian_tagsets', 'bert_dp', 'aiml'] + 'sortedcontainers', 'russian_tagsets', 'bert_dp', 'aiml', 'rasa'] extlinks = { 'config': (f'https://github.com/deepmipt/DeepPavlov/blob/{release}/deeppavlov/configs/%s', None) diff --git a/docs/features/skills/aiml_skill.rst b/docs/features/skills/aiml_skill.rst index 6038b4689c..2f2c09944e 100644 --- a/docs/features/skills/aiml_skill.rst +++ b/docs/features/skills/aiml_skill.rst @@ -20,7 +20,7 @@ parameter `path_to_aiml_scripts`. You can download bunch of free and ready for use AIML scripts from pandorabots repo: https://github.com/pandorabots/Free-AIML -DeepPavlov library has default config for AIMLSkill here: :config:`configs/aiml_skill/aiml_skill.json ` +DeepPavlov library has default config for AIMLSkill here: :config:`configs/skills/aiml_skill.json ` Usage ^^^^^^^^ diff --git a/docs/features/skills/rasa_skill.rst b/docs/features/skills/rasa_skill.rst new file mode 100644 index 0000000000..0e9427a119 --- /dev/null +++ b/docs/features/skills/rasa_skill.rst @@ -0,0 +1,51 @@ +Rasa Skill +====================== + +A :class:`Rasa wrapper implementation` that reads a folder with Rasa models +(provided by ``path_to_models`` argument), initializes Rasa Agent with this configuration and responds for incoming +utterances according to responses predicted by Rasa. Each response has confidence value estimated as product of +scores of executed actions by Rasa system in the current prediction step (each prediction step in Rasa usually consists of +multiple actions). If Rasa responds with multiple ``BotUttered`` actions, then such phrases are merged into one utterance +divided by ``'\n'``. + +Quick Start +----------- +To setup a Rasa Skill you need to have a working Rasa project at some path, then you can specify the path to Rasa's +models (usually it is a folder with name ``models`` inside the project path) at initialization of Rasa Skill class +by providing ``path_to_models`` attribute. + +Dummy Rasa project +------------------ +DeepPavlov library has :config:`a template config for RASASkill`. +This project is in essence a working Rasa project created with ``rasa init`` and ``rasa train`` commands +with minimal additions. The Rasa bot can greet, answer about what he can do and detect user's mood sentiment. + +The template DeepPavlov config specifies only one component (RASASkill) in :doc:`a pipeline`. +The configuration also specifies: ``metadata.requirements`` which is the file with Rasa dependency and +``metadata.download`` configuration specifies to download and unpack the gzipped template project into subdir +``{DOWNLOADS_PATH}``. + +If you create a configuration for a Rasa project hosted on your machine, you don't need to specify ``metadata.download`` +and just need to correctly set ``path_to_models`` of the ``rasa_skill`` component. +``path_to_models`` needs to be a path to your Rasa's ``models`` directory. + +See `Rasa's documentation `_ for explanation on how +to create project. + +Usage without DeepPavlov configuration files +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + from deeppavlov.agents.default_agent.default_agent import DefaultAgent + from deeppavlov.agents.processors.highest_confidence_selector import HighestConfidenceSelector + from deeppavlov.skills.rasa_skill.rasa_skill import RASASkill + + rasa_skill_config = { + 'path_to_models': , + } + + rasa_skill = RASASkill(**rasa_skill_config) + agent = DefaultAgent([rasa_skill], skills_selector=HighestConfidenceSelector()) + responses = agent(["Hello"]) + print(responses) diff --git a/docs/index.rst b/docs/index.rst index 65ee8696f0..867822c649 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -51,6 +51,7 @@ Welcome to DeepPavlov's documentation! Frequently Asked Questions Answering eCommerce Bot AIML + Rasa DSL diff --git a/tests/test_aiml_skill.py b/tests/test_aiml_skill.py index deb6638abd..a62049bb63 100644 --- a/tests/test_aiml_skill.py +++ b/tests/test_aiml_skill.py @@ -13,7 +13,7 @@ class TestAIMLSkill: def setup(self): - config_ref = configs.aiml_skill.aiml_skill + config_ref = configs.skills.aiml_skill install_from_config(config_ref) aiml_skill = build_model(config_ref, download=True) self.agent = DefaultAgent([aiml_skill], skills_selector=HighestConfidenceSelector()) diff --git a/tests/test_rasa_skill.py b/tests/test_rasa_skill.py new file mode 100644 index 0000000000..ef9e0e04b0 --- /dev/null +++ b/tests/test_rasa_skill.py @@ -0,0 +1,47 @@ +from logging import getLogger + +from deeppavlov.agents.default_agent.default_agent import DefaultAgent +from deeppavlov.agents.processors.highest_confidence_selector import HighestConfidenceSelector +from deeppavlov import configs, build_model +from deeppavlov.utils.pip_wrapper.pip_wrapper import install_from_config + +log = getLogger(__name__) + + +class TestRASASkill: + def setup(self): + # print(configs.aiml_skill) + config_ref = configs.skills.rasa_skill + install_from_config(config_ref) + # rasa_skill = build_model( + # "/home/alx/Workspace/DeepPavlov/deeppavlov/configs/aiml_skill/rasa_skill.json", + # download=True) + rasa_skill = build_model( + config_ref, + download=True) + self.agent = DefaultAgent([rasa_skill], skills_selector=HighestConfidenceSelector()) + + def test_simple_reaction(self): + user_messages_sequence = ["Hello", + "What can you do?", + "Tell me a joke", + "Learn my pants are Red", + "LET DISCUSS MOVIES", + "Comedy movies are nice to watch", + "I LIKE WATCHING COMEDY!", + "Ok, goodbye" + ] + + history_of_responses = [] + for each_utt in user_messages_sequence: + log.info(f"User says: {each_utt}") + responses_batch = self.agent([each_utt]) + log.info(f" Bot says: {responses_batch[0]}") + history_of_responses.append(responses_batch) + + print("history_of_responses:") + print(history_of_responses) + # # check the first greeting message in 0th batch + assert "Hey! How are you?" in history_of_responses[0][0] + # # check second response message in 0th batch + assert "I can chat with you. You can greet me" in history_of_responses[1][0] From 00b8843d9cd4de1cafdb0819eb1f0a15a943e406 Mon Sep 17 00:00:00 2001 From: IgnatovFedor Date: Fri, 6 Sep 2019 10:48:05 +0300 Subject: [PATCH 31/39] tests: added JSON not searizable model response exception handling (#987) * feat: added information to socket test logs * feat: exception handling added for model json not serializable responses * refactor: added data to error message --- tests/test_quick_start.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_quick_start.py b/tests/test_quick_start.py index 051630d989..3b3776f659 100644 --- a/tests/test_quick_start.py +++ b/tests/test_quick_start.py @@ -466,7 +466,10 @@ def interact_socket(config_path, socket_type): f" with {config_path}\n{logfile.getvalue().decode()}" except pexpect.exceptions.EOF: - raise RuntimeError('Got unexpected EOF: \n{}'.format(logfile.getvalue().decode())) + raise RuntimeError(f'Got unexpected EOF: \n{logfile.getvalue().decode()}') + + except json.JSONDecodeError: + raise ValueError(f'Got JSON not serializable response from model: "{data}"\n{logfile.getvalue().decode()}') finally: p.kill(signal.SIGTERM) From 349cfbdebfb05d2faf51ae7c82eca81c97ed5c49 Mon Sep 17 00:00:00 2001 From: Mary Trofimova Date: Fri, 6 Sep 2019 10:48:58 +0300 Subject: [PATCH 32/39] docs: add a new gobot tutorial (#982) * fix: fix super convergence tutor * fix: fix link in classification tutor * feat: add data prep & database build to gobot tutor * feat: make ner config dependent on variables only * feat: support empty slot vals * feat: in the middle of big refactor of ner * feat: slot-filling section in gobot tutor * feat: add simpler dstc2 format * feat: simplify tutor & simplify data * feat: refactor user state & add typings & and format strings * feat: update gobot tutor * feat: table name is optional in sqlite_database, rewrite to f-string * feat: add diagram pics * feat: add diagrams to tutor, add text * feat: fix imgs & add tutor plan * fix: fix simple data reader and ner iterator * fix: use simple dstc reader everywhere * feat: fix several tf warnings * fix: multiuser gobot support * feat: update gobot_dstc2 model * fix: error in DefaultTemplate * feat: update gobot_dstc2_best model * fix: fix debug mode * fix: dstc2_ner_iterator * feat: make api_call_action unrequired --- deeppavlov/configs/go_bot/gobot_dstc2.json | 32 +- .../configs/go_bot/gobot_dstc2_best.json | 9 +- .../configs/go_bot/gobot_simple_dstc2.json | 131 ++ deeppavlov/configs/ner/ner_dstc2.json | 28 +- deeppavlov/configs/ner/slotfill_dstc2.json | 20 +- .../configs/ner/slotfill_dstc2_raw.json | 24 +- .../ner/slotfill_simple_dstc2_raw.json | 60 + deeppavlov/core/common/registry.json | 11 +- deeppavlov/core/data/simple_vocab.py | 2 +- deeppavlov/core/data/sqlite_database.py | 88 +- deeppavlov/core/layers/tf_layers.py | 2 +- .../basic_classification_iterator.py | 4 +- .../dataset_iterators/dstc2_ner_iterator.py | 80 +- deeppavlov/dataset_readers/dstc2_reader.py | 188 +- deeppavlov/download.py | 5 +- deeppavlov/models/go_bot/network.py | 363 ++-- docs/features/overview.rst | 4 +- docs/features/skills/go_bot.rst | 6 +- examples/classification_tutorial.ipynb | 2 +- examples/gobot_tutorial.ipynb | 1729 +++++++++++++++++ examples/img/gobot_database.png | Bin 0 -> 8149 bytes examples/img/gobot_example.png | Bin 0 -> 586959 bytes examples/img/gobot_pipeline.png | Bin 0 -> 84393 bytes examples/img/gobot_policy.png | Bin 0 -> 23464 bytes examples/img/gobot_slotfiller.png | Bin 0 -> 4756 bytes examples/img/gobot_templates.png | Bin 0 -> 6118 bytes examples/img/sc_loss_comparison.png | Bin 0 -> 88085 bytes examples/img/sc_ner_lr_cosine.png | Bin 0 -> 16075 bytes examples/img/sc_ner_lr_exponential.png | Bin 0 -> 15694 bytes examples/img/sc_ner_lr_linear.png | Bin 0 -> 16102 bytes examples/img/sc_ner_lr_linear2.png | Bin 0 -> 16220 bytes examples/img/sc_ner_lr_no.png | Bin 0 -> 12288 bytes examples/img/sc_ner_lr_onecycle.png | Bin 0 -> 23861 bytes examples/img/sc_ner_lr_polynomial.png | Bin 0 -> 16309 bytes examples/img/sc_ner_lr_polynomial1.png | Bin 0 -> 15769 bytes examples/img/sc_ner_lr_polynomial2.png | Bin 0 -> 15410 bytes examples/img/sc_ner_lr_sc.png | Bin 0 -> 36522 bytes examples/img/sc_ner_lr_sc1.png | Bin 0 -> 33542 bytes examples/img/sc_ner_lr_trapezoid.png | Bin 0 -> 22307 bytes 39 files changed, 2475 insertions(+), 313 deletions(-) create mode 100644 deeppavlov/configs/go_bot/gobot_simple_dstc2.json create mode 100644 deeppavlov/configs/ner/slotfill_simple_dstc2_raw.json create mode 100644 examples/gobot_tutorial.ipynb create mode 100644 examples/img/gobot_database.png create mode 100644 examples/img/gobot_example.png create mode 100644 examples/img/gobot_pipeline.png create mode 100644 examples/img/gobot_policy.png create mode 100644 examples/img/gobot_slotfiller.png create mode 100644 examples/img/gobot_templates.png create mode 100644 examples/img/sc_loss_comparison.png create mode 100644 examples/img/sc_ner_lr_cosine.png create mode 100644 examples/img/sc_ner_lr_exponential.png create mode 100644 examples/img/sc_ner_lr_linear.png create mode 100644 examples/img/sc_ner_lr_linear2.png create mode 100644 examples/img/sc_ner_lr_no.png create mode 100644 examples/img/sc_ner_lr_onecycle.png create mode 100644 examples/img/sc_ner_lr_polynomial.png create mode 100644 examples/img/sc_ner_lr_polynomial1.png create mode 100644 examples/img/sc_ner_lr_polynomial2.png create mode 100644 examples/img/sc_ner_lr_sc.png create mode 100644 examples/img/sc_ner_lr_sc1.png create mode 100644 examples/img/sc_ner_lr_trapezoid.png diff --git a/deeppavlov/configs/go_bot/gobot_dstc2.json b/deeppavlov/configs/go_bot/gobot_dstc2.json index a56fcaef0b..d2f7707654 100644 --- a/deeppavlov/configs/go_bot/gobot_dstc2.json +++ b/deeppavlov/configs/go_bot/gobot_dstc2.json @@ -1,7 +1,7 @@ { "dataset_reader": { "class_name": "dstc2_reader", - "data_path": "{DOWNLOADS_PATH}/dstc2" + "data_path": "{DATA_PATH}" }, "dataset_iterator": { "class_name": "dialog_iterator" @@ -21,20 +21,13 @@ "id": "word_vocab", "class_name": "simple_vocab", "fit_on": ["x_tokens"], - "save_path": "{MODELS_PATH}/gobot_dstc2/word.dict", - "load_path": "{MODELS_PATH}/gobot_dstc2/word.dict" - }, - { - "id": "restaurant_database", - "class_name": "sqlite_database", - "table_name": "mytable", - "primary_keys": ["name"], - "save_path": "{DOWNLOADS_PATH}/dstc2/resto.sqlite" + "save_path": "{MODEL_PATH}/word.dict", + "load_path": "{MODEL_PATH}/word.dict" }, { "class_name": "go_bot", - "load_path": "{MODELS_PATH}/gobot_dstc2/model", - "save_path": "{MODELS_PATH}/gobot_dstc2/model", + "load_path": "{MODEL_PATH}/model", + "save_path": "{MODEL_PATH}/model", "in": ["x"], "in_y": ["y"], "out": ["y_predicted"], @@ -53,7 +46,12 @@ "word_vocab": "#word_vocab", "template_path": "{DOWNLOADS_PATH}/dstc2/dstc2-templates.txt", "template_type": "DualTemplate", - "database": "#restaurant_database", + "database": { + "class_name": "sqlite_database", + "table_name": "mytable", + "primary_keys": ["name"], + "save_path": "{DOWNLOADS_PATH}/dstc2/resto.sqlite" + }, "api_call_action": "api_call", "use_action_mask": false, "slot_filler": { @@ -99,9 +97,11 @@ "metadata": { "variables": { "ROOT_PATH": "~/.deeppavlov", + "CONFIGS_PATH": "{DEEPPAVLOV_PATH}/configs", "DOWNLOADS_PATH": "{ROOT_PATH}/downloads", + "DATA_PATH": "{DOWNLOADS_PATH}/dstc2", "MODELS_PATH": "{ROOT_PATH}/models", - "CONFIGS_PATH": "{DEEPPAVLOV_PATH}/configs" + "MODEL_PATH": "{MODELS_PATH}/gobot_dstc2" }, "requirements": [ "{DEEPPAVLOV_PATH}/requirements/tf.txt", @@ -115,7 +115,7 @@ }, "download": [ { - "url": "http://files.deeppavlov.ai/deeppavlov_data/gobot_dstc2_v7.tar.gz", + "url": "http://files.deeppavlov.ai/deeppavlov_data/gobot_dstc2_v9.tar.gz", "subdir": "{MODELS_PATH}" }, { @@ -124,7 +124,7 @@ }, { "url": "http://files.deeppavlov.ai/datasets/dstc2_v2.tar.gz", - "subdir": "{DOWNLOADS_PATH}/dstc2" + "subdir": "{DATA_PATH}" } ] } diff --git a/deeppavlov/configs/go_bot/gobot_dstc2_best.json b/deeppavlov/configs/go_bot/gobot_dstc2_best.json index 6a27fb83bb..d0d3842694 100644 --- a/deeppavlov/configs/go_bot/gobot_dstc2_best.json +++ b/deeppavlov/configs/go_bot/gobot_dstc2_best.json @@ -40,7 +40,7 @@ "out": ["y_predicted"], "main": true, "debug": false, - "learning_rate": 3e-4, + "learning_rate": 3e-3, "learning_rate_drop_patience": 10, "learning_rate_drop_div": 4.0, "momentum": 0.95, @@ -51,13 +51,12 @@ "hidden_size": 128, "dense_size": 128, "attention_mechanism": { - "type": "cs_bahdanau", + "type": "general", "hidden_size": 32, - "depth": 3, "action_as_key": true, "intent_as_key": true, "max_num_tokens": 100, - "projected_align": false + "projected_align": false }, "word_vocab": "#token_vocab", "template_path": "{DOWNLOADS_PATH}/dstc2/dstc2-templates.txt", @@ -124,7 +123,7 @@ }, "download": [ { - "url": "http://files.deeppavlov.ai/deeppavlov_data/gobot_dstc2_best_v3.tar.gz", + "url": "http://files.deeppavlov.ai/deeppavlov_data/gobot_dstc2_best_v4.tar.gz", "subdir": "{MODELS_PATH}" }, { diff --git a/deeppavlov/configs/go_bot/gobot_simple_dstc2.json b/deeppavlov/configs/go_bot/gobot_simple_dstc2.json new file mode 100644 index 0000000000..01ba40b1f3 --- /dev/null +++ b/deeppavlov/configs/go_bot/gobot_simple_dstc2.json @@ -0,0 +1,131 @@ +{ + "dataset_reader": { + "class_name": "simple_dstc2_reader", + "data_path": "{DATA_PATH}" + }, + "dataset_iterator": { + "class_name": "dialog_iterator" + }, + "chainer": { + "in": ["x"], + "in_y": ["y"], + "out": ["y_predicted"], + "pipe": [ + { + "class_name": "deeppavlov.models.go_bot.wrapper:DialogComponentWrapper", + "component": { "class_name": "split_tokenizer" }, + "in": ["x"], + "out": ["x_tokens"] + }, + { + "id": "word_vocab", + "class_name": "simple_vocab", + "fit_on": ["x_tokens"], + "save_path": "{MODEL_PATH}/word.dict", + "load_path": "{MODEL_PATH}/word.dict" + }, + { + "class_name": "go_bot", + "load_path": "{MODEL_PATH}/model", + "save_path": "{MODEL_PATH}/model", + "in": ["x"], + "in_y": ["y"], + "out": ["y_predicted"], + "main": true, + "debug": false, + "learning_rate": 0.003, + "learning_rate_drop_patience": 5, + "learning_rate_drop_div": 10.0, + "momentum": 0.95, + "optimizer": "tensorflow.train:AdamOptimizer", + "clip_norm": 2.0, + "dropout_rate": 0.4, + "l2_reg_coef": 3e-4, + "hidden_size": 128, + "dense_size": 160, + "word_vocab": "#word_vocab", + "template_path": "{DATA_PATH}/simple-dstc2-templates.txt", + "template_type": "DefaultTemplate", + "database": { + "class_name": "sqlite_database", + "table_name": "mytable", + "primary_keys": ["name"], + "save_path": "{DATA_PATH}/resto.sqlite" + }, + "api_call_action": "api_call", + "use_action_mask": false, + "slot_filler": { + "config_path": "{CONFIGS_PATH}/ner/slotfill_dstc2.json" + }, + "intent_classifier": null, + "embedder": { + "class_name": "glove", + "load_path": "{DOWNLOADS_PATH}/embeddings/glove.6B.100d.txt" + }, + "bow_embedder": { + "class_name": "bow", + "depth": "#word_vocab.__len__()", + "with_counts": true + }, + "tokenizer": { + "class_name": "stream_spacy_tokenizer", + "lowercase": false + }, + "tracker": { + "class_name": "featurized_tracker", + "slot_names": ["pricerange", "this", "area", "food", "name"] + } + } + ] + }, + "train": { + "epochs": 200, + "batch_size": 8, + + "metrics": ["per_item_dialog_accuracy"], + "validation_patience": 10, + "val_every_n_batches": 15, + + "log_every_n_batches": 15, + "show_examples": false, + "evaluation_targets": [ + "valid", + "test" + ], + "class_name": "nn_trainer" + }, + "metadata": { + "variables": { + "ROOT_PATH": "~/.deeppavlov", + "CONFIGS_PATH": "{DEEPPAVLOV_PATH}/configs", + "DOWNLOADS_PATH": "{ROOT_PATH}/downloads", + "DATA_PATH": "{DOWNLOADS_PATH}/simple-dstc2", + "MODELS_PATH": "{ROOT_PATH}/models", + "MODEL_PATH": "{MODELS_PATH}/gobot_dstc2" + }, + "requirements": [ + "{DEEPPAVLOV_PATH}/requirements/tf.txt", + "{DEEPPAVLOV_PATH}/requirements/gensim.txt", + "{DEEPPAVLOV_PATH}/requirements/spacy.txt", + "{DEEPPAVLOV_PATH}/requirements/en_core_web_sm.txt" + ], + "labels": { + "telegram_utils": "GoalOrientedBot", + "server_utils": "GoalOrientedBot" + }, + "download": [ + { + "url": "http://files.deeppavlov.ai/deeppavlov_data/gobot_dstc2_v9.tar.gz", + "subdir": "{MODELS_PATH}" + }, + { + "url": "http://files.deeppavlov.ai/embeddings/glove.6B.100d.txt", + "subdir": "{DOWNLOADS_PATH}/embeddings" + }, + { + "url": "http://files.deeppavlov.ai/datasets/simple_dstc2.tar.gz", + "subdir": "{DATA_PATH}" + } + ] + } +} diff --git a/deeppavlov/configs/ner/ner_dstc2.json b/deeppavlov/configs/ner/ner_dstc2.json index ca6a3790a1..9840c2fb3a 100644 --- a/deeppavlov/configs/ner/ner_dstc2.json +++ b/deeppavlov/configs/ner/ner_dstc2.json @@ -1,11 +1,11 @@ { "dataset_reader": { "class_name": "dstc2_reader", - "data_path": "{DOWNLOADS_PATH}/dstc2" + "data_path": "{DATA_PATH}" }, "dataset_iterator": { "class_name": "dstc2_ner_iterator", - "dataset_path": "{DOWNLOADS_PATH}/dstc2" + "slot_values_path": "{SLOT_VALS_PATH}" }, "chainer": { "in": ["x"], @@ -27,8 +27,8 @@ "class_name": "simple_vocab", "pad_with_zeros": true, "fit_on": ["x_lower"], - "save_path": "{MODELS_PATH}/slotfill_dstc2/word.dict", - "load_path": "{MODELS_PATH}/slotfill_dstc2/word.dict", + "save_path": "{MODEL_PATH}/word.dict", + "load_path": "{MODEL_PATH}/word.dict", "out": ["x_tok_ind"] }, { @@ -43,8 +43,8 @@ "class_name": "simple_vocab", "pad_with_zeros": true, "fit_on": ["y"], - "save_path": "{MODELS_PATH}/slotfill_dstc2/tag.dict", - "load_path": "{MODELS_PATH}/slotfill_dstc2/tag.dict", + "save_path": "{MODEL_PATH}/tag.dict", + "load_path": "{MODEL_PATH}/tag.dict", "out": ["y_ind"] }, { @@ -62,8 +62,8 @@ "n_hidden_list": [64, 64], "net_type": "cnn", "n_tags": "#tag_vocab.len", - "save_path": "{MODELS_PATH}/slotfill_dstc2/model", - "load_path": "{MODELS_PATH}/slotfill_dstc2/model", + "save_path": "{MODEL_PATH}/model", + "load_path": "{MODEL_PATH}/model", "embeddings_dropout": true, "top_dropout": true, "intra_layer_dropout": false, @@ -107,8 +107,10 @@ "metadata": { "variables": { "ROOT_PATH": "~/.deeppavlov", - "DOWNLOADS_PATH": "{ROOT_PATH}/downloads", - "MODELS_PATH": "{ROOT_PATH}/models" + "DATA_PATH": "{ROOT_PATH}/downloads/dstc2", + "SLOT_VALS_PATH": "{DATA_PATH}/dstc_slot_vals.json", + "MODELS_PATH": "{ROOT_PATH}/models", + "MODEL_PATH": "{MODELS_PATH}/slotfill_dstc2" }, "requirements": [ "{DEEPPAVLOV_PATH}/requirements/tf.txt" @@ -118,10 +120,14 @@ "server_utils": "NER" }, "download": [ + { + "url": "http://files.deeppavlov.ai/deeppavlov_data/dstc_slot_vals.tar.gz", + "subdir": "{DATA_PATH}" + }, { "url": "http://files.deeppavlov.ai/deeppavlov_data/slotfill_dstc2.tar.gz", "subdir": "{MODELS_PATH}" } ] } -} \ No newline at end of file +} diff --git a/deeppavlov/configs/ner/slotfill_dstc2.json b/deeppavlov/configs/ner/slotfill_dstc2.json index dc82bf9b45..217f2b2bfc 100644 --- a/deeppavlov/configs/ner/slotfill_dstc2.json +++ b/deeppavlov/configs/ner/slotfill_dstc2.json @@ -1,11 +1,11 @@ { "dataset_reader": { "class_name": "dstc2_reader", - "data_path": "{DOWNLOADS_PATH}/dstc2" + "data_path": "{DATA_PATH}" }, "dataset_iterator": { "class_name": "dstc2_ner_iterator", - "dataset_path": "{DOWNLOADS_PATH}/dstc2" + "slot_values_path": "{SLOT_VALS_PATH}" }, "chainer": { "in": ["x"], @@ -18,7 +18,7 @@ }, { "in": ["x_tokens"], - "config_path": "{CONFIGS_PATH}/ner/ner_dstc2.json", + "config_path": "{NER_CONFIG_PATH}", "out": ["x_tokens", "tags"] }, @@ -26,8 +26,8 @@ "in": ["x_tokens", "tags"], "class_name": "dstc_slotfilling", "threshold": 0.8, - "save_path": "{MODELS_PATH}/slotfill_dstc2/dstc_slot_vals.json", - "load_path": "{MODELS_PATH}/slotfill_dstc2/dstc_slot_vals.json", + "save_path": "{MODEL_PATH}/model", + "load_path": "{MODEL_PATH}/model", "out": ["slots"] } ], @@ -44,9 +44,11 @@ "metadata": { "variables": { "ROOT_PATH": "~/.deeppavlov", - "DOWNLOADS_PATH": "{ROOT_PATH}/downloads", + "NER_CONFIG_PATH": "{DEEPPAVLOV_PATH}/configs/ner/ner_dstc2.json", + "DATA_PATH": "{ROOT_PATH}/downloads/dstc2", + "SLOT_VALS_PATH": "{DATA_PATH}/dstc_slot_vals.json", "MODELS_PATH": "{ROOT_PATH}/models", - "CONFIGS_PATH": "{DEEPPAVLOV_PATH}/configs" + "MODEL_PATH": "{MODELS_PATH}/slotfill_dstc2" }, "requirements": [ "{DEEPPAVLOV_PATH}/requirements/tf.txt" @@ -56,6 +58,10 @@ "server_utils": "DstcSlotFillingNetwork" }, "download": [ + { + "url": "http://files.deeppavlov.ai/deeppavlov_data/dstc_slot_vals.tar.gz", + "subdir": "{DATA_PATH}" + }, { "url": "http://files.deeppavlov.ai/deeppavlov_data/slotfill_dstc2.tar.gz", "subdir": "{MODELS_PATH}" diff --git a/deeppavlov/configs/ner/slotfill_dstc2_raw.json b/deeppavlov/configs/ner/slotfill_dstc2_raw.json index 709c40c6c3..f66293b8bc 100644 --- a/deeppavlov/configs/ner/slotfill_dstc2_raw.json +++ b/deeppavlov/configs/ner/slotfill_dstc2_raw.json @@ -1,14 +1,15 @@ { "dataset_reader": { "class_name": "dstc2_reader", - "data_path": "{DOWNLOADS_PATH}/dstc2" + "data_path": "{DATA_PATH}" }, "dataset_iterator": { "class_name": "dstc2_ner_iterator", - "dataset_path": "{DOWNLOADS_PATH}/dstc2" + "slot_values_path": "{SLOT_VALS_PATH}" }, "chainer": { "in": ["x"], + "in_y": ["y"], "pipe": [ { "in": ["x"], @@ -23,18 +24,25 @@ { "in": ["x_lower"], "class_name": "slotfill_raw", - "save_path": "{MODELS_PATH}/slotfill_dstc2/dstc_slot_vals.json", - "load_path": "{MODELS_PATH}/slotfill_dstc2/dstc_slot_vals.json", + "save_path": "{SLOT_VALS_PATH}", + "load_path": "{SLOT_VALS_PATH}", "out": ["slots"] } ], "out": ["slots"] }, + "train": { + "metrics": ["slots_accuracy"], + "evaluation_targets": [ + "valid", + "test" + ] + }, "metadata": { "variables": { "ROOT_PATH": "~/.deeppavlov", - "DOWNLOADS_PATH": "{ROOT_PATH}/downloads", - "MODELS_PATH": "{ROOT_PATH}/models" + "DATA_PATH": "{ROOT_PATH}/downloads/dstc2", + "SLOT_VALS_PATH": "{DATA_PATH}/dstc_slot_vals.json" }, "requirements": [ "{DEEPPAVLOV_PATH}/requirements/tf.txt" @@ -44,8 +52,8 @@ }, "download": [ { - "url": "http://files.deeppavlov.ai/deeppavlov_data/slotfill_dstc2.tar.gz", - "subdir": "{MODELS_PATH}" + "url": "http://files.deeppavlov.ai/deeppavlov_data/dstc_slot_vals.tar.gz", + "subdir": "{DATA_PATH}" } ] } diff --git a/deeppavlov/configs/ner/slotfill_simple_dstc2_raw.json b/deeppavlov/configs/ner/slotfill_simple_dstc2_raw.json new file mode 100644 index 0000000000..47f176394c --- /dev/null +++ b/deeppavlov/configs/ner/slotfill_simple_dstc2_raw.json @@ -0,0 +1,60 @@ +{ + "dataset_reader": { + "class_name": "simple_dstc2_reader", + "data_path": "{DATA_PATH}" + }, + "dataset_iterator": { + "class_name": "dstc2_ner_iterator", + "slot_values_path": "{SLOT_VALS_PATH}" + }, + "chainer": { + "in": ["x"], + "in_y": ["y"], + "pipe": [ + { + "in": ["x"], + "class_name": "lazy_tokenizer", + "out": ["x_tokens"] + }, + { + "in": ["x_tokens"], + "class_name": "str_lower", + "out": ["x_lower"] + }, + { + "in": ["x_lower"], + "class_name": "slotfill_raw", + "save_path": "{SLOT_VALS_PATH}", + "load_path": "{SLOT_VALS_PATH}", + "out": ["slots"] + } + ], + "out": ["slots"] + }, + "train": { + "metrics": ["slots_accuracy"], + "evaluation_targets": [ + "valid", + "test" + ] + }, + "metadata": { + "variables": { + "ROOT_PATH": "~/.deeppavlov", + "DATA_PATH": "{ROOT_PATH}/downloads/simple-dstc2", + "SLOT_VALS_PATH": "{DATA_PATH}/dstc_slot_vals.json" + }, + "requirements": [ + "{DEEPPAVLOV_PATH}/requirements/tf.txt" + ], + "labels": { + "telegram_utils": "NERModel" + }, + "download": [ + { + "url": "http://files.deeppavlov.ai/deeppavlov_data/dstc_slot_vals.tar.gz", + "subdir": "{DATA_PATH}" + } + ] + } +} diff --git a/deeppavlov/core/common/registry.json b/deeppavlov/core/common/registry.json index 1108aa3d24..0d50ff6de9 100644 --- a/deeppavlov/core/common/registry.json +++ b/deeppavlov/core/common/registry.json @@ -1,4 +1,5 @@ { + "UD_pymorphy_lemmatizer": "deeppavlov.models.morpho_tagger.lemmatizer:UDPymorphyLemmatizer", "aiml_skill": "deeppavlov.skills.aiml_skill.aiml_skill:AIMLSkill", "amazon_ecommerce_reader": "deeppavlov.dataset_readers.amazon_ecommerce_reader:AmazonEcommerceReader", "api_requester": "deeppavlov.models.api_requester.api_requester:ApiRequester", @@ -6,7 +7,6 @@ "basic_classification_iterator": "deeppavlov.dataset_iterators.basic_classification_iterator:BasicClassificationDatasetIterator", "basic_classification_reader": "deeppavlov.dataset_readers.basic_classification_reader:BasicClassificationDatasetReader", "bert_classifier": "deeppavlov.models.bert.bert_classifier:BertClassifierModel", - "bert_context_add": "deeppavlov.models.preprocessors.bert_preprocessor:BertContextAdd", "bert_ner": "deeppavlov.models.bert.bert_ner:BertNerModel", "bert_ner_preprocessor": "deeppavlov.models.preprocessors.bert_preprocessor:BertNerPreprocessor", "bert_preprocessor": "deeppavlov.models.preprocessors.bert_preprocessor:BertPreprocessor", @@ -21,13 +21,13 @@ "bow": "deeppavlov.models.embedders.bow_embedder:BoWEmbedder", "capitalization_featurizer": "deeppavlov.models.preprocessors.capitalization:CapitalizationPreprocessor", "char_splitter": "deeppavlov.models.preprocessors.char_splitter:CharSplitter", + "char_splitting_lowercase_preprocessor": "deeppavlov.models.preprocessors.capitalization:CharSplittingLowercasePreprocessor", "conll2003_reader": "deeppavlov.dataset_readers.conll2003_reader:Conll2003DatasetReader", "cos_sim_classifier": "deeppavlov.models.classifiers.cos_sim_classifier:CosineSimilarityClassifier", "dam_nn": "deeppavlov.models.ranking.deep_attention_matching_network:DAMNetwork", "dam_nn_use_transformer": "deeppavlov.models.ranking.deep_attention_matching_network_use_transformer:DAMNetworkUSETransformer", "data_fitting_iterator": "deeppavlov.core.data.data_fitting_iterator:DataFittingIterator", "data_learning_iterator": "deeppavlov.core.data.data_learning_iterator:DataLearningIterator", - "default_vocab": "deeppavlov.core.data.vocab:DefaultVocabulary", "dialog_db_result_iterator": "deeppavlov.dataset_iterators.dialog_iterator:DialogDBResultDatasetIterator", "dialog_iterator": "deeppavlov.dataset_iterators.dialog_iterator:DialogDatasetIterator", "dialog_state": "deeppavlov.models.seq2seq_go_bot.dialog_state:DialogState", @@ -69,13 +69,10 @@ "lemmatized_output_prettifier": "deeppavlov.models.morpho_tagger.common:LemmatizedOutputPrettifier", "line_reader": "deeppavlov.dataset_readers.line_reader:LineReader", "logit_ranker": "deeppavlov.models.doc_retrieval.logit_ranker:LogitRanker", - "char_splitting_lowercase_preprocessor": "deeppavlov.models.preprocessors.capitalization:CharSplittingLowercasePreprocessor", "mask": "deeppavlov.models.preprocessors.mask:Mask", "morpho_tagger": "deeppavlov.models.morpho_tagger.morpho_tagger:MorphoTagger", "morphotagger_dataset": "deeppavlov.dataset_iterators.morphotagger_iterator:MorphoTaggerDatasetIterator", "morphotagger_dataset_reader": "deeppavlov.dataset_readers.morphotagging_dataset_reader:MorphotaggerDatasetReader", - "morphotagger_multidataset": "deeppavlov.dataset_iterators.morphotagger_iterator:MorphoTaggerMultiDatasetIterator", - "morphotagger_multidataset_reader": "deeppavlov.dataset_readers.morphotagging_dataset_reader:MorphotaggerMultiDatasetReader", "mpm_nn": "deeppavlov.models.ranking.mpm_siamese_network:MPMSiameseNetwork", "multi_squad_dataset_reader": "deeppavlov.dataset_readers.squad_dataset_reader:MultiSquadDatasetReader", "multi_squad_iterator": "deeppavlov.dataset_iterators.squad_iterator:MultiSquadIterator", @@ -107,13 +104,13 @@ "russian_words_vocab": "deeppavlov.vocabs.typos:RussianWordsVocab", "rasa_skill": "deeppavlov.skills.rasa_skill.rasa_skill:RASASkill", "sanitizer": "deeppavlov.models.preprocessors.sanitizer:Sanitizer", - "sent_label_splitter": "deeppavlov.models.morpho_tagger.misc:SentLabelSplitter", "seq2seq_go_bot": "deeppavlov.models.seq2seq_go_bot.bot:Seq2SeqGoalOrientedBot", "seq2seq_go_bot_nn": "deeppavlov.models.seq2seq_go_bot.network:Seq2SeqGoalOrientedBotNetwork", "siamese_iterator": "deeppavlov.dataset_iterators.siamese_iterator:SiameseIterator", "siamese_predictor": "deeppavlov.models.ranking.siamese_predictor:SiamesePredictor", "siamese_preprocessor": "deeppavlov.models.preprocessors.siamese_preprocessor:SiamesePreprocessor", "siamese_reader": "deeppavlov.dataset_readers.siamese_reader:SiameseReader", + "simple_dstc2_reader": "deeppavlov.dataset_readers.dstc2_reader:SimpleDSTC2DatasetReader", "simple_vocab": "deeppavlov.core.data.simple_vocab:SimpleVocabulary", "sklearn_component": "deeppavlov.models.sklearn.sklearn_component:SklearnComponent", "slotfill_raw": "deeppavlov.models.slotfill.slotfill_raw:SlotFillingComponent", @@ -124,6 +121,7 @@ "spelling_error_model": "deeppavlov.models.spelling_correction.brillmoore.error_model:ErrorModel", "spelling_levenshtein": "deeppavlov.models.spelling_correction.levenshtein.searcher_component:LevenshteinSearcherComponent", "split_tokenizer": "deeppavlov.models.tokenizers.split_tokenizer:SplitTokenizer", + "sq_reader": "deeppavlov.dataset_readers.sq_reader:OntonotesReader", "sqlite_database": "deeppavlov.core.data.sqlite_database:Sqlite3Database", "sqlite_iterator": "deeppavlov.dataset_iterators.sqlite_iterator:SQLiteDataIterator", "squad_ans_postprocessor": "deeppavlov.models.preprocessors.squad_preprocessor:SquadAnsPostprocessor", @@ -156,7 +154,6 @@ "ubuntu_v1_mt_reader": "deeppavlov.dataset_readers.ubuntu_v1_mt_reader:UbuntuV1MTReader", "ubuntu_v2_mt_reader": "deeppavlov.dataset_readers.ubuntu_v2_mt_reader:UbuntuV2MTReader", "ubuntu_v2_reader": "deeppavlov.dataset_readers.ubuntu_v2_reader:UbuntuV2Reader", - "UD_pymorphy_lemmatizer": "deeppavlov.models.morpho_tagger.lemmatizer:UDPymorphyLemmatizer", "wiki_sqlite_vocab": "deeppavlov.vocabs.wiki_sqlite:WikiSQLiteVocab", "wikitionary_100K_vocab": "deeppavlov.vocabs.typos:Wiki100KDictionary" } \ No newline at end of file diff --git a/deeppavlov/core/data/simple_vocab.py b/deeppavlov/core/data/simple_vocab.py index 7ccd78ab02..fde9433079 100644 --- a/deeppavlov/core/data/simple_vocab.py +++ b/deeppavlov/core/data/simple_vocab.py @@ -89,7 +89,7 @@ def __call__(self, batch, is_top=True, **kwargs): looked_up_batch = [self(sample, is_top=False) for sample in batch] else: return self[batch] - if is_top and self._pad_with_zeros and not is_str_batch(looked_up_batch): + if self._pad_with_zeros and is_top and not is_str_batch(looked_up_batch): looked_up_batch = zero_pad(looked_up_batch) return looked_up_batch diff --git a/deeppavlov/core/data/sqlite_database.py b/deeppavlov/core/data/sqlite_database.py index 21e026a4ff..9680f0d9c4 100644 --- a/deeppavlov/core/data/sqlite_database.py +++ b/deeppavlov/core/data/sqlite_database.py @@ -35,17 +35,19 @@ class Sqlite3Database(Estimator): Parameters: save_path: sqlite database path. - table_name: name of the sqlite table. primary_keys: list of table primary keys' names. keys: all table keys' names. + table_name: name of the sqlite table. unknown_value: value assigned to missing item values. - **kwargs: parameters passed to parent :class:`~deeppavlov.core.models.estimator.Estimator` class. + **kwargs: parameters passed to parent + :class:`~deeppavlov.core.models.estimator.Estimator` class. """ - def __init__(self, save_path: str, - table_name: str, + def __init__(self, + save_path: str, primary_keys: List[str], keys: List[str] = None, + table_name: str = "mytable", unknown_value: str = 'UNK', *args, **kwargs) -> None: super().__init__(save_path=save_path, *args, **kwargs) @@ -57,14 +59,15 @@ def __init__(self, save_path: str, self.keys = keys self.unknown_value = unknown_value - self.conn = sqlite3.connect(str(self.save_path), check_same_thread=False) + self.conn = sqlite3.connect(str(self.save_path), + check_same_thread=False) self.cursor = self.conn.cursor() if self._check_if_table_exists(): - log.info("Loading database from {}.".format(self.save_path)) + log.info(f"Loading database from {self.save_path}.") if not self.keys: self.keys = self._get_keys() else: - log.info("Initializing empty database on {}.".format(self.save_path)) + log.info(f"Initializing empty database on {self.save_path}.") def __call__(self, batch: List[Dict], order_by: str = None, @@ -76,31 +79,31 @@ def __call__(self, batch: List[Dict], return [self._search(b, order_by=order_by, order=order) for b in batch] def _check_if_table_exists(self): - self.cursor.execute("SELECT name FROM sqlite_master" - " WHERE type='table'" - " AND name='{}';".format(self.tname)) + self.cursor.execute(f"SELECT name FROM sqlite_master" + f" WHERE type='table'" + f" AND name='{self.tname}';") return bool(self.cursor.fetchall()) def _search(self, kv, order_by, order): if not kv: # get all table content if order_by is not None: - self.cursor.execute("SELECT * FROM {}".format(self.tname) + - " ORDER BY {} {}".format(order_by, order)) + self.cursor.execute(f"SELECT * FROM {self.tname}" + + f" ORDER BY {order_by} {order}") else: - self.cursor.execute("SELECT * FROM {}".format(self.tname)) + self.cursor.execute(f"SELECT * FROM {self.tname}") else: keys = list(kv.keys()) values = [kv[k] for k in keys] - where_expr = ' AND '.join('{}=?'.format(k) for k in keys) + where_expr = " AND ".join(f"{k}=?" for k in keys) if order_by is not None: - self.cursor.execute("SELECT * FROM {}".format(self.tname) + - " WHERE {}".format(where_expr) + - " ORDER BY {} {}".format(order_by, order), + self.cursor.execute(f"SELECT * FROM {self.tname}" + + f" WHERE {where_expr}" + + f" ORDER BY {order_by} {order}", values) else: - self.cursor.execute("SELECT * FROM {}".format(self.tname) + - " WHERE {}".format(where_expr), + self.cursor.execute(f"SELECT * FROM {self.tname}" + + f" WHERE {where_expr}", values) return [self._wrap_selection(s) for s in self.cursor.fetchall()] @@ -110,17 +113,20 @@ def _wrap_selection(self, selection): return {f: v for f, v in zip(self.keys, selection)} def _get_keys(self): - self.cursor.execute("PRAGMA table_info({});".format(self.tname)) + self.cursor.execute(f"PRAGMA table_info({self.tname});") return [info[1] for info in self.cursor] def _get_types(self): - self.cursor.execute("PRAGMA table_info({});".format(self.tname)) + self.cursor.execute(f"PRAGMA table_info({self.tname});") return {info[1]: info[2] for info in self.cursor} def fit(self, data: List[Dict]) -> None: if not self._check_if_table_exists(): - self.keys = self.keys or list(set(k for d in data for k in d.keys())) - types = ('integer' if type(data[0][k]) == int else 'text' for k in self.keys) + self.keys = self.keys or list(set(k for d in data + for k in d.keys())) + types = ('integer' + if type(data[0][k]) == int else 'text' + for k in self.keys) self._create_table(self.keys, types) elif not self.keys: self.keys = self._get_keys() @@ -129,13 +135,14 @@ def fit(self, data: List[Dict]) -> None: def _create_table(self, keys, types): if any(pk not in keys for pk in self.primary_keys): - raise ValueError("Primary keys must be from {}.".format(keys)) - new_types = ("{} {} primary key".format(k, t) if k in self.primary_keys else - "{} {}".format(k, t) + raise ValueError(f"Primary keys must be from {keys}.") + new_types = (f"{k} {t} primary key" + if k in self.primary_keys else f"{k} {t}" for k, t in zip(keys, types)) - self.cursor.execute("CREATE TABLE IF NOT EXISTS {} ({})" - .format(self.tname, ', '.join(new_types))) - log.info("Created table with keys {}.".format(self._get_types())) + new_types_joined = ', '.join(new_types) + self.cursor.execute(f"CREATE TABLE IF NOT EXISTS {self.tname}" + f" ({new_types_joined})") + log.info(f"Created table with keys {self._get_types()}.") def _insert_many(self, data): to_insert = {} @@ -154,8 +161,8 @@ def _insert_many(self, data): if to_insert: fformat = ','.join(['?'] * len(self.keys)) - self.cursor.executemany("INSERT into {}".format(self.tname) + - " VALUES ({})".format(fformat), + self.cursor.executemany(f"INSERT into {self.tname}" + + f" VALUES ({fformat})", to_insert.values()) if to_update: for record in to_update.values(): @@ -165,24 +172,25 @@ def _insert_many(self, data): def _get_record(self, primary_values): ffields = ', '.join(self.keys) or '*' - where_expr = ' AND '.join("{} = '{}'".format(pk, v) - for pk, v in zip(self.primary_keys, primary_values)) - fetched = self.cursor.execute("SELECT {} FROM {}".format(ffields, self.tname) + - " WHERE {}".format(where_expr)).fetchone() + where_expr = " AND ".join(f"{pk} = '{v}'" + for pk, v in zip(self.primary_keys, + primary_values)) + fetched = self.cursor.execute(f"SELECT {ffields} FROM {self.tname}" + + f" WHERE {where_expr}").fetchone() if not fetched: return None return fetched def _update_one(self, record): - set_expr = ', '.join("{} = '{}'".format(k, v) + set_expr = ', '.join(f"{k} = '{v}'" for k, v in zip(self.keys, record) if k not in self.primary_keys) - where_expr = ' AND '.join("{} = '{}'".format(k, v) + where_expr = " AND ".join(f"{k} = '{v}'" for k, v in zip(self.keys, record) if k in self.primary_keys) - self.cursor.execute("UPDATE {}".format(self.tname) + - " SET {}".format(set_expr) + - " WHERE {}".format(where_expr)) + self.cursor.execute(f"UPDATE {self.tname}" + + f" SET {set_expr}" + + f" WHERE {where_expr}") def save(self): pass diff --git a/deeppavlov/core/layers/tf_layers.py b/deeppavlov/core/layers/tf_layers.py index b5b4e54c5b..7cb8298fb8 100644 --- a/deeppavlov/core/layers/tf_layers.py +++ b/deeppavlov/core/layers/tf_layers.py @@ -945,4 +945,4 @@ def variational_dropout(units, keep_prob, fixed_mask_dims=(1,)): noise_shape = [units_shape[n] for n in range(len(units.shape))] for dim in fixed_mask_dims: noise_shape[dim] = 1 - return tf.nn.dropout(units, keep_prob, noise_shape) + return tf.nn.dropout(units, rate=1-keep_prob, noise_shape=noise_shape) diff --git a/deeppavlov/dataset_iterators/basic_classification_iterator.py b/deeppavlov/dataset_iterators/basic_classification_iterator.py index 42cb4a5256..1168142c4d 100644 --- a/deeppavlov/dataset_iterators/basic_classification_iterator.py +++ b/deeppavlov/dataset_iterators/basic_classification_iterator.py @@ -49,12 +49,12 @@ class BasicClassificationDatasetIterator(DataLearningIterator): def __init__(self, data: dict, fields_to_merge: List[str] = None, merged_field: str = None, field_to_split: str = None, split_fields: List[str] = None, split_proportions: List[float] = None, - seed: int = None, shuffle: bool = True, split_seed: int=None, + seed: int = None, shuffle: bool = True, split_seed: int = None, stratify: bool = None, *args, **kwargs): """ Initialize dataset using data from DatasetReader, - merges and splits fields according to the given parameters + merges and splits fields according to the given parameters. """ super().__init__(data, seed=seed, shuffle=shuffle) diff --git a/deeppavlov/dataset_iterators/dstc2_ner_iterator.py b/deeppavlov/dataset_iterators/dstc2_ner_iterator.py index 10c07ab3ad..834c00ebb3 100644 --- a/deeppavlov/dataset_iterators/dstc2_ner_iterator.py +++ b/deeppavlov/dataset_iterators/dstc2_ner_iterator.py @@ -14,12 +14,12 @@ import json import logging -from typing import List, Tuple, Dict +from overrides import overrides +from typing import List, Tuple, Dict, Any from deeppavlov.core.commands.utils import expand_path from deeppavlov.core.common.registry import register from deeppavlov.core.data.data_learning_iterator import DataLearningIterator -from deeppavlov.core.data.utils import download logger = logging.getLogger(__name__) @@ -36,50 +36,61 @@ class Dstc2NerDatasetIterator(DataLearningIterator): seed: value for random seed shuffle: whether to shuffle the data """ - def __init__(self, data: Dict[str, List[Tuple]], dataset_path: str, seed: int = None, shuffle: bool = False): + def __init__(self, + data: Dict[str, List[Tuple]], + slot_values_path: str, + seed: int = None, + shuffle: bool = False): # TODO: include slot vals to dstc2.tar.gz - dataset_path = expand_path(dataset_path) / 'slot_vals.json' - self._build_slot_vals(dataset_path) - with open(dataset_path, encoding='utf8') as f: + with open(expand_path(slot_values_path), encoding='utf8') as f: self._slot_vals = json.load(f) super().__init__(data, seed, shuffle) - def preprocess(self, data_part, *args, **kwargs): - processed_data_part = list() + @overrides + def preprocess(self, + data: List[Tuple[Any, Any]], + *args, **kwargs) -> List[Tuple[Any, Any]]: + processed_data = list() processed_texts = dict() - for sample in data_part: - for utterance in sample: - if 'intents' not in utterance or len(utterance['text']) < 1: - continue - text = utterance['text'] - intents = utterance.get('intents', dict()) - slots = list() - for intent in intents: + for x, y in data: + text = x['text'] + if len(text.strip()) < 1: + continue + intents = [] + if 'intents' in x: + intents = x['intents'] + elif 'slots' in x: + intents = [x] + # aggregate slots from different intents + slots = list() + for intent in intents: + current_slots = intent.get('slots', []) + for slot_type, slot_val in current_slots: + if not self._slot_vals or (slot_type in self._slot_vals): + slots.append((slot_type, slot_val,)) + # remove duplicate pairs (text, slots) + if (text in processed_texts) and (slots in processed_texts[text]): + continue + processed_texts[text] = processed_texts.get(text, []) + [slots] - current_slots = intent.get('slots', []) - for slot_type, slot_val in current_slots: - if slot_type in self._slot_vals: - slots.append((slot_type, slot_val,)) + processed_data.append(self._add_bio_markup(text, slots)) + return processed_data - # remove duplicate pairs (text, slots) - if (text in processed_texts) and (slots in processed_texts[text]): - continue - processed_texts[text] = processed_texts.get(text, []) + [slots] - - processed_data_part.append(self._add_bio_markup(text, slots)) - return processed_data_part - - def _add_bio_markup(self, utterance, slots): + def _add_bio_markup(self, + utterance: str, + slots: List[Tuple[str, str]]) -> List[Tuple[List, List]]: tokens = utterance.split() n_toks = len(tokens) tags = ['O' for _ in range(n_toks)] for n in range(n_toks): for slot_type, slot_val in slots: - for entity in self._slot_vals[slot_type][slot_val]: + for entity in self._slot_vals[slot_type].get(slot_val, + [slot_val]): slot_tokens = entity.split() slot_len = len(slot_tokens) - if n + slot_len <= n_toks and self._is_equal_sequences(tokens[n: n + slot_len], - slot_tokens): + if n + slot_len <= n_toks and \ + self._is_equal_sequences(tokens[n: n + slot_len], + slot_tokens): tags[n] = 'B-' + slot_type for k in range(1, slot_len): tags[n + k] = 'I-' + slot_type @@ -90,8 +101,3 @@ def _add_bio_markup(self, utterance, slots): def _is_equal_sequences(seq1, seq2): equality_list = [tok1 == tok2 for tok1, tok2 in zip(seq1, seq2)] return all(equality_list) - - @staticmethod - def _build_slot_vals(slot_vals_json_path='data/'): - url = 'http://files.deeppavlov.ai/datasets/dstc_slot_vals.json' - download(slot_vals_json_path, url) diff --git a/deeppavlov/dataset_readers/dstc2_reader.py b/deeppavlov/dataset_readers/dstc2_reader.py index e8fc16862b..187d047e52 100644 --- a/deeppavlov/dataset_readers/dstc2_reader.py +++ b/deeppavlov/dataset_readers/dstc2_reader.py @@ -70,7 +70,7 @@ class DSTC2DatasetReader(DatasetReader): @staticmethod def _data_fname(datatype): assert datatype in ('trn', 'val', 'tst'), "wrong datatype name" - return 'dstc2-{}.jsonlist'.format(datatype) + return f"dstc2-{datatype}.jsonlist" @classmethod @overrides @@ -92,7 +92,7 @@ def read(self, data_path: str, dialogs: bool = False) -> Dict[str, List]: """ required_files = (self._data_fname(dt) for dt in ('trn', 'val', 'tst')) if not all(Path(data_path, f).exists() for f in required_files): - log.info('[downloading data from {} to {}]'.format(self.url, data_path)) + log.info(f"[downloading data from {self.url} to {data_path}]") download_decompress(self.url, data_path) mark_done(data_path) @@ -109,7 +109,7 @@ def read(self, data_path: str, dialogs: bool = False) -> Dict[str, List]: @classmethod def _read_from_file(cls, file_path, dialogs=False): """Returns data from single file""" - log.info("[loading dialogs from {}]".format(file_path)) + log.info(f"[loading dialogs from {file_path}]") utterances, responses, dialog_indices =\ cls._get_turns(cls._iter_file(file_path), with_indices=True) @@ -122,14 +122,15 @@ def _read_from_file(cls, file_path, dialogs=False): @staticmethod def _format_turn(turn): - x = {'text': turn[0]['text'], - 'intents': turn[0]['dialog_acts']} - if turn[0].get('db_result') is not None: - x['db_result'] = turn[0]['db_result'] - if turn[0].get('episode_done'): + turn_x, turn_y = turn + x = {'text': turn_x['text'], + 'intents': turn_x['dialog_acts']} + if turn_x.get('db_result') is not None: + x['db_result'] = turn_x['db_result'] + if turn_x.get('episode_done'): x['episode_done'] = True - y = {'text': turn[1]['text'], - 'act': turn[1]['dialog_acts'][0]['act']} + y = {'text': turn_y['text'], + 'act': turn_y['dialog_acts'][0]['act']} return (x, y) @staticmethod @@ -180,9 +181,9 @@ def _get_turns(data, with_indices=False): else: new_turn = copy.deepcopy(utterances[-1]) if 'db_result' not in responses[-1]: - raise RuntimeError("Every api_call action should have" - " db_result, turn = {}" - .format(responses[-1])) + raise RuntimeError(f"Every api_call action" + f" should have db_result," + f" turn = {responses[-1]}") new_turn['db_result'] = responses[-1].pop('db_result') utterances.append(new_turn) responses.append(turn) @@ -198,3 +199,164 @@ def _get_turns(data, with_indices=False): if with_indices: return utterances, responses, dialog_indices return utterances, responses + + +@register('simple_dstc2_reader') +class SimpleDSTC2DatasetReader(DatasetReader): + """ + Contains labelled dialogs from Dialog State Tracking Challenge 2 + (http://camdial.org/~mh521/dstc/). + + There've been made the following modifications to the original dataset: + + 1. added api calls to restaurant database + + - example: ``{"text": "api_call area=\"south\" food=\"dontcare\" + pricerange=\"cheap\"", "dialog_acts": ["api_call"]}``. + + 2. new actions + + - bot dialog actions were concatenated into one action + (example: ``{"dialog_acts": ["ask", "request"]}`` -> + ``{"dialog_acts": ["ask_request"]}``) + + - if a slot key was associated with the dialog action, the new act + was a concatenation of an act and a slot key (example: + ``{"dialog_acts": ["ask"], "slot_vals": ["area"]}`` -> + ``{"dialog_acts": ["ask_area"]}``) + + 3. new train/dev/test split + + - original dstc2 consisted of three different MDP policies, the original + train and dev datasets (consisting of two policies) were merged and + randomly split into train/dev/test + + 4. minor fixes + + - fixed several dialogs, where actions were wrongly annotated + - uppercased first letter of bot responses + - unified punctuation for bot responses + """ + + url = 'http://files.deeppavlov.ai/datasets/simple_dstc2.tar.gz' + + @staticmethod + def _data_fname(datatype): + assert datatype in ('trn', 'val', 'tst'), "wrong datatype name" + return f"simple-dstc2-{datatype}.json" + + @classmethod + @overrides + def read(self, data_path: str, dialogs: bool = False) -> Dict[str, List]: + """ + Downloads ``'simple_dstc2.tar.gz'`` archive from internet, + decompresses and saves files to ``data_path``. + + Parameters: + data_path: path to save DSTC2 dataset + dialogs: flag which indicates whether to output list of turns or + list of dialogs + + Returns: + dictionary that contains ``'train'`` field with dialogs from + ``'simple-dstc2-trn.json'``, ``'valid'`` field with dialogs + from ``'simple-dstc2-val.json'`` and ``'test'`` field with + dialogs from ``'simple-dstc2-tst.json'``. + Each field is a list of tuples ``(user turn, system turn)``. + """ + required_files = (self._data_fname(dt) for dt in ('trn', 'val', 'tst')) + if not all(Path(data_path, f).exists() for f in required_files): + log.info(f"{[Path(data_path, f) for f in required_files]}]") + log.info(f"[downloading data from {self.url} to {data_path}]") + download_decompress(self.url, data_path) + mark_done(data_path) + + data = { + 'train': self._read_from_file( + Path(data_path, self._data_fname('trn')), dialogs), + 'valid': self._read_from_file( + Path(data_path, self._data_fname('val')), dialogs), + 'test': self._read_from_file( + Path(data_path, self._data_fname('tst')), dialogs) + } + log.info(f"There are {len(data['train'])} samples in train split.") + log.info(f"There are {len(data['valid'])} samples in valid split.") + log.info(f"There are {len(data['test'])} samples in test split.") + return data + + @classmethod + def _read_from_file(cls, file_path: str, dialogs: bool = False): + """Returns data from single file""" + log.info(f"[loading dialogs from {file_path}]") + + utterances, responses, dialog_indices =\ + cls._get_turns(json.load(open(file_path, 'rt')), with_indices=True) + + data = list(map(cls._format_turn, zip(utterances, responses))) + + if dialogs: + return [data[idx['start']:idx['end']] for idx in dialog_indices] + return data + + @staticmethod + def _format_turn(turn): + turn_x, turn_y = turn + x = {'text': turn_x['text']} + y = {'text': turn_y['text'], + 'act': turn_y['act']} + if 'act' in turn_x: + x['intents'] = turn_x['act'] + if 'episode_done' in turn_x: + x['episode_done'] = turn_x['episode_done'] + if turn_x.get('db_result') is not None: + x['db_result'] = turn_x['db_result'] + if turn_x.get('slots'): + x['slots'] = turn_x['slots'] + if turn_y.get('slots'): + y['slots'] = turn_y['slots'] + return (x, y) + + @staticmethod + def _get_turns(data, with_indices=False): + n = 0 + utterances, responses, dialog_indices = [], [], [] + for dialog in data: + cur_n_utter, cur_n_resp = 0, 0 + for i, turn in enumerate(dialog): + speaker = turn.pop('speaker') + if speaker == 1: + if i == 0: + turn['episode_done'] = True + utterances.append(turn) + cur_n_utter += 1 + elif speaker == 2: + responses.append(turn) + cur_n_resp += 1 + if cur_n_utter not in range(cur_n_resp - 2, cur_n_resp + 1): + raise RuntimeError("Datafile has wrong format.") + if cur_n_utter != cur_n_resp: + if i == 0: + new_utter = { + "text": "", + "episode_done": True + } + else: + new_utter = copy.deepcopy(utterances[-1]) + if 'db_result' not in responses[-2]: + raise RuntimeError("Every api_call action" + " should have db_result") + db_result = responses[-2].pop('db_result') + new_utter['db_result'] = db_result + utterances.append(new_utter) + cur_n_utter += 1 + if cur_n_utter != cur_n_resp: + raise RuntimeError("Datafile has wrong format.") + n += cur_n_utter + dialog_indices.append({ + 'start': n - cur_n_utter, + 'end': n, + }) + + if with_indices: + return utterances, responses, dialog_indices + return utterances, responses diff --git a/deeppavlov/download.py b/deeppavlov/download.py index 7ae7b73846..6b4f48723a 100644 --- a/deeppavlov/download.py +++ b/deeppavlov/download.py @@ -109,8 +109,9 @@ def check_md5(url: str, dest_paths: List[Path]) -> bool: return True -def download_resource(url: str, dest_paths: Iterable[Path]) -> None: - dest_paths = list(dest_paths) +def download_resource(url: str, dest_paths: Iterable[Union[Path, str]]) \ + -> None: + dest_paths = [Path(dest) for dest in dest_paths] if check_md5(url, dest_paths): log.info(f'Skipped {url} download because of matching hashes') diff --git a/deeppavlov/models/go_bot/network.py b/deeppavlov/models/go_bot/network.py index a5e713fb47..e7c304f95d 100644 --- a/deeppavlov/models/go_bot/network.py +++ b/deeppavlov/models/go_bot/network.py @@ -15,8 +15,9 @@ import collections import json import re +import copy from logging import getLogger -from typing import Dict, Any +from typing import Dict, Any, List, Optional, Union, Tuple import numpy as np import tensorflow as tf @@ -38,9 +39,9 @@ @register("go_bot") class GoalOrientedBot(LRScheduledTFModel): """ - The dialogue bot is based on https://arxiv.org/abs/1702.03274, which introduces - Hybrid Code Networks that combine an RNN with domain-specific knowledge - and system action templates. + The dialogue bot is based on https://arxiv.org/abs/1702.03274, which + introduces Hybrid Code Networks that combine an RNN with domain-specific + knowledge and system action templates. The network handles dialogue policy management. Inputs features of an utterance and predicts label of a bot action @@ -91,8 +92,8 @@ class GoalOrientedBot(LRScheduledTFModel): slot_filler: component that outputs slot values for a given utterance (:class:`~deeppavlov.models.slotfill.slotfill.DstcSlotFillingNetwork` recommended). - intent_classifier: component that outputs intents probability distribution - for a given utterance ( + intent_classifier: component that outputs intents probability + distribution for a given utterance ( :class:`~deeppavlov.models.classifiers.keras_classification_model.KerasClassificationModel` recommended). database: database that will be used during inference to perform @@ -132,21 +133,21 @@ def __init__(self, slot_filler: Component = None, intent_classifier: Component = None, database: Component = None, - api_call_action: str = None, # TODO: make it unrequired + api_call_action: str = None, use_action_mask: bool = False, debug: bool = False, - **kwargs): + **kwargs) -> None: if any(p in network_parameters for p in self.DEPRECATED): log.warning(f"parameters {self.DEPRECATED} are deprecated," - " for learning rate schedule documentation see" - " deeppavlov.core.models.lr_scheduled_tf_model" - " or read gitub tutorial on super convergence.") + f" for learning rate schedule documentation see" + f" deeppavlov.core.models.lr_scheduled_tf_model" + f" or read gitub tutorial on super convergence.") if 'learning_rate' in network_parameters: kwargs['learning_rate'] = network_parameters.pop('learning_rate') super().__init__(load_path=load_path, save_path=save_path, **kwargs) self.tokenizer = tokenizer - self.tracker = tracker + self.default_tracker = tracker self.bow_embedder = bow_embedder self.embedder = embedder self.slot_filler = slot_filler @@ -157,13 +158,13 @@ def __init__(self, template_path = expand_path(template_path) template_type = getattr(templ, template_type) - log.info("[loading templates from {}]".format(template_path)) + log.info(f"[loading templates from {template_path}]") self.templates = templ.Templates(template_type).load(template_path) self.n_actions = len(self.templates) - log.info("{} templates loaded".format(self.n_actions)) + log.info(f"{self.n_actions} templates loaded.") self.database = database - self.api_call_id = None + self.api_call_id = -1 if api_call_action is not None: self.api_call_id = self.templates.actions.index(api_call_action) @@ -185,14 +186,21 @@ def __init__(self, new_network_parameters.update(network_parameters) self._init_network(**new_network_parameters) + self.states = {} self.reset() - def _init_network(self, hidden_size, action_size, obs_size, dropout_rate, - l2_reg_coef, dense_size, attn): + def _init_network(self, + hidden_size: int, + action_size: int, + obs_size: int, + dropout_rate: float, + l2_reg_coef: float, + dense_size: int, + attn: dict) -> None: # initialize network dense_size = dense_size or hidden_size if obs_size is None: - obs_size = 6 + self.tracker.num_features + self.n_actions + obs_size = 6 + self.default_tracker.num_features + self.n_actions if callable(self.bow_embedder): obs_size += len(self.word_vocab) if callable(self.embedder): @@ -237,17 +245,14 @@ def _init_network(self, hidden_size, action_size, obs_size, dropout_rate, self.sess.run(tf.global_variables_initializer()) if tf.train.checkpoint_exists(str(self.load_path.resolve())): - log.info("[initializing `{}` from saved]".format(self.__class__.__name__)) + log.info(f"[initializing `{self.__class__.__name__}` from saved]") self.load() else: - log.info("[initializing `{}` from scratch]".format(self.__class__.__name__)) - - def _encode_context(self, context, db_result=None): - # tokenize input - tokens = self.tokenizer([context.lower().strip()])[0] - if self.debug: - log.debug("Tokenized text= `{}`".format(' '.join(tokens))) + log.info(f"[initializing `{self.__class__.__name__}` from scratch]") + def _encode_context(self, + tokens: List[str], + state: dict) -> List[np.ndarray]: # Bag of words features bow_features = [] if callable(self.bow_embedder): @@ -282,128 +287,126 @@ def _encode_context(self, context, db_result=None): # Intent features intent_features = [] if callable(self.intent_classifier): - intent_features = self.intent_classifier([context])[1][0] + intent_features = self.intent_classifier([' '.join(tokens)])[1][0] if self.debug: intent = self.intents[np.argmax(intent_features[0])] - log.debug("Predicted intent = `{}`".format(intent)) + log.debug(f"Predicted intent = `{intent}`") attn_key = np.array([], dtype=np.float32) if self.attn: if self.attn.action_as_key: - attn_key = np.hstack((attn_key, self.prev_action)) + attn_key = np.hstack((attn_key, state['prev_action'])) if self.attn.intent_as_key: attn_key = np.hstack((attn_key, intent_features)) if len(attn_key) == 0: attn_key = np.array([1], dtype=np.float32) - # Text entity features - if callable(self.slot_filler): - self.tracker.update_state(self.slot_filler([tokens])[0]) - if self.debug: - log.debug("Slot vals: {}".format(self.slot_filler([tokens]))) - - state_features = self.tracker.get_features() + state_features = state['tracker'].get_features() # Other features result_matches_state = 0. - if self.db_result is not None: - result_matches_state = all(v == self.db_result.get(s) - for s, v in self.tracker.get_state().items() + if state['db_result'] is not None: + matching_items = state['tracker'].get_state().items() + result_matches_state = all(v == state['db_result'].get(s) + for s, v in matching_items if v != 'dontcare') * 1. - context_features = np.array([bool(db_result) * 1., - (db_result == {}) * 1., - (self.db_result is None) * 1., - bool(self.db_result) * 1., - (self.db_result == {}) * 1., + context_features = np.array([bool(state['current_db_result']) * 1., + (state['current_db_result'] == {}) * 1., + (state['db_result'] is None) * 1., + bool(state['db_result']) * 1., + (state['db_result'] == {}) * 1., result_matches_state], dtype=np.float32) if self.debug: - log.debug("Context features = {}".format(context_features)) - debug_msg = "num bow features = {}, ".format(len(bow_features)) +\ - "num emb features = {}, ".format(len(emb_features)) +\ - "num intent features = {}, ".format(len(intent_features)) +\ - "num state features = {}, ".format(len(state_features)) +\ - "num context features = {}, ".format(len(context_features)) +\ - "prev_action shape = {}".format(len(self.prev_action)) + log.debug(f"Context features = {context_features}") + debug_msg = f"num bow features = {bow_features}" +\ + f", num emb features = {emb_features}" +\ + f", num intent features = {intent_features}" +\ + f", num state features = {len(state_features)}" +\ + f", num context features = {len(context_features)}" +\ + f", prev_action shape = {len(state['prev_action'])}" log.debug(debug_msg) concat_feats = np.hstack((bow_features, emb_features, intent_features, - state_features, context_features, self.prev_action)) + state_features, context_features, + state['prev_action'])) return concat_feats, emb_context, attn_key - def _encode_response(self, act): + def _encode_response(self, act: str) -> int: return self.templates.actions.index(act) - def _decode_response(self, action_id): + def _decode_response(self, action_id: int, state: dict) -> str: """ Convert action template id and entities from tracker to final response. """ template = self.templates.templates[int(action_id)] - slots = self.tracker.get_state() - if self.db_result is not None: - for k, v in self.db_result.items(): + slots = state['tracker'].get_state() + if state['db_result'] is not None: + for k, v in state['db_result'].items(): slots[k] = str(v) resp = template.generate_text(slots) # in api calls replace unknown slots to "dontcare" - if (self.templates.ttype is templ.DualTemplate) and\ - (action_id == self.api_call_id): + if action_id == self.api_call_id: resp = re.sub("#([A-Za-z]+)", "dontcare", resp).lower() - if self.debug: - log.debug("Pred response = {}".format(resp)) return resp - def calc_action_mask(self, previous_action): + def calc_action_mask(self, state: dict) -> np.ndarray: mask = np.ones(self.n_actions, dtype=np.float32) if self.use_action_mask: - known_entities = {**self.tracker.get_state(), **(self.db_result or {})} + known_entities = {**state['tracker'].get_state(), + **(state['db_result'] or {})} for a_id in range(self.n_actions): tmpl = str(self.templates.templates[a_id]) for entity in set(re.findall('#([A-Za-z]+)', tmpl)): if entity not in known_entities: mask[a_id] = 0. # forbid two api calls in a row - if np.any(previous_action): - prev_act_id = np.argmax(previous_action) + if np.any(state['prev_action']): + prev_act_id = np.argmax(state['prev_action']) if prev_act_id == self.api_call_id: mask[prev_act_id] = 0. return mask - def prepare_data(self, x, y): + def prepare_data(self, x: List[dict], y: List[dict]) -> List[np.ndarray]: b_features, b_u_masks, b_a_masks, b_actions = [], [], [], [] b_emb_context, b_keys = [], [] # for attention max_num_utter = max(len(d_contexts) for d_contexts in x) for d_contexts, d_responses in zip(x, y): - self.reset() - if self.debug: - preds = self._infer_dialog(d_contexts) + state = self._zero_state() d_features, d_a_masks, d_actions = [], [], [] d_emb_context, d_key = [], [] # for attention for context, response in zip(d_contexts, d_responses): - if context.get('db_result') is not None: - self.db_result = context['db_result'] - features, emb_context, key = \ - self._encode_context(context['text'], context.get('db_result')) + tokens = self.tokenizer([context['text'].lower().strip()])[0] + + # update state + state['current_db_result'] = context.get('db_result', None) + if state['current_db_result'] is not None: + state['db_result'] = state['current_db_result'] + if callable(self.slot_filler): + context_slots = self.slot_filler([tokens])[0] + state['tracker'].update_state(context_slots) + + features, emb_context, key = self._encode_context(tokens, + state=state) d_features.append(features) d_emb_context.append(emb_context) d_key.append(key) - d_a_masks.append(self.calc_action_mask(self.prev_action)) + d_a_masks.append(self.calc_action_mask(state)) action_id = self._encode_response(response['act']) d_actions.append(action_id) - # previous action is teacher-forced here - self.prev_action *= 0. - self.prev_action[action_id] = 1. + # update state + # - previous action is teacher-forced here + state['prev_action'] *= 0. + state['prev_action'][action_id] = 1. if self.debug: - log.debug("True response = `{}`".format(response['text'])) - if preds[0].lower() != response['text'].lower(): - log.debug("Pred response = `{}`".format(preds[0])) - preds = preds[1:] + log.debug(f"True response = '{response['text']}'.") if d_a_masks[-1][action_id] != 1.: log.warn("True action forbidden by action mask.") @@ -424,41 +427,48 @@ def prepare_data(self, x, y): b_actions.append(d_actions) return b_features, b_emb_context, b_keys, b_u_masks, b_a_masks, b_actions - def train_on_batch(self, x, y): + def train_on_batch(self, x: List[dict], y: List[dict]) -> dict: return self.network_train_on_batch(*self.prepare_data(x, y)) - def _infer(self, context, db_result=None, prob=False): - if db_result is not None: - self.db_result = db_result - features, emb_context, key = self._encode_context(context, db_result) - action_mask = self.calc_action_mask(self.prev_action) - probs = self.network_call([[features]], [[emb_context]], [[key]], - [[action_mask]], prob=True) - pred_id = np.argmax(probs) - - # one-hot encoding seems to work better then probabilities - if prob: - self.prev_action = probs - else: - self.prev_action *= 0 - self.prev_action[pred_id] = 1 - - return self._decode_response(pred_id) - - def _infer_dialog(self, contexts): - self.reset() + def _infer(self, tokens: List[str], state: dict) -> List: + features, emb_context, key = self._encode_context(tokens, state=state) + action_mask = self.calc_action_mask(state) + probs, state_c, state_h = \ + self.network_call([[features]], [[emb_context]], [[key]], + [[action_mask]], [[state['network_state'][0]]], + [[state['network_state'][1]]], + prob=True) + return probs, np.argmax(probs), (state_c, state_h) + + def _infer_dialog(self, contexts: List[dict]) -> List[str]: res = [] + state = self._zero_state() for context in contexts: if context.get('prev_resp_act') is not None: - action_id = self._encode_response(context.get('prev_resp_act')) + prev_act_id = self._encode_response(context['prev_resp_act']) # previous action is teacher-forced - self.prev_action *= 0. - self.prev_action[action_id] = 1. - - res.append(self._infer(context['text'], db_result=context.get('db_result'))) + state['prev_action'] *= 0. + state['prev_action'][prev_act_id] = 1. + + state['current_db_result'] = context.get('db_result') + if state['current_db_result'] is not None: + state['db_result'] = state['current_db_result'] + + tokens = self.tokenizer([context['text'].lower().strip()])[0] + if callable(self.slot_filler): + utter_slots = self.slot_filler([tokens])[0] + state['tracker'].update_state(utter_slots) + _, pred_act_id, state['network_state'] = \ + self._infer(tokens, state=state) + state['prev_action'] *= 0. + state['prev_action'][pred_act_id] = 1. + + resp = self._decode_response(pred_act_id, state) + res.append(resp) return res - def make_api_call(self, slots): + def make_api_call(self, state: dict) -> dict: + slots = state['tracker'].get_state() db_results = [] if self.database is not None: # filter slot keys with value equal to 'dontcare' as @@ -467,43 +477,82 @@ def make_api_call(self, slots): db_slots = {s: v for s, v in slots.items() if (v != 'dontcare') and (s in self.database.keys)} db_results = self.database([db_slots])[0] + # filter api results if there are more than one + if len(db_results) > 1: + db_results = [r for r in db_results if r != state['db_result']] else: log.warn("No database specified.") - log.info("Made api_call with {}, got {} results.".format(slots, len(db_results))) - # filter api results if there are more than one - if len(db_results) > 1: - db_results = [r for r in db_results if r != self.db_result] - return db_results[0] if db_results else {} + log.info(f"Made api_call with {slots}, got {len(db_results)} results.") + return {} if not db_results else db_results[0] - def __call__(self, batch): + def __call__(self, + batch: Union[List[dict], List[str]], + user_ids: Optional[List] = None) -> List[str]: + # batch is a list of utterances if isinstance(batch[0], str): res = [] - for x in batch: - pred = self._infer(x) + if not user_ids: + user_ids = ['finn' for i in range(len(batch))] + for user_id, x in zip(user_ids, batch): + state = self.states[user_id] + state['current_db_result'] = None + + tokens = self.tokenizer([x.lower().strip()])[0] + if callable(self.slot_filler): + utter_slots = self.slot_filler([tokens])[0] + state['tracker'].update_state(utter_slots) + _, pred_act_id, state['network_state'] = \ + self._infer(tokens, state=state) + state['prev_action'] *= 0. + state['prev_action'][pred_act_id] = 1. + # if made api_call, then respond with next prediction - prev_act_id = np.argmax(self.prev_action) - if prev_act_id == self.api_call_id: - db_result = self.make_api_call(self.tracker.get_state()) - res.append(self._infer(x, db_result=db_result)) - else: - res.append(pred) + if pred_act_id == self.api_call_id: + state['current_db_result'] = self.make_api_call(state) + if state['current_db_result'] is not None: + state['db_result'] = state['current_db_result'] + _, pred_act_id, state['network_state'] = \ + self._infer(tokens, state=state) + state['prev_action'] *= 0. + state['prev_action'][pred_act_id] = 1. + + resp = self._decode_response(pred_act_id, state) + res.append(resp) + self.states[user_id] = state return res + # batch is a list of dialogs, user_ids ignored return [self._infer_dialog(x) for x in batch] - def reset(self): - self.tracker.reset_state() - self.db_result = None - self.prev_action = np.zeros(self.n_actions, dtype=np.float32) - self.reset_network_state() + def _zero_state(self) -> dict: + return { + 'tracker': copy.deepcopy(self.default_tracker), + 'db_result': None, + 'current_db_result': None, + 'prev_action': np.zeros(self.n_actions, dtype=np.float32), + 'network_state': ( + np.zeros([1, self.hidden_size], dtype=np.float32), + np.zeros([1, self.hidden_size], dtype=np.float32) + ) + } + + def reset(self, user_id: Union[str, int] = 'finn') -> None: + self.states[user_id] = self._zero_state() if self.debug: log.debug("Bot reset.") - def network_call(self, features, emb_context, key, action_mask, prob=False): + def network_call(self, + features: np.ndarray, + emb_context: np.ndarray, + key: np.ndarray, + action_mask: np.ndarray, + states_c: np.ndarray, + states_h: np.ndarray, + prob: bool = False) -> List[np.ndarray]: feed_dict = { self._features: features, self._dropout_keep_prob: 1., self._utterance_mask: [[1.]], - self._initial_state: (self.state_c, self.state_h), + self._initial_state: (states_c, states_h), self._action_mask: action_mask } if self.attn: @@ -514,13 +563,17 @@ def network_call(self, features, emb_context, key, action_mask, prob=False): self.sess.run([self._probs, self._prediction, self._state], feed_dict=feed_dict) - self.state_c, self._state_h = state if prob: - return probs - return prediction - - def network_train_on_batch(self, features, emb_context, key, utter_mask, - action_mask, action): + return probs, state[0], state[1] + return prediction, state[0], state[1] + + def network_train_on_batch(self, + features: np.ndarray, + emb_context: np.ndarray, + key: np.ndarray, + utter_mask: np.ndarray, + action_mask: np.ndarray, + action: np.ndarray) -> dict: feed_dict = { self._dropout_keep_prob: 1., self._utterance_mask: utter_mask, @@ -539,7 +592,7 @@ def network_train_on_batch(self, features, emb_context, key, utter_mask, 'learning_rate': self.get_learning_rate(), 'momentum': self.get_momentum()} - def _init_network_params(self): + def _init_network_params(self) -> None: self.dropout_rate = self.opt['dropout_rate'] self.hidden_size = self.opt['hidden_size'] self.action_size = self.opt['action_size'] @@ -557,7 +610,7 @@ def _init_network_params(self): else: self.attn = None - def _build_graph(self): + def _build_graph(self) -> None: self._add_placeholders() @@ -584,7 +637,7 @@ def _build_graph(self): self._loss += self.l2_reg * tf.losses.get_regularization_loss() self._train_op = self.get_train_op(self._loss) - def _add_placeholders(self): + def _add_placeholders(self) -> None: self._dropout_keep_prob = tf.placeholder_with_default(1.0, shape=[], name='dropout_prob') @@ -618,13 +671,13 @@ def _add_placeholders(self): [None, None, self.attn.key_size], name='key') - def _build_body(self): + def _build_body(self) -> Tuple[tf.Tensor, tf.Tensor]: # input projection _units = tf.layers.dense(self._features, self.dense_size, kernel_regularizer=tf.nn.l2_loss, kernel_initializer=xav()) if self.attn: - attn_scope = "attention_mechanism/{}".format(self.attn.type) + attn_scope = f"attention_mechanism/{self.attn.type}" with tf.variable_scope(attn_scope): if self.attn.type == 'general': _attn_output = am.general_attention( @@ -673,7 +726,10 @@ def _build_body(self): # recurrent network unit _lstm_cell = tf.nn.rnn_cell.LSTMCell(self.hidden_size) - _utter_lengths = tf.to_int32(tf.reduce_sum(self._utterance_mask, axis=-1)) + _utter_lengths = tf.cast(tf.reduce_sum(self._utterance_mask, axis=-1), + tf.int32) + # _output: [batch_size, max_time, hidden_size] + # _state: tuple of two [batch_size, hidden_size] _output, _state = tf.nn.dynamic_rnn(_lstm_cell, _units, time_major=False, @@ -688,35 +744,30 @@ def _build_body(self): kernel_initializer=xav(), name='logits') return _logits, _state - def load(self, *args, **kwargs): + def load(self, *args, **kwargs) -> None: self.load_params() super().load(*args, **kwargs) - def save(self, *args, **kwargs): + def save(self, *args, **kwargs) -> None: super().save(*args, **kwargs) self.save_params() - def save_params(self): + def save_params(self) -> None: path = str(self.save_path.with_suffix('.json').resolve()) - log.info('[saving parameters to {}]'.format(path)) + log.info(f"[saving parameters to {path}]") with open(path, 'w', encoding='utf8') as fp: json.dump(self.opt, fp) - def load_params(self): + def load_params(self) -> None: path = str(self.load_path.with_suffix('.json').resolve()) - log.info('[loading parameters from {}]'.format(path)) + log.info(f"[loading parameters from {path}]") with open(path, 'r', encoding='utf8') as fp: params = json.load(fp) for p in self.GRAPH_PARAMS: if self.opt.get(p) != params.get(p): - raise ConfigError("`{}` parameter must be equal to saved model " - "parameter value `{}`, but is equal to `{}`" - .format(p, params.get(p), self.opt.get(p))) + raise ConfigError(f"`{p}` parameter must be equal to saved" + f" model parameter value `{params.get(p)}`," + f" but is equal to `{self.opt.get(p)}`") - def process_event(self, event_name, data): + def process_event(self, event_name, data) -> None: super().process_event(event_name, data) - - def reset_network_state(self): - # set zero state - self.state_c = np.zeros([1, self.hidden_size], dtype=np.float32) - self.state_h = np.zeros([1, self.hidden_size], dtype=np.float32) diff --git a/docs/features/overview.rst b/docs/features/overview.rst index a8917f4ed9..ed280db9db 100644 --- a/docs/features/overview.rst +++ b/docs/features/overview.rst @@ -444,9 +444,9 @@ Available pre-trained models and their comparison with existing benchmarks: +----------------+------+-------------------------------------------------------------------------------------+---------------+---------+------------+------------------+ | Dataset | Lang | Model | Metric | Valid | Test | Downloads | +================+======+=====================================================================================+===============+=========+============+==================+ -| `DSTC 2`_ [*]_ | En | :config:`bot with slot filler ` | Turn Accuracy | 0.521 | 0.529 | 400 Mb | +| `DSTC 2`_ [*]_ | En | :config:`bot with slot filler ` | Turn Accuracy | 0.544 | 0.542 | 400 Mb | + + +-------------------------------------------------------------------------------------+ +---------+------------+------------------+ -| | | :config:`bot with slot filler & intents & attention ` | | 0.555 | **0.561** | 8.5 Gb | +| | | :config:`bot with slot filler & intents & attention ` | | 0.548 | **0.553** | 8.5 Gb | +----------------+ +-------------------------------------------------------------------------------------+ +---------+------------+------------------+ | `DSTC 2`_ | | Bordes and Weston (2016) | | -- | 0.411 | -- | + + +-------------------------------------------------------------------------------------+ +---------+------------+------------------+ diff --git a/docs/features/skills/go_bot.rst b/docs/features/skills/go_bot.rst index bfcffabb95..b1b3079fef 100644 --- a/docs/features/skills/go_bot.rst +++ b/docs/features/skills/go_bot.rst @@ -325,11 +325,9 @@ Scores for different modifications of our bot model and comparison with existing +================+======+===========================================+======================================================================+===============+===========+===============+ | `DSTC 2`_ [*]_ | En | basic bot | :config:`gobot_dstc2_minimal.json ` | Turn Accuracy | 0.380 | 10 Mb | + + +-------------------------------------------+----------------------------------------------------------------------+ +-----------+---------------+ -| | | bot with slot filler | :config:`gobot_dstc2.json ` | | 0.529 | 400 Mb | +| | | bot with slot filler | :config:`gobot_dstc2.json ` | | 0.542 | 400 Mb | + + +-------------------------------------------+----------------------------------------------------------------------+ +-----------+---------------+ -| | | bot with slot filler & intents | | | 0.531 | -- | -+ + +-------------------------------------------+----------------------------------------------------------------------+ +-----------+---------------+ -| | | bot with slot filler, intents & attention | :config:`gobot_dstc2_best.json ` | | **0.561** | 8.5 Gb | +| | | bot with slot filler, intents & attention | :config:`gobot_dstc2_best.json ` | | **0.553** | 8.5 Gb | +----------------+ +-------------------------------------------+----------------------------------------------------------------------+ +-----------+---------------+ | `DSTC 2`_ | | Bordes and Weston (2016) [3]_ | -- | | 0.411 | -- | + + +-------------------------------------------+----------------------------------------------------------------------+ +-----------+---------------+ diff --git a/examples/classification_tutorial.ipynb b/examples/classification_tutorial.ipynb index b80dcb5918..b0c7915b1d 100644 --- a/examples/classification_tutorial.ipynb +++ b/examples/classification_tutorial.ipynb @@ -48,7 +48,7 @@ " * [Vocabulary](#Vocabulary)\n", "3. [Featurization](#Featurization): [docs link](https://deeppavlov.readthedocs.io/en/latest/components/data_processors.html), [pre-trained embeddings link](https://deeppavlov.readthedocs.io/en/latest/intro/pretrained_vectors.html)\n", " * [Bag-of-words embedder](#Bag-of-words)\n", - " * [TF-IDF vectorizer](#TF-IDF Vectorizer)\n", + " * [TF-IDF vectorizer](#TF-IDF-Vectorizer)\n", " * [GloVe embedder](#GloVe-embedder)\n", " * [Mean GloVe embedder](#Mean-GloVe-embedder)\n", " * [GloVe weighted by TF-IDF embedder](#GloVe-weighted-by-TF-IDF-embedder)\n", diff --git a/examples/gobot_tutorial.ipynb b/examples/gobot_tutorial.ipynb new file mode 100644 index 0000000000..8d7e6f14a1 --- /dev/null +++ b/examples/gobot_tutorial.ipynb @@ -0,0 +1,1729 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### You can also run the notebook in [COLAB](https://colab.research.google.com/github/deepmipt/DeepPavlov/blob/master/examples/gobot_tutorial.ipynb)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!pip install deeppavlov" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Goal-oriented bot in DeepPavlov" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The tutor is focused on building a goal-oriented dialogue system:\n", + "\n", + "0. [Data preparation](#0.-Data-Preparation)\n", + "1. [Build database of items](#1.-Build-database-of-items)\n", + "2. [Build Slot Filler](#2.-Build-Slot-Filler)\n", + "3. [Train bot](#3.-Train-bot)\n", + "\n", + "An example of the final model served as a telegram bot is:\n", + "\n", + "![gobot_example.png](img/gobot_example.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 0. Data Preparation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The tutor's dialogue system will be on the domain of restaurant booking. [Dialogue State Tracking Challenge 2 (DSTC-2)](http://camdial.org/~mh521/dstc/) dataset provides dialogues of a human talking to a booking system labelled with slots and dialogue actions. The labels are will be used for training a dialogue policy network.\n", + "\n", + "See below a small chunk of the data. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2019-09-04 14:40:33.370 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 269: [PosixPath('my_data/simple-dstc2-val.json'), PosixPath('my_data/simple-dstc2-tst.json')]]\n", + "2019-09-04 14:40:33.371 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 270: [downloading data from http://files.deeppavlov.ai/datasets/simple_dstc2.tar.gz to my_data]\n", + "2019-09-04 14:40:33.399 INFO in 'deeppavlov.core.data.utils'['utils'] at line 63: Downloading from http://files.deeppavlov.ai/datasets/simple_dstc2.tar.gz to my_data/simple_dstc2.tar.gz\n", + "100%|██████████| 497k/497k [00:00<00:00, 67.5MB/s]\n", + "2019-09-04 14:40:33.410 INFO in 'deeppavlov.core.data.utils'['utils'] at line 201: Extracting my_data/simple_dstc2.tar.gz archive into my_data\n", + "2019-09-04 14:40:33.442 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 290: [loading dialogs from my_data/simple-dstc2-trn.json]\n", + "2019-09-04 14:40:33.534 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 290: [loading dialogs from my_data/simple-dstc2-val.json]\n", + "2019-09-04 14:40:33.604 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 290: [loading dialogs from my_data/simple-dstc2-tst.json]\n", + "2019-09-04 14:40:33.652 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 282: There are 9115 samples in train split.\n", + "2019-09-04 14:40:33.652 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 283: There are 6231 samples in valid split.\n", + "2019-09-04 14:40:33.653 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 284: There are 6345 samples in test split.\n" + ] + } + ], + "source": [ + "from deeppavlov.dataset_readers.dstc2_reader import SimpleDSTC2DatasetReader\n", + "\n", + "data = SimpleDSTC2DatasetReader().read('my_data')" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "simple-dstc2-templates.txt simple-dstc2-tst.json\r\n", + "simple-dstc2-trn.json\t simple-dstc2-val.json\r\n" + ] + } + ], + "source": [ + "!ls my_data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The training/validation/test data is stored in json files (`simple-dstc2-trn.json`, `simple-dstc2-val.json` and `simple-dstc2-tst.json`):" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[\r\n", + " [\r\n", + " {\r\n", + " \"speaker\": 2,\r\n", + " \"text\": \"Hello, welcome to the Cambridge restaurant system. You can ask for restaurants by area, price range or food type. How may I help you?\",\r\n", + " \"slots\": [],\r\n", + " \"act\": \"welcomemsg\"\r\n", + " },\r\n", + " {\r\n", + " \"speaker\": 1,\r\n", + " \"text\": \"cheap restaurant\",\r\n", + " \"slots\": [\r\n", + " [\r\n", + " \"pricerange\",\r\n", + " \"cheap\"\r\n", + " ]\r\n", + " ]\r\n", + " },\r\n", + " {\r\n", + " \"speaker\": 2,\r\n", + " \"text\": \"What kind of food would you like?\",\r\n", + " \"slots\": [],\r\n", + " \"act\": \"request_food\"\r\n", + " },\r\n", + " {\r\n", + " \"speaker\": 1,\r\n", + " \"text\": \"any\",\r\n", + " \"slots\": [\r\n", + " [\r\n", + " \"this\",\r\n", + " \"dontcare\"\r\n", + " ]\r\n", + " ]\r\n", + " },\r\n", + " {\r\n", + " \"speaker\": 2,\r\n", + " \"text\": \"What part of town do you have in mind?\",\r\n", + " \"slots\": [],\r\n", + " \"act\": \"request_area\"\r\n", + " },\r\n", + " {\r\n", + " \"speaker\": 1,\r\n", + " \"text\": \"south\",\r\n", + " \"slots\": [\r\n", + " [\r\n", + " \"area\",\r\n", + " \"south\"\r\n", + " ]\r\n", + " ]\r\n", + " },\r\n", + " {\r\n", + " \"speaker\": 2,\r\n", + " \"text\": \"api_call area=\\\"south\\\" food=\\\"dontcare\\\" pricerange=\\\"cheap\\\"\",\r\n", + " \"db_result\": {\r\n", + " \"food\": \"chinese\",\r\n", + " \"pricerange\": \"cheap\",\r\n", + " \"area\": \"south\",\r\n", + " \"addr\": \"cambridge leisure park clifton way cherry hinton\",\r\n", + " \"phone\": \"01223 244277\",\r\n", + " \"postcode\": \"c.b 1, 7 d.y\",\r\n", + " \"name\": \"the lucky star\"\r\n", + " },\r\n", + " \"slots\": [\r\n", + " [\r\n", + " \"area\",\r\n", + " \"south\"\r\n", + " ],\r\n", + " [\r\n", + " \"pricerange\",\r\n", + " \"cheap\"\r\n", + " ],\r\n", + " [\r\n", + " \"food\",\r\n", + " \"dontcare\"\r\n", + " ]\r\n", + " ],\r\n", + " \"act\": \"api_call\"\r\n", + " },\r\n", + " {\r\n", + " \"speaker\": 2,\r\n", + " \"text\": \"The lucky star is a nice place in the south of town serving tasty chinese food.\",\r\n", + " \"slots\": [\r\n", + " [\r\n", + " \"area\",\r\n", + " \"south\"\r\n", + " ],\r\n", + " [\r\n", + " \"pricerange\",\r\n", + " \"cheap\"\r\n", + " ],\r\n", + " [\r\n", + " \"name\",\r\n", + " \"the lucky star\"\r\n", + " ],\r\n", + " [\r\n", + " \"food\",\r\n", + " \"chinese\"\r\n", + " ]\r\n", + " ],\r\n", + " \"act\": \"inform_area+inform_food+offer_name\"\r\n", + " },\r\n" + ] + } + ], + "source": [ + "!head -n 101 my_data/simple-dstc2-trn.json" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "from deeppavlov.dataset_iterators.dialog_iterator import DialogDatasetIterator\n", + "\n", + "iterator = DialogDatasetIterator(data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can now iterate over batches of preprocessed DSTC-2 dialogs:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "User utterances:\n", + "----------------\n", + "\n", + "[ {'prev_resp_act': None, 'text': ''},\n", + " { 'prev_resp_act': 'welcomemsg',\n", + " 'slots': [['pricerange', 'moderate'], ['area', 'north']],\n", + " 'text': 'im looking for a moderately priced restaurant in the north '\n", + " 'part of town'},\n", + " { 'db_result': { 'addr': '7 milton road chesterton',\n", + " 'area': 'north',\n", + " 'food': 'indian',\n", + " 'name': 'the nirala',\n", + " 'phone': '01223 360966',\n", + " 'postcode': 'c.b 4, 1 u.y',\n", + " 'pricerange': 'moderate'},\n", + " 'prev_resp_act': 'api_call',\n", + " 'slots': [['pricerange', 'moderate'], ['area', 'north']],\n", + " 'text': 'im looking for a moderately priced restaurant in the north '\n", + " 'part of town'},\n", + " { 'prev_resp_act': 'inform_area+inform_pricerange+offer_name',\n", + " 'slots': [['slot', 'phone']],\n", + " 'text': 'what is the phone number'},\n", + " {'prev_resp_act': 'inform_phone+offer_name', 'text': 'thank you goodbye'}]\n", + "\n", + "System responses:\n", + "-----------------\n", + "\n", + "[ { 'act': 'welcomemsg',\n", + " 'text': 'Hello, welcome to the Cambridge restaurant system. You can '\n", + " 'ask for restaurants by area, price range or food type. How '\n", + " 'may I help you?'},\n", + " { 'act': 'api_call',\n", + " 'slots': [['pricerange', 'moderate'], ['area', 'north']],\n", + " 'text': 'api_call area=\"north\" food=\"dontcare\" pricerange=\"moderate\"'},\n", + " { 'act': 'inform_area+inform_pricerange+offer_name',\n", + " 'slots': [ ['pricerange', 'moderate'],\n", + " ['area', 'north'],\n", + " ['name', 'the nirala']],\n", + " 'text': 'The nirala is a nice place in the north of town and the '\n", + " 'prices are moderate.'},\n", + " { 'act': 'inform_phone+offer_name',\n", + " 'slots': [['phone', '01223 360966'], ['name', 'the nirala']],\n", + " 'text': 'The phone number of the nirala is 01223 360966.'},\n", + " {'act': 'bye', 'text': 'You are welcome!'}]\n" + ] + } + ], + "source": [ + "from pprint import pprint\n", + "\n", + "for dialog in iterator.gen_batches(batch_size=1, data_type='train'):\n", + " turns_x, turns_y = dialog\n", + " \n", + " print(\"User utterances:\\n----------------\\n\")\n", + " pprint(turns_x[0], indent=4)\n", + " print(\"\\nSystem responses:\\n-----------------\\n\")\n", + " pprint(turns_y[0], indent=4)\n", + " \n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "!cp my_data/simple-dstc2-trn.json my_data/simple-dstc2-trn.full.json" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train set is reduced to 50 dialogues (out of 967).\n" + ] + } + ], + "source": [ + "import json\n", + "\n", + "NUM_TRAIN = 50\n", + "\n", + "with open('my_data/simple-dstc2-trn.full.json', 'rt') as fin:\n", + " data = json.load(fin)\n", + "with open('my_data/simple-dstc2-trn.json', 'wt') as fout:\n", + " json.dump(data[:NUM_TRAIN], fout, indent=2)\n", + "print(f\"Train set is reduced to {NUM_TRAIN} dialogues (out of {len(data)}).\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Build database of items" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " \n", + "![gobot_database.png](img/gobot_database.png)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For a valid goal-oriented bot there should be a `database` of relevant items. In the case of restaurant booking it will contain all available restaurants and their info.\n", + "\n", + " >> database([{'pricerange': 'cheap', 'area': 'south'}])\n", + " \n", + " Out[1]: \n", + " [[{'name': 'the lucky star',\n", + " 'food': 'chinese',\n", + " 'pricerange': 'cheap',\n", + " 'area': 'south',\n", + " 'addr': 'cambridge leisure park clifton way cherry hinton',\n", + " 'phone': '01223 244277',\n", + " 'postcode': 'c.b 1, 7 d.y'},\n", + " {'name': 'nandos',\n", + " 'food': 'portuguese',\n", + " 'pricerange': 'cheap',\n", + " 'area': 'south',\n", + " 'addr': 'cambridge leisure park clifton way',\n", + " 'phone': '01223 327908',\n", + " 'postcode': 'c.b 1, 7 d.y'}]]\n", + " \n", + "The dialogues in the training dataset should contain a `\"db_result\"` dictionary key. It is required for turns where system performs a special type of external action: an api call to the database of items. `\"db_result\"` should contain the result of the api call:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " {\r\n", + " \"speaker\": 2,\r\n", + " \"text\": \"api_call area=\\\"south\\\" food=\\\"dontcare\\\" pricerange=\\\"cheap\\\"\",\r\n", + " \"db_result\": {\r\n", + " \"food\": \"chinese\",\r\n", + " \"pricerange\": \"cheap\",\r\n", + " \"area\": \"south\",\r\n", + " \"addr\": \"cambridge leisure park clifton way cherry hinton\",\r\n", + " \"phone\": \"01223 244277\",\r\n", + " \"postcode\": \"c.b 1, 7 d.y\",\r\n", + " \"name\": \"the lucky star\"\r\n", + " },\r\n", + " \"slots\": [\r\n", + " [\r\n", + " \"area\",\r\n", + " \"south\"\r\n", + " ],\r\n", + " [\r\n", + " \"pricerange\",\r\n", + " \"cheap\"\r\n", + " ],\r\n", + " [\r\n", + " \"food\",\r\n", + " \"dontcare\"\r\n", + " ]\r\n", + " ],\r\n", + " \"act\": \"api_call\"\r\n", + " },\r\n" + ] + } + ], + "source": [ + "!head -n 78 my_data/simple-dstc2-trn.json | tail +51" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2019-09-04 14:40:49.312 WARNING in 'deeppavlov.core.models.serializable'['serializable'] at line 47: No load path is set for Sqlite3Database in 'infer' mode. Using save path instead\n", + "2019-09-04 14:40:49.313 INFO in 'deeppavlov.core.data.sqlite_database'['sqlite_database'] at line 70: Initializing empty database on /home/vimary/code-projects/Pilot/examples/my_bot/db.sqlite.\n" + ] + } + ], + "source": [ + "from deeppavlov.core.data.sqlite_database import Sqlite3Database\n", + "\n", + "database = Sqlite3Database(primary_keys=[\"name\"],\n", + " save_path=\"my_bot/db.sqlite\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set `primary_keys` to a list of slot names that have unique values for different items (common SQL term). For the case of DSTC-2, the primary slot is restaurant name.\n", + "\n", + "Let's find all `\"db_result\"` api call results and add it to our database of restaurants:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2019-09-04 14:40:50.332 INFO in 'deeppavlov.core.data.sqlite_database'['sqlite_database'] at line 145: Created table with keys {'food': 'text', 'postcode': 'text', 'pricerange': 'text', 'area': 'text', 'phone': 'text', 'name': 'text', 'addr': 'text'}.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Adding 3016 items.\n" + ] + } + ], + "source": [ + "db_results = []\n", + "\n", + "for dialog in iterator.gen_batches(batch_size=1, data_type='all'):\n", + " turns_x, turns_y = dialog\n", + " db_results.extend(x['db_result'] for x in turns_x[0] if x.get('db_result'))\n", + "\n", + "print(f\"Adding {len(db_results)} items.\")\n", + "if db_results:\n", + " database.fit(db_results)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Interacting with database" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now play with the database and make requests to it:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[[{'food': 'chinese',\n", + " 'postcode': 'c.b 1, 7 d.y',\n", + " 'pricerange': 'cheap',\n", + " 'area': 'south',\n", + " 'phone': '01223 244277',\n", + " 'name': 'the lucky star',\n", + " 'addr': 'cambridge leisure park clifton way cherry hinton'},\n", + " {'food': 'portuguese',\n", + " 'postcode': 'c.b 1, 7 d.y',\n", + " 'pricerange': 'cheap',\n", + " 'area': 'south',\n", + " 'phone': '01223 327908',\n", + " 'name': 'nandos',\n", + " 'addr': 'cambridge leisure park clifton way'}]]" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "database([{'pricerange': 'cheap', 'area': 'south'}])" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "db.sqlite\r\n" + ] + } + ], + "source": [ + "!ls my_bot" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Build Slot Filler" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " \n", + "![gobot_slotfiller.png](img/gobot_slotfiller.png)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Slot Filler is component that inputs text and outputs dictionary of slot names and their values:\n", + "\n", + " >> slot_filler(['I would like some chineese food'])\n", + " \n", + " Out[1]: [{'food': 'chinese'}]\n", + "\n", + "To implement a slot filler you need to provide\n", + " \n", + " - **slot types**\n", + " - all possible **slot values**\n", + " - optionally, it will be good to provide examples of mentions for every value of each slot\n", + " \n", + "The data should be in `slot_vals.json` file with the following format:\n", + "\n", + " {\n", + " 'food': {\n", + " 'chinese': ['chinese', 'chineese', 'chines'],\n", + " 'french': ['french', 'freench'],\n", + " 'dontcare': ['any food', 'any type of food']\n", + " }\n", + " }\n", + " \n", + "\n", + "Let's use a simple non-trainable slot filler that relies on levenshtein distance:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2019-09-04 14:40:53.225 INFO in 'deeppavlov.core.data.utils'['utils'] at line 63: Downloading from http://files.deeppavlov.ai/deeppavlov_data/dstc_slot_vals.tar.gz to my_bot/slotfill/dstc_slot_vals.tar.gz\n", + "100%|██████████| 1.62k/1.62k [00:00<00:00, 11.1MB/s]\n", + "2019-09-04 14:40:53.227 INFO in 'deeppavlov.core.data.utils'['utils'] at line 201: Extracting my_bot/slotfill/dstc_slot_vals.tar.gz archive into my_bot/slotfill\n" + ] + } + ], + "source": [ + "from deeppavlov.download import download_decompress\n", + "\n", + "download_decompress(url='http://files.deeppavlov.ai/deeppavlov_data/dstc_slot_vals.tar.gz',\n", + " download_path='my_bot/slotfill')" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dstc_slot_vals.json\r\n" + ] + } + ], + "source": [ + "!ls my_bot/slotfill" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\r\n", + " \"food\": {\r\n", + " \"caribbean\": [\r\n", + " \"carraibean\",\r\n", + " \"carribean\",\r\n", + " \"caribbean\"\r\n", + " ],\r\n", + " \"kosher\": [\r\n", + " \"kosher\"\r\n", + " ],\r\n" + ] + } + ], + "source": [ + "!head -n 10 my_bot/slotfill/dstc_slot_vals.json" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Metric scores on valid&test" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's check performance of our slot filler on DSTC-2 dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "from deeppavlov import configs\n", + "from deeppavlov.core.common.file import read_json\n", + "\n", + "slotfill_config = read_json(configs.ner.slotfill_simple_dstc2_raw)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We take [original DSTC2 slot-filling config](https://github.com/deepmipt/DeepPavlov/blob/master/deeppavlov/configs/ner/slotfill_dstc2_raw.json) and change variables determining data paths:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "slotfill_config['metadata']['variables']['DATA_PATH'] = 'my_data'\n", + "slotfill_config['metadata']['variables']['SLOT_VALS_PATH'] = 'my_bot/slotfill/dstc_slot_vals.json'" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2019-09-04 14:40:55.992 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 290: [loading dialogs from /home/vimary/code-projects/Pilot/examples/my_data/simple-dstc2-trn.json]\n", + "2019-09-04 14:40:55.999 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 290: [loading dialogs from /home/vimary/code-projects/Pilot/examples/my_data/simple-dstc2-val.json]\n", + "2019-09-04 14:40:56.105 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 290: [loading dialogs from /home/vimary/code-projects/Pilot/examples/my_data/simple-dstc2-tst.json]\n", + "2019-09-04 14:40:56.150 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 282: There are 479 samples in train split.\n", + "2019-09-04 14:40:56.151 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 283: There are 6231 samples in valid split.\n", + "2019-09-04 14:40:56.151 INFO in 'deeppavlov.dataset_readers.dstc2_reader'['dstc2_reader'] at line 284: There are 6345 samples in test split.\n", + "[nltk_data] Downloading package punkt to /home/vimary/nltk_data...\n", + "[nltk_data] Package punkt is already up-to-date!\n", + "[nltk_data] Downloading package stopwords to /home/vimary/nltk_data...\n", + "[nltk_data] Package stopwords is already up-to-date!\n", + "[nltk_data] Downloading package perluniprops to\n", + "[nltk_data] /home/vimary/nltk_data...\n", + "[nltk_data] Package perluniprops is already up-to-date!\n", + "[nltk_data] Downloading package nonbreaking_prefixes to\n", + "[nltk_data] /home/vimary/nltk_data...\n", + "[nltk_data] Package nonbreaking_prefixes is already up-to-date!\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\"valid\": {\"eval_examples_count\": 1253, \"metrics\": {\"slots_accuracy\": 0.933}, \"time_spent\": \"0:00:34\"}}\n", + "{\"test\": {\"eval_examples_count\": 1190, \"metrics\": {\"slots_accuracy\": 0.9487}, \"time_spent\": \"0:00:31\"}}\n" + ] + } + ], + "source": [ + "from deeppavlov import evaluate_model\n", + "\n", + "slotfill = evaluate_model(slotfill_config);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We've got slot accuracy of **93% on valid** set and **94% on test** set." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Interacting with slot filler" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "from deeppavlov import build_model\n", + "\n", + "slotfill = build_model(slotfill_config)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'food': 'chinese', 'pricerange': 'cheap'}]" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "slotfill(['i want cheap chinee food'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "##### Dumping slot filler's config" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Saving slotfill config file to disk (we will require it's path later):" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "\n", + "json.dump(slotfill_config, open('my_bot/slotfill_config.json', 'wt'))" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "db.sqlite slotfill slotfill_config.json\r\n" + ] + } + ], + "source": [ + "!ls my_bot" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Train bot" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's assemble all modules together and train the final module: dialogue policy network.\n", + "\n", + " \n", + "![gobot_policy.png](img/gobot_policy.png)\n", + " \n", + "\n", + "Policy network decides which action the system should take on each turn of a dialogue: should it say goodbye, request user's location or make api call to a database.\n", + "\n", + "The policy network is a recurrent neural network (recurrent over utterances represented as bags of words) and a dense layer with softmax function on top. The network classifies user utterance into one of predefined system actions.\n", + "\n", + " \n", + "![gobot_templates.png](img/gobot_templates.png)\n", + " \n", + "\n", + "All actions available for the system should be listed in a `simple-dstc2-templates.txt` file. Each action should be associated with a string of the corresponding system response.\n", + "\n", + "Templates should be in the format `TAB