Skip to content

Commit 6bcd32b

Browse files
Boosted inference speed
1 parent 38bb99d commit 6bcd32b

10 files changed

Lines changed: 336 additions & 385 deletions

src/main/deep_learning_service.py

100644100755
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
2+
import re
23
import json
34
import uuid
4-
import re
55
from inference.inference_engines_factory import InferenceEngineFactory
66
from inference.exceptions import ModelNotFound, InvalidModelConfiguration, ModelNotLoaded, InferenceEngineNotFound, \
77
InvalidInputData, ApplicationError
@@ -75,14 +75,14 @@ def load_models(self, model_names):
7575
for model in model_names:
7676
self.load_model(model)
7777

78-
async def run_model(self, model_name, input_data, draw_boxes, predict_batch):
78+
async def run_model(self, model_name, input_data, draw, predict_batch):
7979
"""
8080
Loads the model in case it was never loaded and calls the inference engine class to get a prediction.
8181
:param model_name: Model name
8282
:param input_data: Batch of images or a single image
83-
:param draw_boxes: Boolean to specify if we need to draw the response on the input image
83+
:param draw: Boolean to specify if we need to draw the response on the input image
8484
:param predict_batch: Boolean to specify if there is a batch of images in a request or not
85-
:return: Model response in case draw_boxes was set to False, else an actual image
85+
:return: Model response in case draw was set to False, else an actual image
8686
"""
8787
if re.match(r'[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}', model_name,
8888
flags=0):
@@ -92,18 +92,18 @@ async def run_model(self, model_name, input_data, draw_boxes, predict_batch):
9292
if self.model_loaded(model_name):
9393
try:
9494
if predict_batch:
95-
return await self.models_dict[model_name].run_batch(input_data, draw_boxes, predict_batch)
95+
return await self.models_dict[model_name].run_batch(input_data, draw, predict_batch)
9696
else:
97-
if not draw_boxes:
98-
return await self.models_dict[model_name].run(input_data, draw_boxes, predict_batch)
97+
if not draw:
98+
return await self.models_dict[model_name].infer(input_data, draw, predict_batch)
9999
else:
100-
await self.models_dict[model_name].run(input_data, draw_boxes, predict_batch)
100+
await self.models_dict[model_name].infer(input_data, draw, predict_batch)
101101
except ApplicationError as e:
102102
raise e
103103
else:
104104
try:
105105
self.load_model(model_name)
106-
return await self.run_model(model_name, input_data, draw_boxes, predict_batch)
106+
return await self.run_model(model_name, input_data, draw, predict_batch)
107107
except ApplicationError as e:
108108
raise e
109109

src/main/inference/__init__.py

100644100755
File mode changed.

src/main/inference/base_error.py

100644100755
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def __init__(self):
1212
"""
1313
self.logger = logging.getLogger('logger')
1414
date = datetime.now().strftime('%Y-%m-%d')
15-
file_path = 'logs/yolov3_inference_engine_' + date + '.log'
15+
file_path = 'logs/' + date + '.log'
1616
self.handler = logging.FileHandler(file_path)
1717
self.handler.setLevel(logging.INFO)
1818
self.handler.setFormatter(logging.Formatter("%(levelname)s;%(asctime)s;%(message)s"))

src/main/inference/base_inference_engine.py

100644100755
Lines changed: 78 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,89 +4,89 @@
44

55
class AbstractInferenceEngine(ABC):
66

7-
def __init__(self, model_path):
8-
"""
9-
Takes a model path and calls the load function.
10-
:param model_path: The model's path
11-
:return:
12-
"""
13-
self.labels = []
14-
self.configuration = {}
15-
self.model_path = model_path
16-
try:
17-
self.validate_configuration()
18-
except ApplicationError as e:
19-
raise e
20-
try:
21-
self.load()
22-
except ApplicationError as e:
23-
raise e
24-
except Exception as e:
25-
raise ModelNotLoaded()
7+
def __init__(self, model_path):
8+
"""
9+
Takes a model path and calls the load function.
10+
:param model_path: The model's path
11+
:return:
12+
"""
13+
self.labels = []
14+
self.configuration = {}
15+
self.model_path = model_path
16+
try:
17+
self.validate_configuration()
18+
except ApplicationError as e:
19+
raise e
20+
try:
21+
self.load()
22+
except ApplicationError as e:
23+
raise e
24+
except Exception as e:
25+
raise ModelNotLoaded()
2626

27-
@abstractmethod
28-
def load(self):
29-
"""
30-
Loads the model based on the underlying implementation.
31-
"""
32-
pass
27+
@abstractmethod
28+
def load(self):
29+
"""
30+
Loads the model based on the underlying implementation.
31+
"""
32+
pass
3333

34-
@abstractmethod
35-
def free(self):
36-
"""
37-
Performs any manual memory implementation required to when unloading a model.
38-
Will be called when the class's destructor is called.
39-
"""
40-
pass
34+
@abstractmethod
35+
def free(self):
36+
"""
37+
Performs any manual memory implementation required to when unloading a model.
38+
Will be called when the class's destructor is called.
39+
"""
40+
pass
4141

42-
@abstractmethod
43-
async def run(self, input_data, draw_boxes, predict_batch):
44-
"""
45-
Performs the required inference based on the underlying implementation of this class.
46-
Could be used to return classification predictions, object detection coordinates...
47-
:param predict_batch: Boolean
48-
:param input_data: A single image
49-
:param draw_boxes: Used to draw bounding boxes on image instead of returning them
50-
:return: A bounding-box
51-
"""
52-
pass
42+
@abstractmethod
43+
async def infer(self, input_data, draw, predict_batch):
44+
"""
45+
Performs the required inference based on the underlying implementation of this class.
46+
Could be used to return classification predictions, object detection coordinates...
47+
:param predict_batch: Boolean
48+
:param input_data: A single image
49+
:param draw: Used to draw bounding boxes on image instead of returning them
50+
:return: A bounding-box
51+
"""
52+
pass
5353

54-
@abstractmethod
55-
async def run_batch(self, input_data, draw_boxes, predict_batch):
56-
"""
57-
Iterates over images and returns a prediction for each one.
58-
:param predict_batch: Boolean
59-
:param input_data: List of images
60-
:param draw_boxes: Used to draw bounding boxes on image instead of returning them
61-
:return: List of bounding-boxes
62-
"""
63-
pass
54+
@abstractmethod
55+
async def run_batch(self, input_data, draw, predict_batch):
56+
"""
57+
Iterates over images and returns a prediction for each one.
58+
:param predict_batch: Boolean
59+
:param input_data: List of images
60+
:param draw: Used to draw bounding boxes on image instead of returning them
61+
:return: List of bounding-boxes
62+
"""
63+
pass
6464

65-
@abstractmethod
66-
def validate_configuration(self):
67-
"""
68-
Validates that the model and its files are valid based on the underlying implementation's requirements.
69-
Can check for configuration values, folder structure...
70-
"""
71-
pass
65+
@abstractmethod
66+
def validate_configuration(self):
67+
"""
68+
Validates that the model and its files are valid based on the underlying implementation's requirements.
69+
Can check for configuration values, folder structure...
70+
"""
71+
pass
7272

73-
@abstractmethod
74-
def set_configuration(self, data):
75-
"""
76-
Takes the configuration from the config.json file
77-
:param data: Json data
78-
:return:
79-
"""
80-
pass
73+
@abstractmethod
74+
def set_model_configuration(self, data):
75+
"""
76+
Takes the configuration from the config.json file
77+
:param data: Json data
78+
:return:
79+
"""
80+
pass
8181

82-
@abstractmethod
83-
def validate_json_configuration(self, data):
84-
"""
85-
Validates the configuration of the config.json file.
86-
:param data: Json data
87-
:return:
88-
"""
89-
pass
82+
@abstractmethod
83+
def validate_json_configuration(self, data):
84+
"""
85+
Validates the configuration of the config.json file.
86+
:param data: Json data
87+
:return:
88+
"""
89+
pass
9090

91-
def __del__(self):
92-
self.free()
91+
def __del__(self):
92+
self.free()

src/main/inference/errors.py

100644100755
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import os
22
import logging
3-
from datetime import datetime, date
3+
from datetime import datetime
44
from inference.base_error import AbstractError
55

66

@@ -31,15 +31,15 @@ def check_date(self):
3131
:return:
3232
"""
3333
self.date = datetime.now().strftime('%Y-%m-%d')
34-
file_path = 'yolov3_inference_engine_' + self.date + '.log'
34+
file_path = self.date + '.log'
3535
if file_path not in os.listdir('logs'):
3636
self.logger.removeHandler(self.handler)
3737
self.handler = logging.FileHandler('logs/' + file_path)
3838
self.handler.setLevel(logging.INFO)
3939
self.handler.setFormatter(logging.Formatter("%(levelname)s;%(asctime)s;%(message)s"))
4040
self.logger.addHandler(self.handler)
4141
oldest_log_file = os.listdir('logs')[0]
42-
oldest_date = oldest_log_file.split("_")[3].split('.')[0]
42+
oldest_date = oldest_log_file.split('.')[0]
4343
a = datetime.strptime(datetime.now().strftime('%Y-%m-%d'), '%Y-%m-%d')
4444
b = datetime.strptime(oldest_date, '%Y-%m-%d')
4545
delta = a - b

src/main/inference/exceptions.py

100644100755
Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,55 +2,50 @@
22

33

44
class ApplicationError(Exception):
5-
"""Base class for other exceptions"""
5+
"""Base class for other exceptions"""
66

7-
def __init__(self, default_message, additional_message=''):
8-
self.default_message = default_message
9-
self.additional_message = additional_message
7+
def __init__(self, default_message, additional_message=''):
8+
self.default_message = default_message
9+
self.additional_message = additional_message
1010

11-
def __str__(self):
12-
return self.get_message()
11+
def __str__(self):
12+
return self.get_message()
1313

14-
def get_message(self):
15-
return self.default_message if self.additional_message == '' else "{}: {}".format(self.default_message,
16-
self.additional_message)
14+
def get_message(self):
15+
return self.default_message if self.additional_message == '' else "{}: {}".format(self.default_message,
16+
self.additional_message)
1717

1818

1919
class InvalidModelConfiguration(ApplicationError):
20-
"""Raised when the model's configuration is corrupted"""
20+
"""Raised when the model's configuration is corrupted"""
2121

22-
def __init__(self, additional_message=''):
23-
# super('Invalid model configuration', additional_message)
24-
super().__init__('Invalid model configuration', additional_message)
22+
def __init__(self, additional_message=''):
23+
super().__init__('Invalid model configuration', additional_message)
2524

2625

2726
class ModelNotFound(ApplicationError):
28-
"""Raised when the model is not found"""
27+
"""Raised when the model is not found"""
2928

30-
def __init__(self, additional_message=''):
31-
# super('Model not found', additional_message)
32-
super().__init__('Model not found', additional_message)
29+
def __init__(self, additional_message=''):
30+
super().__init__('Model not found', additional_message)
3331

3432

3533
class ModelNotLoaded(ApplicationError):
36-
"""Raised when the model is not loaded"""
34+
"""Raised when the model is not loaded"""
3735

38-
def __init__(self, additional_message=''):
39-
# super('Error loading model', additional_message)
40-
super().__init__('Error loading model', additional_message)
36+
def __init__(self, additional_message=''):
37+
super().__init__('Error loading model', additional_message)
4138

4239

4340
class InvalidInputData(ApplicationError):
44-
"""Raised when the input data is corrupted"""
41+
"""Raised when the input data is corrupted"""
4542

46-
def __init__(self, additional_message=''):
47-
# super('Invalid input data', additional_message)
48-
super().__init__('Invalid input data', additional_message)
43+
def __init__(self, additional_message=''):
44+
super().__init__('Invalid input data', additional_message)
4945

5046

5147
class InferenceEngineNotFound(ApplicationError):
52-
"""Raised when the Inference Engine is not found"""
48+
"""Raised when the Inference Engine is not found"""
5349

54-
def __init__(self, additional_message=''):
55-
# super('Inference engine not found', additional_message)
56-
super().__init__('Inference engine not found', additional_message)
50+
def __init__(self, additional_message=''):
51+
super().__init__('Inference engine not found', additional_message)

src/main/inference/inference_engines_factory.py

100644100755
Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,33 @@
11
import os
22
import json
3-
from inference.exceptions import ModelNotFound, ApplicationError, InvalidModelConfiguration, InferenceEngineNotFound, ModelNotLoaded
3+
from inference.exceptions import ModelNotFound, ApplicationError, InvalidModelConfiguration, InferenceEngineNotFound, \
4+
ModelNotLoaded
45

56

67
class InferenceEngineFactory:
78

8-
@staticmethod
9-
def get_engine(path_to_model):
10-
"""
11-
Reads the model's inference engine from the model's configuration and calls the right inference engine class.
12-
:param path_to_model: Model's path
13-
:return: The model's instance
14-
"""
15-
if not os.path.exists(path_to_model):
16-
raise ModelNotFound()
17-
try:
18-
configuration = json.loads(open(os.path.join(path_to_model, 'config.json')).read())
19-
except Exception:
20-
raise InvalidModelConfiguration('config.json not found or corrupted')
21-
try:
22-
inference_engine_name = configuration['inference_engine_name']
23-
except Exception:
24-
raise InvalidModelConfiguration('missing inference engine name in config.json')
25-
try:
26-
# import one of the available inference engine class (in this project there's only one), and return a
27-
# model instance
28-
return getattr(__import__(inference_engine_name), 'InferenceEngine')(path_to_model)
29-
except ApplicationError as e:
30-
raise e
31-
except Exception as e:
32-
raise InferenceEngineNotFound(inference_engine_name)
9+
@staticmethod
10+
def get_engine(path_to_model):
11+
"""
12+
Reads the model's inference engine from the model's configuration and calls the right inference engine class.
13+
:param path_to_model: Model's path
14+
:return: The model's instance
15+
"""
16+
if not os.path.exists(path_to_model):
17+
raise ModelNotFound()
18+
try:
19+
configuration = json.loads(open(os.path.join(path_to_model, 'config.json')).read())
20+
except Exception:
21+
raise InvalidModelConfiguration('config.json not found or corrupted')
22+
try:
23+
inference_engine_name = configuration['inference_engine_name']
24+
except Exception:
25+
raise InvalidModelConfiguration('missing inference engine name in config.json')
26+
try:
27+
# import one of the available inference engine class (in this project there's only one), and return a
28+
# model instance
29+
return getattr(__import__(inference_engine_name), 'InferenceEngine')(path_to_model)
30+
except ApplicationError as e:
31+
raise e
32+
except Exception as e:
33+
raise InferenceEngineNotFound(inference_engine_name)

0 commit comments

Comments
 (0)