Skip to content

Commit 62490e9

Browse files
Merge pull request #2 from BMW-InnovationLab/dev
Dev
2 parents c3e19df + 6bcd32b commit 62490e9

11 files changed

Lines changed: 345 additions & 402 deletions

README.md

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ sudo docker build --build-arg http_proxy='' --build-arg https_proxy='' -t yolov3
5555

5656
## Run The Docker Container
5757

58-
To run the API, go to the project's root directory and run the following:
58+
To run the API, go the to the API's directory and run the following:
5959

6060
#### Using Linux based docker:
6161

@@ -79,7 +79,7 @@ To see all available endpoints, open your favorite browser and navigate to:
7979
```
8080
http://<machine_IP>:<docker_host_port>/docs
8181
```
82-
The 'predict_batch' endpoint is not shown on swagger.
82+
The 'predict_batch' endpoint is not shown on swagger. The list of files input is not yet supported.
8383

8484
**P.S: If you are using custom endpoints like /load, /detect, and /get_labels, you should always use the /load endpoint first and then use /detect or /get_labels**
8585

@@ -133,24 +133,26 @@ Returns the specified model's configuration
133133

134134
Performs inference on specified model and a list of images, and returns bounding boxes
135135

136+
**P.S: Custom endpoints like /load, /detect, and /get_labels should be used in a chronological order. First you have to call /load, and then call /detect or /get_labels**
137+
136138
## Model structure
137139

138140
The folder "models" contains subfolders of all the models to be loaded.
139141
Inside each subfolder there should be a:
140142

141-
- Cfg file (ends with .cfg): contains the configuration of the model
143+
- Cfg file (yolo-obj.cfg): contains the configuration of the model
142144

143-
- Weights file (ends with .weights)
145+
- Weights file (yolo-obj.weights)
144146

145-
- Names file (ends with .names) : contains the names of the classes
147+
- Names file (obj.names) : contains the names of the classes
146148

147149
- Config.json (This is a json file containing information about the model)
148150

149151
```json
150152
{
151153
"inference_engine_name": "yolov3_opencv_cpu_detection",
152-
"confidence": 60,
153-
"nms_threshold": 0.6,
154+
"confidence": <between_0_and_100>,
155+
"nms_threshold": <between_0_and_1>,
154156
"image": {
155157
"width": 416,
156158
"height": 416,
@@ -169,8 +171,6 @@ Inside each subfolder there should be a:
169171
}
170172
```
171173
P.S
172-
- confidence value should be between 0 and 100
173-
- nms_threshold value should be between 0 and 1
174174
- You can change confidence and nms_threshold values while running the API
175175
- The API will return bounding boxes with a confidence higher than the "confidence" value. A high "confidence" can show you only accurate predictions
176176

@@ -206,11 +206,3 @@ Inside each subfolder there should be a:
206206

207207
## Acknowledgment
208208

209-
[inmind.ai](https://inmind.ai)
210-
211-
[robotron.de](https://robotron.de)
212-
213-
Antoine Charbel, inmind.ai , Beirut, Lebanon
214-
215-
Daniel Anani, inmind.ai, Beirut, Lebanon
216-

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

0 commit comments

Comments
 (0)