Skip to content

Commit e597c3f

Browse files
committed
Adding support for state-of-the-art Yolov4 with OPENCV 4.4-pre .
multiple improvment for error handeling and logging
1 parent c97d84c commit e597c3f

8 files changed

Lines changed: 124 additions & 20 deletions

File tree

.DS_Store

6 KB
Binary file not shown.

.vscode/launch.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Python: Remote Attach",
9+
"type": "python",
10+
"request": "attach",
11+
"port": 4000,
12+
"host": "0.0.0.0",
13+
"pathMappings": [
14+
{
15+
"localRoot": "${workspaceFolder}",
16+
"remoteRoot": "${workspaceFolder}`"
17+
}
18+
]
19+
}
20+
]
21+
}

README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# YOLO v3 CPU Inference API for Windows and Linux
1+
# YOLO v4-v3 CPU Inference API for Windows and Linux
22

3-
This is a repository for an object detection inference API using the Yolov3 Opencv.
3+
This is a repository for an object detection inference API using the Yolov4 and Yolo v3 Opencv.
44

55
The inference REST API works on CPU and doesn't require any GPU usage. It's supported on both Windows and Linux Operating systems.
66

7-
Models trained using our training Yolov3 repository can be deployed in this API. Several object detection models can be loaded and used at the same time.
7+
Models trained using our training Yolov4 or Yolov3 repository can be deployed in this API. Several object detection models can be loaded and used at the same time.
88

99
![predict image](./docs/4.gif)
1010

@@ -44,13 +44,12 @@ To [install Docker on Windows](https://docs.docker.com/docker-for-windows/instal
4444
In order to build the project run the following command from the project's root directory:
4545

4646
```sh
47-
sudo docker build -t yolov3_inference_api_cpu -f ./docker/dockerfile .
47+
sudo docker build -t yolov4_inference_api_cpu -f ./docker/dockerfile .
4848
```
4949
### Behind a proxy
5050

5151
```sh
52-
sudo docker build --build-arg http_proxy='' --build-arg https_proxy='' -t yolov3_inference_api_cpu -f ./docker/dockerfile .
53-
52+
sudo docker build --build-arg http_proxy='' --build-arg https_proxy='' -t yolov4_inference_api_cpu -f ./docker/dockerfile .
5453
```
5554

5655
## Run The Docker Container
@@ -60,12 +59,12 @@ To run the API, go the to the API's directory and run the following:
6059
#### Using Linux based docker:
6160

6261
```sh
63-
sudo docker run -itv $(pwd)/models:/models -p <docker_host_port>:7770 yolov3_inference_api_cpu
62+
sudo docker run -itv $(pwd)/models:/models -p <docker_host_port>:7770 yolov4_inference_api_cpu
6463
```
6564
#### Using Windows based docker:
6665

6766
```sh
68-
docker run -itv ${PWD}/models:/models -p <docker_host_port>:7770 yolov3_inference_api_cpu
67+
docker run -itv ${PWD}/models:/models -p <docker_host_port>:7770 yolov4_inference_api_cpu
6968
```
7069

7170
The <docker_host_port> can be any unique port of your choice.
@@ -150,7 +149,7 @@ Inside each subfolder there should be a:
150149

151150
```json
152151
{
153-
"inference_engine_name": "yolov3_opencv_cpu_detection",
152+
"inference_engine_name": "yolov4_opencv_cpu_detection",
154153
"confidence": 60,
155154
"nms_threshold": 0.6,
156155
"image": {
@@ -171,6 +170,9 @@ Inside each subfolder there should be a:
171170
}
172171
```
173172
P.S
173+
174+
- You can choose **"inference_engine_name"**: between **yolov4_opencv_cpu_detection** and **yolov3_opencv_cpu_detection** depending on the model you have.
175+
174176
- You can change confidence and nms_threshold values while running the API
175177
- The API will return bounding boxes with a confidence higher than the "confidence" value. A high "confidence" can show you only accurate predictions
176178

docker/dockerfile

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,50 @@ FROM python:3.6
33
LABEL maintainer="antoine.charbel@inmind.ai"
44

55
COPY docker/requirements.txt .
6+
ENV HOME /root
67

78
COPY src/main /main
89

10+
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y --no-install-recommends install \
11+
locales \
12+
wget \
13+
software-properties-common \
14+
ca-certificates \
15+
build-essential \
16+
cmake \
17+
git \
18+
libopencv-dev \
19+
python3-dev \
20+
python3-pip \
21+
libgtk2.0-dev\
22+
pkg-config\
23+
&& apt-get -y autoremove \
24+
&& apt-get clean \
25+
&& pip3 install setuptools wheel \
26+
&& rm -rf /var/lib/apt/lists/{apt,dpkg,cache,log} /tmp/* /var/tmp/*
27+
928
RUN pip install -r requirements.txt
1029

11-
WORKDIR /main
1230

31+
WORKDIR ${HOME}
32+
RUN git clone http://github.com/opencv/opencv.git && cd opencv \
33+
&& git checkout master \
34+
&& mkdir build && cd build \
35+
&& cmake -D CMAKE_BUILD_TYPE=RELEASE \
36+
-D CMAKE_INSTALL_PREFIX=/usr/local \
37+
-D WITH_CUDA=OFF \
38+
-D WITH_OPENCL=OFF \
39+
-D ENABLE_FAST_MATH=1 \
40+
-D CUDA_FAST_MATH=1 \
41+
-D WITH_CUBLAS=1 \
42+
-D BUILD_DOCS=OFF \
43+
-D BUILD_PERF_TESTS=OFF \
44+
-D BUILD_TESTS=OFF \
45+
.. \
46+
&& make -j `nproc` \
47+
&& make install \
48+
&& cd ${HOME} && rm -rf ./opencv/
49+
50+
51+
WORKDIR /main
1352
CMD ["uvicorn", "start:app", "--host", "0.0.0.0", "--port", "7770"]

src/.DS_Store

6 KB
Binary file not shown.

src/main/deep_learning_service.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ def get_labels(self, model_name):
130130
:param model_name: Model name
131131
:return: List of model labels
132132
"""
133+
if model_name not in self.models_hash_dict and model_name not in self.models_hash_dict.values():
134+
raise ModelNotFound
133135
if not self.model_loaded(model_name):
134136
self.load_model(model_name)
135137
return self.models_dict[model_name].labels
@@ -140,6 +142,8 @@ def get_labels_custom(self, model_name):
140142
:param model_name: Model name
141143
:return: A list of mode's labels with their hashed values
142144
"""
145+
if model_name not in self.models_hash_dict and model_name not in self.models_hash_dict.values():
146+
raise ModelNotFound
143147
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,
144148
flags=0):
145149
for key, value in self.models_hash_dict.items():
@@ -162,6 +166,8 @@ def get_config(self, model_name):
162166
:param model_name: Model name
163167
:return: List of model's configuration
164168
"""
169+
if model_name not in self.models_hash_dict and model_name not in self.models_hash_dict.values():
170+
raise ModelNotFound
165171
if not self.model_loaded(model_name):
166172
self.load_model(model_name)
167173
return self.models_dict[model_name].configuration

src/main/inference/inference_engines_factory.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ def get_engine(path_to_model):
2626
try:
2727
# import one of the available inference engine class (in this project there's only one), and return a
2828
# model instance
29-
return getattr(__import__(inference_engine_name), 'InferenceEngine')(path_to_model)
29+
if inference_engine_name=='yolov3_opencv_cpu_detection' or inference_engine_name=='yolov4_opencv_cpu_detection':
30+
return getattr(__import__("yolov3_opencv_cpu_detection"), 'InferenceEngine')(path_to_model)
3031
except ApplicationError as e:
3132
raise e
3233
except Exception as e:

src/main/start.py

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,13 @@ def load_custom():
4040
:return: All the available models with their respective hashed values
4141
"""
4242
try:
43+
error_logging.info('request successful;')
4344
return dl_service.load_all_models()
4445
except ApplicationError as e:
46+
error_logging.warning(str(e))
4547
return ApiResponse(success=False, error=e)
46-
except Exception:
48+
except Exception as e:
49+
error_logging.error(str(e))
4750
return ApiResponse(success=False, error='unexpected server error')
4851

4952

@@ -76,7 +79,15 @@ def get_labels_custom(model: str = Form(...)):
7679
:param model: Model name or model hash
7780
:return: A list of the model's labels with their hashed values
7881
"""
79-
return dl_service.get_labels_custom(model)
82+
try :
83+
error_logging.info('request successful;')
84+
return dl_service.get_labels_custom(model)
85+
except ModelNotFound as e :
86+
error_logging.warning(model+' '+str(e))
87+
return ApiResponse(success=False, error=e)
88+
except Exception as e:
89+
error_logging.error(model + ' ' + str(e))
90+
return ApiResponse(success=False, error='unexpected server error')
8091

8192

8293
@app.get('/models/{model_name}/load')
@@ -89,9 +100,14 @@ async def load(model_name: str, force: bool = False):
89100
"""
90101
try:
91102
dl_service.load_model(model_name, force)
103+
error_logging.info('request successful;')
92104
return ApiResponse(success=True)
93105
except ApplicationError as e:
106+
error_logging.warning(str(e))
94107
return ApiResponse(success=False, error=e)
108+
except Exception as e:
109+
error_logging.error(str(e))
110+
return ApiResponse(success=False, error='unexpected server error')
95111

96112

97113
@app.get('/models')
@@ -101,7 +117,12 @@ async def list_models(user_agent: str = Header(None)):
101117
:param user_agent:
102118
:return: APIResponse
103119
"""
104-
return ApiResponse(data={'models': dl_service.list_models()})
120+
try :
121+
error_logging.info('request successful;')
122+
return ApiResponse(data={'models': dl_service.list_models()})
123+
except Exception as e:
124+
error_logging.error(str(e))
125+
return ApiResponse(success=False, error='unexpected server error')
105126

106127

107128
@app.post('/models/{model_name}/predict')
@@ -140,7 +161,6 @@ async def run_model_batch(model_name: str, input_data: List[UploadFile] = File(.
140161
error_logging.warning(model_name + ';' + str(e))
141162
return ApiResponse(success=False, error=e)
142163
except Exception as e:
143-
print(e)
144164
error_logging.error(model_name + ' ' + str(e))
145165
return ApiResponse(success=False, error='unexpected server error')
146166

@@ -172,9 +192,16 @@ async def list_model_labels(model_name: str):
172192
:param model_name: Model name
173193
:return: List of model's labels
174194
"""
175-
labels = dl_service.get_labels(model_name)
176-
return ApiResponse(data=labels)
177-
195+
try :
196+
labels = dl_service.get_labels(model_name)
197+
error_logging.info('request successful;' + str(labels))
198+
return ApiResponse(data=labels)
199+
except ModelNotFound as e :
200+
error_logging.warning(model_name + ';' + str(e))
201+
return ApiResponse (success=False, error=e)
202+
except Exception as e:
203+
error_logging.error(model_name + ' ' + str(e))
204+
return ApiResponse(success=False, error='unexpected server error')
178205

179206
@app.get('/models/{model_name}/config')
180207
async def list_model_config(model_name: str):
@@ -183,5 +210,13 @@ async def list_model_config(model_name: str):
183210
:param model_name: Model name
184211
:return: List of model's configuration
185212
"""
186-
config = dl_service.get_config(model_name)
187-
return ApiResponse(data=config)
213+
try:
214+
config = dl_service.get_config(model_name)
215+
error_logging.info('request successful;' + str(config))
216+
return ApiResponse(data=config)
217+
except ModelNotFound as e :
218+
error_logging.warning(model_name + ';' + str(e))
219+
return ApiResponse(success=False, error=e)
220+
except Exception as e:
221+
error_logging.error(model_name + ' ' + str(e))
222+
return ApiResponse(success=False, error='unexpected server error')

0 commit comments

Comments
 (0)