Skip to content

Commit 797588f

Browse files
sovrasovAlexanderDokuchaev
authored andcommitted
Add mmdetection and related tools (openvinotoolkit#96)
* Add mmdetection submodule * Add ssd-related tools to object detection folder
1 parent 9af5597 commit 797588f

9 files changed

+440
-0
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@
55
[submodule "models"]
66
path = external/models
77
url = https://github.com/tensorflow/models.git
8+
[submodule "external/mmdetection"]
9+
path = external/mmdetection
10+
url = https://github.com/sovrasov/mmdetection/

external/mmdetection

Submodule mmdetection added at 804451b
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env bash
2+
3+
work_dir=$(realpath "$(dirname $0)")
4+
5+
cd ${work_dir}
6+
if [[ -e venv ]]; then
7+
echo "Please remove a previously virtual environment folder '${work_dir}/venv'."
8+
exit
9+
fi
10+
11+
# Create virtual environment
12+
virtualenv venv -p python3 --prompt="(pytorch-toolbox) "
13+
echo "export PYTHONPATH=\$PYTHONPATH:${work_dir}" >> venv/bin/activate
14+
. venv/bin/activate
15+
pip install -r ${work_dir}/requirements.txt
16+
17+
# Install OpenVino Model Optimizer (optional)
18+
mo_requirements_file="${INTEL_CVSDK_DIR}/deployment_tools/model_optimizer/requirements_tf.txt"
19+
if [[ -e "${mo_requirements_file}" ]]; then
20+
pip install -qr ${mo_requirements_file}
21+
else
22+
echo "Model optimizer requirements were not installed. Please install the OpenVino toolkit to use one."
23+
fi
24+
25+
26+
echo
27+
echo "===================================================="
28+
echo "To start to work, you need to activate a virtualenv:"
29+
echo "$ . venv/bin/activate"
30+
echo "===================================================="
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
cd ../../external/mmdetection/
2+
bash compile.sh
3+
python setup.py develop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
torch==1.1
2+
cython
3+
matplotlib
4+
ptflops
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import argparse
2+
3+
import torch
4+
from mmdet.apis import init_detector
5+
from ptflops import get_model_complexity_info
6+
7+
8+
def parse_args():
9+
parser = argparse.ArgumentParser(description='MMDet count flops')
10+
parser.add_argument('config', help='test config file path')
11+
args = parser.parse_args()
12+
return args
13+
14+
15+
def inp_fun(input_res):
16+
batch = torch.FloatTensor(1, 3, *input_res).cuda()
17+
return dict(img=[batch], img_meta=[[{'img_shape': (*input_res, 3),
18+
'ori_shape': (*input_res, 3),
19+
'scale_factor': 1.0}]],
20+
rescale=True, return_loss=False)
21+
22+
23+
def main():
24+
args = parse_args()
25+
with torch.no_grad():
26+
model = init_detector(args.config)
27+
model.eval()
28+
input_res = model.cfg.data['test']['img_scale']
29+
flops, params = get_model_complexity_info(model, input_res,
30+
as_strings=True,
31+
print_per_layer_stat=True,
32+
input_constructor=inp_fun)
33+
print('Computational complexity: ' + flops)
34+
print('Number of parameters: ', params)
35+
36+
37+
if __name__ == '__main__':
38+
main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import argparse
2+
import cv2 as cv
3+
from mmdet.apis import inference_detector, init_detector
4+
5+
6+
def decode_detections(detections, conf_t=0.5):
7+
results = []
8+
for detection in detections:
9+
confidence = detection[4]
10+
11+
if confidence > conf_t:
12+
left, top, right, bottom = detection[:4]
13+
results.append(((int(left), int(top), int(right), int(bottom)),
14+
confidence))
15+
16+
return results
17+
18+
19+
def draw_detections(frame, detections, class_name):
20+
"""Draws detections and labels"""
21+
for i, rect in enumerate(detections):
22+
left, top, right, bottom = rect[0]
23+
cv.rectangle(frame, (left, top), (right, bottom),
24+
(0, 255, 0), thickness=2)
25+
label = class_name + '(' + str(round(rect[1], 2)) + ')'
26+
label_size, base_line = cv.getTextSize(label,
27+
cv.FONT_HERSHEY_SIMPLEX, 1, 1)
28+
top = max(top, label_size[1])
29+
cv.rectangle(frame, (left, top - label_size[1]),
30+
(left + label_size[0], top + base_line),
31+
(255, 255, 255), cv.FILLED)
32+
cv.putText(frame, label, (left, top),
33+
cv.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0))
34+
35+
return frame
36+
37+
38+
def main():
39+
parser = argparse.ArgumentParser(description='Face detection live \
40+
demo script')
41+
parser.add_argument('--cam_id', type=int, default=0, help='Input cam')
42+
parser.add_argument('config', help='test config file path')
43+
parser.add_argument('checkpoint', help='checkpoint file')
44+
parser.add_argument('--d_thresh', type=float, default=0.5,
45+
help='Threshold for FD')
46+
args = parser.parse_args()
47+
48+
model = init_detector(args.config, args.checkpoint)
49+
50+
cap = cv.VideoCapture(args.cam_id)
51+
cap.set(cv.CAP_PROP_FRAME_WIDTH, 1280)
52+
cap.set(cv.CAP_PROP_FRAME_HEIGHT, 720)
53+
cap.set(cv.CAP_PROP_FOURCC, cv.VideoWriter_fourcc(*'MJPG'))
54+
55+
while cv.waitKey(1) != 27:
56+
has_frame, frame = cap.read()
57+
if not has_frame:
58+
return
59+
results = inference_detector(model, frame)
60+
for i, class_result in enumerate(results):
61+
class_boxes = decode_detections(class_result, args.d_thresh)
62+
frame = draw_detections(frame, class_boxes, model.CLASSES[i])
63+
cv.imshow('Detection Demo', frame)
64+
65+
66+
if __name__ == '__main__':
67+
main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import argparse
2+
3+
import numpy as np
4+
import torch
5+
from mmcv.parallel import MMDataParallel
6+
7+
from mmdet.apis import init_detector
8+
from mmdet.models import detectors
9+
10+
from tools.ssd_export_helpers import (get_proposals, PriorBox,
11+
PriorBoxClustered, DetectionOutput)
12+
13+
14+
def onnx_export(self, img, img_meta, export_name='', **kwargs):
15+
self._export_mode = True
16+
self.img_metas = img_meta
17+
torch.onnx.export(self, img, export_name, verbose=False)
18+
19+
20+
def forward(self, img, img_meta=[None], return_loss=True, **kwargs): #passing None here is a hack to fool the jit engine
21+
if self._export_mode:
22+
return self.forward_export(img)
23+
if return_loss:
24+
return self.forward_train(img, img_meta, **kwargs)
25+
else:
26+
return self.forward_test(img, img_meta, **kwargs)
27+
28+
29+
def forward_export_detector(self, img):
30+
x = self.extract_feat(img)
31+
outs = self.bbox_head(x)
32+
bbox_result = self.bbox_head.export_forward(*outs, self.test_cfg, True,
33+
self.img_metas, x, img)
34+
return bbox_result
35+
36+
37+
def export_forward_ssd_head(self, cls_scores, bbox_preds, cfg, rescale,
38+
img_metas, feats, img_tensor):
39+
num_levels = len(cls_scores)
40+
41+
anchors = []
42+
for i in range(num_levels):
43+
if self.anchor_generators[i].manual_anchors:
44+
anchors.append(PriorBoxClustered.apply(
45+
self.anchor_generators[i], self.anchor_strides[i],
46+
feats[i], img_tensor, self.target_stds))
47+
else:
48+
anchors.append(PriorBox.apply(self.anchor_generators[i],
49+
self.anchor_strides[i],
50+
feats[i],
51+
img_tensor, self.target_stds))
52+
anchors = torch.cat(anchors, 2)
53+
cls_scores, bbox_preds = self._prepare_cls_scores_bbox_preds(
54+
cls_scores, bbox_preds)
55+
56+
return DetectionOutput.apply(cls_scores, bbox_preds, img_metas, cfg,
57+
rescale, anchors, self.cls_out_channels,
58+
self.use_sigmoid_cls, self.target_means,
59+
self.target_stds)
60+
61+
62+
def prepare_cls_scores_bbox_preds_ssd_head(self, cls_scores, bbox_preds):
63+
scores_list = []
64+
for o in cls_scores:
65+
score = o.permute(0, 2, 3, 1).contiguous().view(o.size(0), -1)
66+
scores_list.append(score)
67+
cls_scores = torch.cat(scores_list, 1)
68+
cls_scores = cls_scores.view(cls_scores.size(0), -1, self.num_classes)
69+
if self.use_sigmoid_cls:
70+
cls_scores = cls_scores.sigmoid()
71+
else:
72+
cls_scores = cls_scores.softmax(-1)
73+
cls_scores = cls_scores.view(cls_scores.size(0), -1)
74+
bbox_list = []
75+
for o in bbox_preds:
76+
boxes = o.permute(0, 2, 3, 1).contiguous().view(o.size(0), -1)
77+
bbox_list.append(boxes)
78+
bbox_preds = torch.cat(bbox_list, 1)
79+
return cls_scores, bbox_preds
80+
81+
82+
def get_bboxes_ssd_head(self, cls_scores, bbox_preds, img_metas, cfg,
83+
rescale=False):
84+
assert len(cls_scores) == len(bbox_preds)
85+
num_levels = len(cls_scores)
86+
mlvl_anchors = [
87+
self.anchor_generators[i].grid_anchors(cls_scores[i].size()[-2:],
88+
self.anchor_strides[i])
89+
for i in range(num_levels)
90+
]
91+
mlvl_anchors = torch.cat(mlvl_anchors, 0)
92+
cls_scores, bbox_preds = self._prepare_cls_scores_bbox_preds(
93+
cls_scores, bbox_preds)
94+
bboxes_list = get_proposals(img_metas, cls_scores, bbox_preds,
95+
mlvl_anchors, cfg, rescale,
96+
self.cls_out_channels,
97+
self.use_sigmoid_cls, self.target_means,
98+
self.target_stds)
99+
100+
101+
def parse_args():
102+
parser = argparse.ArgumentParser(description='MMDet onnx exporter for \
103+
SSD detector')
104+
parser.add_argument('config', help='config file path')
105+
parser.add_argument('checkpoint', help='checkpoint file')
106+
parser.add_argument('output', help='onnx file')
107+
args = parser.parse_args()
108+
return args
109+
110+
111+
def main():
112+
args = parse_args()
113+
114+
model = init_detector(args.config, args.checkpoint)
115+
cfg = model.cfg
116+
assert getattr(detectors, cfg.model['type']) is \
117+
detectors.SingleStageDetector
118+
model = MMDataParallel(model, device_ids=[0])
119+
120+
batch = torch.FloatTensor(1, 3, cfg.input_size, cfg.input_size).cuda()
121+
input_shape = (cfg.input_size, cfg.input_size, 3)
122+
scale = np.array([1, 1, 1, 1], dtype=np.float32)
123+
data = dict(img=batch, img_meta=[{'img_shape': input_shape,
124+
'scale_factor': scale}])
125+
model.eval()
126+
model.module.onnx_export = onnx_export.__get__(model.module)
127+
model.module.forward = forward.__get__(model.module)
128+
model.module.forward_export = forward_export_detector.__get__(model.module)
129+
model.module.bbox_head.export_forward = export_forward_ssd_head.__get__(model.module.bbox_head)
130+
model.module.bbox_head._prepare_cls_scores_bbox_preds = prepare_cls_scores_bbox_preds_ssd_head.__get__(model.module.bbox_head)
131+
model.module.bbox_head.get_bboxes = get_bboxes_ssd_head.__get__(model.module.bbox_head)
132+
model.module.onnx_export(export_name=args.output, **data)
133+
134+
if __name__ == '__main__':
135+
main()

0 commit comments

Comments
 (0)